Skip to content

Commit d590f05

Browse files
authored
feat: display view query text (#1780)
1 parent 37ccfb5 commit d590f05

File tree

10 files changed

+494
-42
lines changed

10 files changed

+494
-42
lines changed

package-lock.json

+284-5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
"react-redux": "^9.1.2",
4848
"react-router-dom": "^5.3.4",
4949
"react-split": "^2.0.14",
50+
"react-syntax-highlighter": "^15.6.1",
5051
"redux": "^5.0.1",
5152
"redux-location-state": "^2.8.2",
5253
"tslib": "^2.6.3",
@@ -136,6 +137,7 @@
136137
"@types/react": "^18.3.3",
137138
"@types/react-dom": "^18.3.0",
138139
"@types/react-router-dom": "^5.3.3",
140+
"@types/react-syntax-highlighter": "^15.5.13",
139141
"@types/uuid": "^10.0.0",
140142
"copyfiles": "^2.4.1",
141143
"http-proxy-middleware": "^2.0.6",
@@ -144,7 +146,7 @@
144146
"lint-staged": "^15.2.7",
145147
"mini-css-extract-plugin": "^2.9.1",
146148
"monaco-editor-webpack-plugin": "^7.1.0",
147-
"monaco-yql-languages": "^1.0.6",
149+
"monaco-yql-languages": "^1.2.1",
148150
"npm-run-all": "^4.1.5",
149151
"postcss": "^8.4.38",
150152
"prettier": "^3.2.5",

playwright.config.ts

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ const config: PlaywrightTestConfig = {
1919
: {
2020
command: 'npm run dev',
2121
port: 3000,
22+
reuseExistingServer: true,
2223
},
2324
use: {
2425
baseURL: baseUrl || 'http://localhost:3000/',

src/components/TruncatedQuery/TruncatedQuery.scss

-8
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,4 @@
1414
}
1515
}
1616
}
17-
18-
&__popover-content {
19-
overflow: hidden;
20-
21-
max-width: 600px;
22-
23-
white-space: pre;
24-
}
2517
}
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React from 'react';
22

33
import {cn} from '../../utils/cn';
4-
import {CellWithPopover} from '../CellWithPopover/CellWithPopover';
4+
import {YqlHighlighter} from '../YqlHighlighter/YqlHighlighter';
55

66
import './TruncatedQuery.scss';
77

