mirror of
https://github.com/SigNoz/signoz.git
synced 2025-12-24 19:07:47 +00:00
feat: update context to recognise conjunction operator
This commit is contained in:
parent
2c193747d3
commit
711af444dc
@ -1,16 +1,149 @@
|
||||
.code-mirror-where-clause {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 16px;
|
||||
gap: 16px;
|
||||
font-family: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
|
||||
'Helvetica Neue', sans-serif;
|
||||
|
||||
.query-context {
|
||||
background-color: #f0f0f0;
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
.cm-editor {
|
||||
border: 1px solid var(--bg-vanilla-300);
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
margin-bottom: 4px;
|
||||
|
||||
&:focus-within {
|
||||
border-color: var(--bg-robin-500);
|
||||
box-shadow: 0 0 0 2px rgba(63, 94, 204, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
.cursor-position {
|
||||
background-color: #f0f0f0;
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
font-size: 12px;
|
||||
color: var(--bg-ink-200);
|
||||
padding: 6px;
|
||||
background-color: var(--bg-vanilla-200);
|
||||
border-radius: 4px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.query-validation {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin-bottom: 8px;
|
||||
|
||||
.valid,
|
||||
.invalid {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
font-weight: 500;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.valid {
|
||||
background-color: rgba(39, 174, 96, 0.1);
|
||||
color: #27ae60;
|
||||
}
|
||||
|
||||
.invalid {
|
||||
background-color: rgba(235, 87, 87, 0.1);
|
||||
color: #eb5757;
|
||||
}
|
||||
}
|
||||
|
||||
.query-context {
|
||||
padding: 12px;
|
||||
background-color: var(--bg-vanilla-200);
|
||||
border-radius: 4px;
|
||||
border-left: 3px solid var(--bg-robin-500);
|
||||
|
||||
h3 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 8px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--bg-ink-300);
|
||||
}
|
||||
|
||||
.context-details {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
font-size: 13px;
|
||||
|
||||
strong {
|
||||
color: var(--bg-ink-300);
|
||||
margin-right: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.query-examples {
|
||||
padding: 12px;
|
||||
background-color: var(--bg-vanilla-100);
|
||||
border: 1px solid var(--bg-vanilla-300);
|
||||
border-radius: 4px;
|
||||
|
||||
ul {
|
||||
margin-top: 8px;
|
||||
margin-bottom: 0;
|
||||
padding-left: 16px;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
||||
gap: 8px;
|
||||
|
||||
li {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Dark mode support */
|
||||
:global(.darkMode) {
|
||||
.code-mirror-where-clause {
|
||||
.cm-editor {
|
||||
border-color: var(--bg-slate-500);
|
||||
background-color: var(--bg-ink-400);
|
||||
}
|
||||
|
||||
.cursor-position {
|
||||
background-color: var(--bg-ink-400);
|
||||
color: var(--bg-vanilla-100);
|
||||
}
|
||||
|
||||
.query-context {
|
||||
background-color: var(--bg-ink-400);
|
||||
color: var(--bg-vanilla-100);
|
||||
|
||||
h3 {
|
||||
color: var(--bg-vanilla-100);
|
||||
}
|
||||
|
||||
.context-details {
|
||||
p {
|
||||
strong {
|
||||
color: var(--bg-vanilla-200);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.query-examples {
|
||||
background-color: var(--bg-ink-400);
|
||||
border-color: var(--bg-slate-500);
|
||||
color: var(--bg-vanilla-100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,13 +2,19 @@
|
||||
|
||||
import './CodeMirrorWhereClause.styles.scss';
|
||||
|
||||
import {
|
||||
CheckCircleFilled,
|
||||
CloseCircleFilled,
|
||||
InfoCircleOutlined,
|
||||
QuestionCircleOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import CodeMirror, { EditorView } from '@uiw/react-codemirror';
|
||||
import { Typography } from 'antd';
|
||||
import { Badge, Card, Divider, Space, Tooltip, Typography } from 'antd';
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { IQueryContext, IValidationResult } from 'types/antlrQueryTypes';
|
||||
import { getQueryContextAtCursor, validateQuery } from 'utils/antlrQueryUtils';
|
||||
|
||||
const { Text } = Typography;
|
||||
const { Text, Title } = Typography;
|
||||
|
||||
function CodeMirrorWhereClause(): JSX.Element {
|
||||
const [query, setQuery] = useState<string>('');
|
||||
@ -74,82 +80,169 @@ function CodeMirrorWhereClause(): JSX.Element {
|
||||
}
|
||||
}, [query, cursorPos]);
|
||||
|
||||
useEffect(() => {
|
||||
console.log('cursorPos', cursorPos);
|
||||
}, [cursorPos]);
|
||||
|
||||
const handleChange = (value: string): void => {
|
||||
console.log('value', value);
|
||||
setQuery(value);
|
||||
handleQueryChange(value);
|
||||
};
|
||||
|
||||
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';
|
||||
} else if (queryContext.isInParenthesis) {
|
||||
color = 'grey';
|
||||
text = 'Parenthesis';
|
||||
}
|
||||
|
||||
return (
|
||||
<Badge
|
||||
color={color}
|
||||
text={text}
|
||||
style={{
|
||||
color: 'black',
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="code-mirror-where-clause">
|
||||
<CodeMirror
|
||||
value={query}
|
||||
onChange={handleChange}
|
||||
onUpdate={handleUpdate}
|
||||
placeholder="Enter your query (e.g., status = 'error' AND service = 'frontend')"
|
||||
/>
|
||||
<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}
|
||||
theme="dark"
|
||||
onChange={handleChange}
|
||||
onUpdate={handleUpdate}
|
||||
placeholder="Enter your query (e.g., status = 'error' AND service = 'frontend')"
|
||||
/>
|
||||
|
||||
<div className="cursor-position">
|
||||
Cursor at Line: {cursorPos.line}, Ch: {cursorPos.ch}
|
||||
</div>
|
||||
<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>
|
||||
|
||||
{queryContext && (
|
||||
<div className="query-context">
|
||||
<h3>Current Context</h3>
|
||||
<Card size="small" title="Current Context" className="query-context">
|
||||
<div className="context-details">
|
||||
<p>
|
||||
<strong>Token:</strong> {queryContext.currentToken}
|
||||
</p>
|
||||
<p>
|
||||
<strong>Type:</strong> {queryContext.tokenType}
|
||||
</p>
|
||||
<p>
|
||||
<strong>Context:</strong>{' '}
|
||||
{queryContext.isInValue
|
||||
? 'Value'
|
||||
: queryContext.isInKey
|
||||
? 'Key'
|
||||
: queryContext.isInOperator
|
||||
? 'Operator'
|
||||
: queryContext.isInFunction
|
||||
? 'Function'
|
||||
: 'Unknown'}
|
||||
</p>
|
||||
<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>
|
||||
</Space>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
)}
|
||||
|
||||
<div className="query-examples">
|
||||
<Text type="secondary">Examples:</Text>
|
||||
<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>
|
||||
<ul>
|
||||
<li>
|
||||
<Text code>status = 'error'</Text>
|
||||
<Text code style={{ color: 'black' }}>
|
||||
status = 'error'
|
||||
</Text>
|
||||
</li>
|
||||
<li>
|
||||
<Text code>
|
||||
<Text code style={{ color: 'black' }}>
|
||||
service = 'frontend' AND level = 'error'
|
||||
</Text>
|
||||
</li>
|
||||
<li>
|
||||
<Text code>message LIKE '%timeout%'</Text>
|
||||
<Text code style={{ color: 'black' }}>
|
||||
message LIKE '%timeout%'
|
||||
</Text>
|
||||
</li>
|
||||
<li>
|
||||
<Text code>duration {'>'} 1000</Text>
|
||||
<Text code style={{ color: 'black' }}>
|
||||
duration {'>'} 1000
|
||||
</Text>
|
||||
</li>
|
||||
<li>
|
||||
<Text code>tags IN ['prod', 'frontend']</Text>
|
||||
<Text code style={{ color: 'black' }}>
|
||||
tags IN ['prod', 'frontend']
|
||||
</Text>
|
||||
</li>
|
||||
<li>
|
||||
<Text code>
|
||||
<Text code style={{ color: 'black' }}>
|
||||
NOT (status = 'error' OR level = 'error')
|
||||
</Text>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -22,6 +22,8 @@ export interface IQueryContext {
|
||||
isInKey: boolean;
|
||||
isInOperator: boolean;
|
||||
isInFunction: boolean;
|
||||
isInConjunction?: boolean;
|
||||
isInParenthesis?: boolean;
|
||||
}
|
||||
|
||||
export interface IDetailedError {
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
/* eslint-disable sonarjs/no-collapsible-if */
|
||||
/* eslint-disable no-continue */
|
||||
/* eslint-disable sonarjs/cognitive-complexity */
|
||||
/* eslint-disable max-classes-per-file */
|
||||
import { CharStreams, CommonTokenStream } from 'antlr4';
|
||||
import FilterQueryLexer from 'parser/FilterQueryLexer';
|
||||
import FilterQueryParser from 'parser/FilterQueryParser';
|
||||
@ -273,9 +272,22 @@ export function getQueryContextAtCursor(
|
||||
isInKey: false,
|
||||
isInOperator: false,
|
||||
isInFunction: false,
|
||||
isInConjunction: false,
|
||||
isInParenthesis: false,
|
||||
};
|
||||
}
|
||||
|
||||
// Determine if the current token is a conjunction (AND or OR)
|
||||
const isInConjunction = [FilterQueryLexer.AND, FilterQueryLexer.OR].includes(
|
||||
currentToken.type,
|
||||
);
|
||||
|
||||
// Determine if the current token is a parenthesis
|
||||
const isInParenthesis = [
|
||||
FilterQueryLexer.LPAREN,
|
||||
FilterQueryLexer.RPAREN,
|
||||
].includes(currentToken.type);
|
||||
|
||||
// Determine the context based on the token type
|
||||
const isInValue = [
|
||||
FilterQueryLexer.QUOTED_TEXT,
|
||||
@ -322,6 +334,8 @@ export function getQueryContextAtCursor(
|
||||
isInKey,
|
||||
isInOperator,
|
||||
isInFunction,
|
||||
isInConjunction,
|
||||
isInParenthesis,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error in getQueryContextAtCursor:', error);
|
||||
@ -335,6 +349,8 @@ export function getQueryContextAtCursor(
|
||||
isInKey: false,
|
||||
isInOperator: false,
|
||||
isInFunction: false,
|
||||
isInConjunction: false,
|
||||
isInParenthesis: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user