feat: styling updates

This commit is contained in:
Yunus M 2025-04-28 01:30:37 +05:30 committed by ahrefabhi
parent bcb2824e07
commit bbe4dcb6b8
5 changed files with 219 additions and 181 deletions

View File

@ -18,6 +18,89 @@
border-color: var(--bg-robin-500);
background-color: var(--bg-ink-400);
}
.cm-content {
border-radius: 2px;
border: 1px solid var(--Slate-400, #1d212d);
background: var(--Ink-300, #16181d);
}
.cm-tooltip-autocomplete {
background: var(--bg-ink-300) !important;
border-radius: 2px !important;
font-size: 12px !important;
font-weight: 500 !important;
margin-top: -2px !important;
min-width: 400px !important;
position: relative !important;
top: 0px !important;
left: 0px !important;
border-radius: 4px;
border: 1px solid var(--bg-slate-200, #1d212d);
ul {
width: 100% !important;
max-width: 100% !important;
&::-webkit-scrollbar {
width: 0.3rem;
}
&::-webkit-scrollbar-corner {
background: transparent;
}
&::-webkit-scrollbar-thumb {
background: rgb(136, 136, 136);
border-radius: 0.625rem;
}
&::-webkit-scrollbar-track {
background: transparent;
}
li {
width: 100% !important;
max-width: 100% !important;
line-height: 24px !important;
padding: 4px 8px !important;
display: flex !important;
align-items: center !important;
gap: 8px !important;
.cm-completionIcon {
display: none !important;
}
&[aria-selected='true'] {
background-color: rgba(78, 116, 248, 0.7) !important;
}
}
}
}
.cm-gutters {
display: none !important;
}
.cm-line {
line-height: 1.8 !important;
background: var(--bg-ink-300) !important;
::-moz-selection {
background: var(--bg-ink-100) !important;
opacity: 0.5 !important;
}
::selection {
background: var(--bg-ink-100) !important;
opacity: 0.5 !important;
}
}
.cm-selectionBackground {
background: var(--bg-ink-100) !important;
opacity: 0.5 !important;
}
}
.cursor-position {
@ -29,11 +112,12 @@
display: inline-flex;
align-items: center;
margin-bottom: 8px;
margin-top: 8px;
}
.query-validation {
display: flex;
align-items: center;
flex-direction: column;
gap: 8px;
margin-bottom: 8px;
@ -56,20 +140,39 @@
background-color: rgba(235, 87, 87, 0.1);
color: #eb5757;
}
.query-validation-status {
display: flex;
align-items: center;
gap: 8px;
}
.query-validation-errors {
display: flex;
flex-direction: column;
gap: 8px;
.query-validation-error {
display: flex;
flex-direction: row;
gap: 16px;
font-size: 12px;
font-family: 'Space Mono', monospace !important;
color: var(--bg-cherry-500);
}
}
}
.query-context {
padding: 12px;
background-color: var(--bg-vanilla-200);
background-color: var(--bg-ink-400);
border-radius: 4px;
border-left: 3px solid var(--bg-robin-500);
color: var(--bg-ink-300) !important;
h3 {
margin-top: 0;
margin-bottom: 8px;
font-size: 14px;
font-weight: 600;
color: var(--bg-ink-300);
.ant-card-head {
color: var(--bg-vanilla-300) !important;
}
.context-details {
@ -82,7 +185,7 @@
font-size: 13px;
strong {
color: var(--bg-ink-300);
color: var(--bg-vanilla-300);
margin-right: 4px;
}
}

View File

@ -5,12 +5,7 @@
import './CodeMirrorWhereClause.styles.scss';
import {
CheckCircleFilled,
CloseCircleFilled,
InfoCircleOutlined,
QuestionCircleOutlined,
} from '@ant-design/icons';
import { CheckCircleFilled, CloseCircleFilled } from '@ant-design/icons';
import {
autocompletion,
CompletionContext,
@ -20,12 +15,15 @@ import {
import { javascript } from '@codemirror/lang-javascript';
import { copilot } from '@uiw/codemirror-theme-copilot';
import CodeMirror, { EditorView, Extension } from '@uiw/react-codemirror';
import { Badge, Card, Divider, Space, Tooltip, Typography } from 'antd';
import { Badge, Card, Divider, Space, Typography } from 'antd';
import { getValueSuggestions } from 'api/querySuggestions/getValueSuggestion';
import { useGetQueryKeySuggestions } from 'hooks/querySuggestions/useGetQueryKeySuggestions';
// import { useGetQueryKeyValueSuggestions } from 'hooks/querySuggestions/useGetQueryKeyValueSuggestions';
import { useCallback, useEffect, useRef, useState } from 'react';
import { IQueryContext, IValidationResult } from 'types/antlrQueryTypes';
import {
IDetailedError,
IQueryContext,
IValidationResult,
} from 'types/antlrQueryTypes';
import { QueryKeySuggestionsProps } from 'types/api/querySuggestions/types';
import {
getQueryContextAtCursor,
@ -33,7 +31,7 @@ import {
validateQuery,
} from 'utils/antlrQueryUtils';
const { Text, Title } = Typography;
const { Text } = Typography;
function collapseSpacesOutsideStrings(): Extension {
return EditorView.inputHandler.of((view, from, to, text) => {
@ -244,7 +242,7 @@ function CodeMirrorWhereClause(): JSX.Element {
setValidation({
isValid: false,
message: 'Failed to process query',
errors: [error instanceof Error ? error.message : 'Unknown error'],
errors: [error as IDetailedError],
});
}
}, []);
@ -289,15 +287,7 @@ function CodeMirrorWhereClause(): JSX.Element {
// text = 'Parenthesis';
// }
return (
<Badge
color={color}
text={text}
style={{
color: 'black',
}}
/>
);
return <Badge color={color} text={text} />;
};
function myCompletions(context: CompletionContext): CompletionResult | null {
@ -380,33 +370,6 @@ function CodeMirrorWhereClause(): JSX.Element {
};
}
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',
},
});
// Add back the generateOptions function and useEffect
const generateOptions = (data: any): any[] =>
Object.values(data.keys).flatMap((items: any) =>
@ -440,15 +403,7 @@ function CodeMirrorWhereClause(): JSX.Element {
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>
}
>
<Card size="small">
<CodeMirror
value={query}
theme={copilot}
@ -466,41 +421,57 @@ function CodeMirrorWhereClause(): JSX.Element {
}),
collapseSpacesOutsideStrings(),
javascript({ jsx: false, typescript: false }),
customTheme,
// customTheme,
]}
basicSetup={{
lineNumbers: false,
}}
/>
<Space className="cursor-position" size={4}>
<InfoCircleOutlined />
<Text style={{ color: 'black' }}>
Line: {cursorPos.line}, Position: {cursorPos.ch}
</Text>
</Space>
{query && (
<>
<Divider style={{ margin: '8px 0' }} />
<Space direction="vertical" size={4}>
<Text>Query:</Text>
<Text code>{query}</Text>
</Space>
</>
)}
<Divider style={{ margin: '8px 0' }} />
{query && (
<>
<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>
<div className="query-validation">
<div className="query-validation-status">
<Text>Status:</Text>
<div className={validation.isValid ? 'valid' : 'invalid'}>
{validation.isValid ? (
<Space>
<CheckCircleFilled /> Valid
</Space>
) : (
<Space>
<CloseCircleFilled /> Invalid
</Space>
)}
</div>
</div>
<div className="query-validation-errors">
{validation.errors.map((error) => (
<div key={error.message} className="query-validation-error">
<div className="query-validation-error-line">
{error.line}:{error.column}
</div>
<div className="query-validation-error-message">{error.message}</div>
</div>
))}
</div>
</div>
</>
)}
</Card>
{queryContext && (
@ -508,107 +479,43 @@ function CodeMirrorWhereClause(): JSX.Element {
<div className="context-details">
<Space direction="vertical" size={4}>
<Space>
<Text strong style={{ color: 'black' }}>
Token:
</Text>
<Text code style={{ color: 'black' }}>
{queryContext.currentToken || '-'}
</Text>
<Text strong>Token:</Text>
<Text code>{queryContext.currentToken || '-'}</Text>
</Space>
<Space>
<Text strong style={{ color: 'black' }}>
Type:
</Text>
<Text style={{ color: 'black' }}>{queryContext.tokenType || '-'}</Text>
<Text strong>Type:</Text>
<Text>{queryContext.tokenType || '-'}</Text>
</Space>
<Space>
<Text strong style={{ color: 'black' }}>
Context:
</Text>
<Text strong>Context:</Text>
{renderContextBadge()}
</Space>
{/* 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>
<Text strong>Key:</Text>
<Text code>{queryContext.keyToken}</Text>
</Space>
)}
{queryContext.operatorToken && (
<Space>
<Text strong style={{ color: 'black' }}>
Operator:
</Text>
<Text code style={{ color: 'purple' }}>
{queryContext.operatorToken}
</Text>
<Text strong>Operator:</Text>
<Text code>{queryContext.operatorToken}</Text>
</Space>
)}
{queryContext.valueToken && (
<Space>
<Text strong style={{ color: 'black' }}>
Value:
</Text>
<Text code style={{ color: 'green' }}>
{queryContext.valueToken}
</Text>
<Text strong>Value:</Text>
<Text code>{queryContext.valueToken}</Text>
</Space>
)}
</Space>
</div>
</Card>
)}
<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 style={{ color: 'black' }}>
status = &apos;error&apos;
</Text>
</li>
<li>
<Text code style={{ color: 'black' }}>
service = &apos;frontend&apos; AND level = &apos;error&apos;
</Text>
</li>
<li>
<Text code style={{ color: 'black' }}>
message LIKE &apos;%timeout%&apos;
</Text>
</li>
<li>
<Text code style={{ color: 'black' }}>
duration {'>'} 1000
</Text>
</li>
<li>
<Text code style={{ color: 'black' }}>
tags IN [&apos;prod&apos;, &apos;frontend&apos;]
</Text>
</li>
<li>
<Text code style={{ color: 'black' }}>
NOT (status = &apos;error&apos; OR level = &apos;error&apos;)
</Text>
</li>
</ul>
</Card>
</div>
);
}

View File

@ -37,7 +37,13 @@ function QueryWhereClause(): JSX.Element {
setValidation({
isValid: false,
message: 'Failed to process query',
errors: [error instanceof Error ? error.message : 'Unknown error'],
errors: [
{
message: error instanceof Error ? error.message : 'Unknown error',
line: 0,
column: 0,
},
],
});
} finally {
setIsLoading(false);
@ -79,7 +85,7 @@ function QueryWhereClause(): JSX.Element {
{queryContext && (
<div className="query-context">
<h3>Current Context</h3>
<Text strong>Current Context</Text>
<div className="context-details">
<p>
<strong>Token:</strong> {queryContext.currentToken}

View File

@ -1,7 +1,7 @@
export interface IValidationResult {
isValid: boolean;
message: string;
errors: string[];
errors: IDetailedError[];
}
export interface IToken {

View File

@ -92,14 +92,22 @@ class QueryErrorListener {
getFormattedErrors(): string[] {
return this.errors.map((error) => {
let message = `Line ${error.line}:${error.column} - ${error.message}`;
const {
offendingSymbol,
expectedTokens,
message: errorMessage,
line,
column,
} = error;
if (error.offendingSymbol && error.offendingSymbol !== 'undefined') {
message += `\nOffending symbol: '${error.offendingSymbol}'`;
let message = `Line ${line}:${column} - ${errorMessage}`;
if (offendingSymbol && offendingSymbol !== 'undefined') {
message += `\n Symbol: '${offendingSymbol}'`;
}
if (error.expectedTokens && error.expectedTokens.length > 0) {
message += `\nExpected: ${error.expectedTokens.join(', ')}`;
if (expectedTokens && expectedTokens.length > 0) {
message += `\n Expected: ${expectedTokens.join(', ')}`;
}
return message;
@ -113,7 +121,15 @@ export const validateQuery = (query: string): IValidationResult => {
return {
isValid: false,
message: 'Query cannot be empty',
errors: ['Query cannot be empty'],
errors: [
{
message: 'Query cannot be empty',
line: 0,
column: 0,
offendingSymbol: '',
expectedTokens: [],
},
],
};
}
@ -133,16 +149,14 @@ export const validateQuery = (query: string): IValidationResult => {
parser.addErrorListener(errorListener);
// Try parsing
const parsedTree = parser.query();
console.log('parsedTree', parsedTree);
parser.query();
// Check if any errors were captured
if (errorListener.hasErrors()) {
return {
isValid: false,
message: 'Query syntax error',
errors: errorListener.getFormattedErrors(),
errors: errorListener.getErrors(),
};
}
@ -154,10 +168,18 @@ export const validateQuery = (query: string): IValidationResult => {
} catch (error) {
const errorMessage =
error instanceof Error ? error.message : 'Invalid query syntax';
const detailedError: IDetailedError = {
message: errorMessage,
line: 0,
column: 0,
offendingSymbol: '',
expectedTokens: [],
};
return {
isValid: false,
message: 'Invalid query syntax',
errors: [errorMessage],
errors: [detailedError],
};
}
};