@@ -22,22 +22,10 @@ export const TruncatedQuery = ({value = '', maxQueryHeight = 6}: TruncatedQueryP
2222
'\n...\nThe request was truncated. Click on the line to show the full query on the query tab';
2323
return (
2424
<React.Fragment>
25-
<span className={b()}>{content}</span>
25+
<YqlHighlighter className={b()}>{content}</YqlHighlighter>
2626
<span className={b('message', {color: 'secondary'})}>{message}</span>
2727
</React.Fragment>
2828
);
2929
}
30-
return <React.Fragment>{value}</React.Fragment>;
31-
};
32-
33-
interface OneLineQueryWithPopoverProps {
34-
value?: string;
35-
}
36-
37-
export const OneLineQueryWithPopover = ({value = ''}: OneLineQueryWithPopoverProps) => {
38-
return (
39-
<CellWithPopover contentClassName={b('popover-content')} content={value}>
40-
{value}
41-
</CellWithPopover>
42-
);
30+
return <YqlHighlighter>{value}</YqlHighlighter>;
4331
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import {useThemeValue} from '@gravity-ui/uikit';
2+
import {PrismLight as SyntaxHighlighter} from 'react-syntax-highlighter';
3+
4+
import {cn} from '../../utils/cn';
5+
6+
import {dark, light, yql} from './yql';
7+
8+
SyntaxHighlighter.registerLanguage('yql', yql);
9+
10+
const b = cn('yql-highlighter');
11+
12+
interface YqlHighlighterProps {
13+
children: string;
14+
className?: string;
15+
}
16+
17+
export const YqlHighlighter = ({children, className}: YqlHighlighterProps) => {
18+
const themeValue = useThemeValue();
19+
const isDark = themeValue === 'dark' || themeValue === 'dark-hc';
20+
21+
return (
22+
<div className={b(null, className)}>
23+
<SyntaxHighlighter language="yql" style={isDark ? dark : light}>
24+
{children}
25+
</SyntaxHighlighter>
26+
</div>
27+
);
28+
};

src/components/YqlHighlighter/yql.ts

+168
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
import {
2+
builtinFunctions,
3+
keywords,
4+
typeKeywords,
5+
} from 'monaco-yql-languages/build/yql/yql.keywords';
6+
import {
7+
vscDarkPlus as darkTheme,
8+
materialLight as lightTheme,
9+
} from 'react-syntax-highlighter/dist/esm/styles/prism';
10+
11+
export const light = {
12+
...lightTheme,
13+
'pre[class*="language-"]': {
14+
...lightTheme['pre[class*="language-"]'],
15+
background: 'transparent',
16+
margin: 0,
17+
},
18+
'code[class*="language-"]': {
19+
...lightTheme['code[class*="language-"]'],
20+
background: 'transparent',
21+
color: 'var(--g-color-text-primary)',
22+
whiteSpace: 'pre-wrap' as const,
23+
},
24+
comment: {
25+
color: '#969896',
26+
},
27+
string: {
28+
color: '#a31515',
29+
},
30+
tablepath: {
31+
color: '#338186',
32+
},
33+
function: {
34+
color: '#7a3e9d',
35+
},
36+
udf: {
37+
color: '#7a3e9d',
38+
},
39+
type: {
40+
color: '#4d932d',
41+
},
42+
boolean: {
43+
color: '#608b4e',
44+
},
45+
constant: {
46+
color: '#608b4e',
47+
},
48+
variable: {
49+
color: '#001188',
50+
},
51+
};
52+
53+
export const dark = {
54+
...darkTheme,
55+
'pre[class*="language-"]': {
56+
...darkTheme['pre[class*="language-"]'],
57+
background: 'transparent',
58+
margin: 0,
59+
},
60+
'code[class*="language-"]': {
61+
...darkTheme['code[class*="language-"]'],
62+
background: 'transparent',
63+
color: 'var(--g-color-text-primary)',
64+
whiteSpace: 'pre-wrap' as const,
65+
},
66+
comment: {
67+
color: '#969896',
68+
},
69+
string: {
70+
color: '#ce9178',
71+
},
72+
tablepath: {
73+
color: '#338186',
74+
},
75+
function: {
76+
color: '#9e7bb0',
77+
},
78+
udf: {
79+
color: '#9e7bb0',
80+
},
81+
type: {
82+
color: '#6A8759',
83+
},
84+
boolean: {
85+
color: '#608b4e',
86+
},
87+
constant: {
88+
color: '#608b4e',
89+
},
90+
variable: {
91+
color: '#74b0df',
92+
},
93+
};
94+
95+
export function yql(Prism: any) {
96+
// Define YQL language
97+
Prism.languages.yql = {
98+
comment: [
99+
{
100+
pattern: /--.*$/m,
101+
greedy: true,
102+
},
103+
{
104+
pattern: /\/\*[\s\S]*?(?:\*\/|$)/,
105+
greedy: true,
106+
},
107+
],
108+
tablepath: {
109+
pattern: /(`[\w/]+`\s*\.\s*)?`[^`]+`/,
110+
greedy: true,
111+
},
112+
string: [
113+
{
114+
pattern: /'(?:\\[\s\S]|[^\\'])*'/,
115+
greedy: true,
116+
},
117+
{
118+
pattern: /"(?:\\[\s\S]|[^\\"])*"/,
119+
greedy: true,
120+
},
121+
{
122+
pattern: /@@(?:[^@]|@(?!@))*@@/,
123+
greedy: true,
124+
},
125+
],
126+
variable: [
127+
{
128+
pattern: /\$[a-zA-Z_]\w*/,
129+
greedy: true,
130+
},
131+
],
132+
function: {
133+
pattern: new RegExp(`\\b(?:${builtinFunctions.join('|')})\\b`, 'i'),
134+
greedy: true,
135+
},
136+
keyword: {
137+
pattern: new RegExp(`\\b(?:${keywords.join('|')})\\b`, 'i'),
138+
greedy: true,
139+
},
140+
udf: {
141+
pattern: /[A-Za-z_]\w*::[A-Za-z_]\w*/,
142+
greedy: true,
143+
},
144+
type: {
145+
pattern: new RegExp(`\\b(?:${typeKeywords.join('|')})\\b`, 'i'),
146+
greedy: true,
147+
},
148+
boolean: {
149+
pattern: /\b(?:true|false|null)\b/i,
150+
greedy: true,
151+
},
152+
number: {
153+
pattern: /[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?/i,
154+
greedy: true,
155+
},
156+
operator: {
157+
pattern: /[-+*/%<>!=&|^~]+|\b(?:and|or|not|is|like|ilike|rlike|in|between)\b/i,
158+
greedy: true,
159+
},
160+
punctuation: {
161+
pattern: /[;[\](){}.,]/,
162+
greedy: true,
163+
},
164+
};
165+
}
166+
167+
yql.displayName = 'yql';
168+
yql.aliases = ['yql'] as string[];

src/containers/Tenant/Diagnostics/TopQueries/columns/columns.tsx

+3-5
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
import DataTable from '@gravity-ui/react-data-table';
22
import type {Column} from '@gravity-ui/react-data-table';
33

4-
import {
5-
OneLineQueryWithPopover,
6-
TruncatedQuery,
7-
} from '../../../../../components/TruncatedQuery/TruncatedQuery';
4+
import {TruncatedQuery} from '../../../../../components/TruncatedQuery/TruncatedQuery';
5+
import {YqlHighlighter} from '../../../../../components/YqlHighlighter/YqlHighlighter';
86
import type {KeyValueRow} from '../../../../../types/api/query';
97
import {cn} from '../../../../../utils/cn';
108
import {formatDateTime, formatNumber} from '../../../../../utils/dataFormatters/dataFormatters';
@@ -82,7 +80,7 @@ const userSIDColumn: Column<KeyValueRow> = {
8280
const oneLineQueryTextColumn: Column<KeyValueRow> = {
8381
name: TOP_QUERIES_COLUMNS_IDS.OneLineQueryText,
8482
header: TOP_QUERIES_COLUMNS_TITLES.OneLineQueryText,
85-
render: ({row}) => <OneLineQueryWithPopover value={row.QueryText?.toString()} />,
83+
render: ({row}) => <YqlHighlighter>{row.QueryText?.toString() || ''}</YqlHighlighter>,
8684
sortable: false,
8785
width: 500,
8886
};

src/containers/Tenant/Info/View/View.tsx

+2-6
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type {DefinitionListItem} from '@gravity-ui/components';
2-
import {Text} from '@gravity-ui/uikit';
32

43
import {YDBDefinitionList} from '../../../../components/YDBDefinitionList/YDBDefinitionList';
4+
import {YqlHighlighter} from '../../../../components/YqlHighlighter/YqlHighlighter';
55
import type {TEvDescribeSchemeResult} from '../../../../types/api/schema';
66
import {getEntityName} from '../../utils';
77
import i18n from '../i18n';
@@ -13,11 +13,7 @@ const prepareViewItems = (data: TEvDescribeSchemeResult): DefinitionListItem[] =
1313
{
1414
name: i18n('view.query-text'),
1515
copyText: queryText,
16-
content: (
17-
<Text variant="code-2" wordBreak="break-word">
18-
{queryText}
19-
</Text>
20-
),
16+
content: queryText ? <YqlHighlighter>{queryText}</YqlHighlighter> : null,
2117
},
2218
];
2319
};

tests/suites/tenant/queryHistory/queryHistory.test.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ test.describe('Query History', () => {
3434

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

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

0 commit comments

Comments
 (0)