Skip to content

Commit

Permalink
feat: display view query text (#1780)
Browse files Browse the repository at this point in the history
  • Loading branch information
astandrik authored Dec 23, 2024
1 parent 37ccfb5 commit d590f05
Show file tree
Hide file tree
Showing 10 changed files with 494 additions and 42 deletions.
289 changes: 284 additions & 5 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"react-redux": "^9.1.2",
"react-router-dom": "^5.3.4",
"react-split": "^2.0.14",
"react-syntax-highlighter": "^15.6.1",
"redux": "^5.0.1",
"redux-location-state": "^2.8.2",
"tslib": "^2.6.3",
Expand Down Expand Up @@ -136,6 +137,7 @@
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@types/react-router-dom": "^5.3.3",
"@types/react-syntax-highlighter": "^15.5.13",
"@types/uuid": "^10.0.0",
"copyfiles": "^2.4.1",
"http-proxy-middleware": "^2.0.6",
Expand All @@ -144,7 +146,7 @@
"lint-staged": "^15.2.7",
"mini-css-extract-plugin": "^2.9.1",
"monaco-editor-webpack-plugin": "^7.1.0",
"monaco-yql-languages": "^1.0.6",
"monaco-yql-languages": "^1.2.1",
"npm-run-all": "^4.1.5",
"postcss": "^8.4.38",
"prettier": "^3.2.5",
Expand Down
1 change: 1 addition & 0 deletions playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const config: PlaywrightTestConfig = {
: {
command: 'npm run dev',
port: 3000,
reuseExistingServer: true,
},
use: {
baseURL: baseUrl || 'http://localhost:3000/',
Expand Down
8 changes: 0 additions & 8 deletions src/components/TruncatedQuery/TruncatedQuery.scss
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,4 @@
}
}
}

&__popover-content {
overflow: hidden;

max-width: 600px;

white-space: pre;
}
}
18 changes: 3 additions & 15 deletions src/components/TruncatedQuery/TruncatedQuery.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';

import {cn} from '../../utils/cn';
import {CellWithPopover} from '../CellWithPopover/CellWithPopover';
import {YqlHighlighter} from '../YqlHighlighter/YqlHighlighter';

import './TruncatedQuery.scss';

Expand All @@ -22,22 +22,10 @@ export const TruncatedQuery = ({value = '', maxQueryHeight = 6}: TruncatedQueryP
'\n...\nThe request was truncated. Click on the line to show the full query on the query tab';
return (
<React.Fragment>
<span className={b()}>{content}</span>
<YqlHighlighter className={b()}>{content}</YqlHighlighter>
<span className={b('message', {color: 'secondary'})}>{message}</span>
</React.Fragment>
);
}
return <React.Fragment>{value}</React.Fragment>;
};

interface OneLineQueryWithPopoverProps {
value?: string;
}

export const OneLineQueryWithPopover = ({value = ''}: OneLineQueryWithPopoverProps) => {
return (
<CellWithPopover contentClassName={b('popover-content')} content={value}>
{value}
</CellWithPopover>
);
return <YqlHighlighter>{value}</YqlHighlighter>;
};
28 changes: 28 additions & 0 deletions src/components/YqlHighlighter/YqlHighlighter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import {useThemeValue} from '@gravity-ui/uikit';
import {PrismLight as SyntaxHighlighter} from 'react-syntax-highlighter';

import {cn} from '../../utils/cn';

import {dark, light, yql} from './yql';

SyntaxHighlighter.registerLanguage('yql', yql);

const b = cn('yql-highlighter');

interface YqlHighlighterProps {
children: string;
className?: string;
}

export const YqlHighlighter = ({children, className}: YqlHighlighterProps) => {
const themeValue = useThemeValue();
const isDark = themeValue === 'dark' || themeValue === 'dark-hc';

return (
<div className={b(null, className)}>
<SyntaxHighlighter language="yql" style={isDark ? dark : light}>
{children}
</SyntaxHighlighter>
</div>
);
};
168 changes: 168 additions & 0 deletions src/components/YqlHighlighter/yql.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
import {
builtinFunctions,
keywords,
typeKeywords,
} from 'monaco-yql-languages/build/yql/yql.keywords';
import {
vscDarkPlus as darkTheme,
materialLight as lightTheme,
} from 'react-syntax-highlighter/dist/esm/styles/prism';

export const light = {
...lightTheme,
'pre[class*="language-"]': {
...lightTheme['pre[class*="language-"]'],
background: 'transparent',
margin: 0,
},
'code[class*="language-"]': {
...lightTheme['code[class*="language-"]'],
background: 'transparent',
color: 'var(--g-color-text-primary)',
whiteSpace: 'pre-wrap' as const,
},
comment: {
color: '#969896',
},
string: {
color: '#a31515',
},
tablepath: {
color: '#338186',
},
function: {
color: '#7a3e9d',
},
udf: {
color: '#7a3e9d',
},
type: {
color: '#4d932d',
},
boolean: {
color: '#608b4e',
},
constant: {
color: '#608b4e',
},
variable: {
color: '#001188',
},
};

export const dark = {
...darkTheme,
'pre[class*="language-"]': {
...darkTheme['pre[class*="language-"]'],
background: 'transparent',
margin: 0,
},
'code[class*="language-"]': {
...darkTheme['code[class*="language-"]'],
background: 'transparent',
color: 'var(--g-color-text-primary)',
whiteSpace: 'pre-wrap' as const,
},
comment: {
color: '#969896',
},
string: {
color: '#ce9178',
},
tablepath: {
color: '#338186',
},
function: {
color: '#9e7bb0',
},
udf: {
color: '#9e7bb0',
},
type: {
color: '#6A8759',
},
boolean: {
color: '#608b4e',
},
constant: {
color: '#608b4e',
},
variable: {
color: '#74b0df',
},
};

export function yql(Prism: any) {
// Define YQL language
Prism.languages.yql = {
comment: [
{
pattern: /--.*$/m,
greedy: true,
},
{
pattern: /\/\*[\s\S]*?(?:\*\/|$)/,
greedy: true,
},
],
tablepath: {
pattern: /(`[\w/]+`\s*\.\s*)?`[^`]+`/,
greedy: true,
},
string: [
{
pattern: /'(?:\\[\s\S]|[^\\'])*'/,
greedy: true,
},
{
pattern: /"(?:\\[\s\S]|[^\\"])*"/,
greedy: true,
},
{
pattern: /@@(?:[^@]|@(?!@))*@@/,
greedy: true,
},
],
variable: [
{
pattern: /\$[a-zA-Z_]\w*/,
greedy: true,
},
],
function: {
pattern: new RegExp(`\\b(?:${builtinFunctions.join('|')})\\b`, 'i'),
greedy: true,
},
keyword: {
pattern: new RegExp(`\\b(?:${keywords.join('|')})\\b`, 'i'),
greedy: true,
},
udf: {
pattern: /[A-Za-z_]\w*::[A-Za-z_]\w*/,
greedy: true,
},
type: {
pattern: new RegExp(`\\b(?:${typeKeywords.join('|')})\\b`, 'i'),
greedy: true,
},
boolean: {
pattern: /\b(?:true|false|null)\b/i,
greedy: true,
},
number: {
pattern: /[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?/i,
greedy: true,
},
operator: {
pattern: /[-+*/%<>!=&|^~]+|\b(?:and|or|not|is|like|ilike|rlike|in|between)\b/i,
greedy: true,
},
punctuation: {
pattern: /[;[\](){}.,]/,
greedy: true,
},
};
}

yql.displayName = 'yql';
yql.aliases = ['yql'] as string[];
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import DataTable from '@gravity-ui/react-data-table';
import type {Column} from '@gravity-ui/react-data-table';

import {
OneLineQueryWithPopover,
TruncatedQuery,
} from '../../../../../components/TruncatedQuery/TruncatedQuery';
import {TruncatedQuery} from '../../../../../components/TruncatedQuery/TruncatedQuery';
import {YqlHighlighter} from '../../../../../components/YqlHighlighter/YqlHighlighter';
import type {KeyValueRow} from '../../../../../types/api/query';
import {cn} from '../../../../../utils/cn';
import {formatDateTime, formatNumber} from '../../../../../utils/dataFormatters/dataFormatters';
Expand Down Expand Up @@ -82,7 +80,7 @@ const userSIDColumn: Column<KeyValueRow> = {
const oneLineQueryTextColumn: Column<KeyValueRow> = {
name: TOP_QUERIES_COLUMNS_IDS.OneLineQueryText,
header: TOP_QUERIES_COLUMNS_TITLES.OneLineQueryText,
render: ({row}) => <OneLineQueryWithPopover value={row.QueryText?.toString()} />,
render: ({row}) => <YqlHighlighter>{row.QueryText?.toString() || ''}</YqlHighlighter>,
sortable: false,
width: 500,
};
Expand Down
8 changes: 2 additions & 6 deletions src/containers/Tenant/Info/View/View.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type {DefinitionListItem} from '@gravity-ui/components';
import {Text} from '@gravity-ui/uikit';

import {YDBDefinitionList} from '../../../../components/YDBDefinitionList/YDBDefinitionList';
import {YqlHighlighter} from '../../../../components/YqlHighlighter/YqlHighlighter';
import type {TEvDescribeSchemeResult} from '../../../../types/api/schema';
import {getEntityName} from '../../utils';
import i18n from '../i18n';
Expand All @@ -13,11 +13,7 @@ const prepareViewItems = (data: TEvDescribeSchemeResult): DefinitionListItem[] =
{
name: i18n('view.query-text'),
copyText: queryText,
content: (
<Text variant="code-2" wordBreak="break-word">
{queryText}
</Text>
),
content: queryText ? <YqlHighlighter>{queryText}</YqlHighlighter> : null,
},
];
};
Expand Down
4 changes: 2 additions & 2 deletions tests/suites/tenant/queryHistory/queryHistory.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ test.describe('Query History', () => {

// Check if the query appears in the history
const historyTable = page.locator('.ydb-queries-history table');
await expect(historyTable.locator(`text="${testQuery}"`)).toBeVisible({
await expect(historyTable.locator('.yql-highlighter', {hasText: testQuery})).toBeVisible({
timeout: VISIBILITY_TIMEOUT,
});
});
Expand Down Expand Up @@ -85,6 +85,6 @@ test.describe('Query History', () => {

// Check if the query appears in the history
const historyTable = page.locator('.ydb-queries-history table');
await expect(historyTable.locator(`text="${testQuery}"`)).toBeVisible();
await expect(historyTable.locator('.yql-highlighter', {hasText: testQuery})).toBeVisible();
});
});

0 comments on commit d590f05

Please sign in to comment.