diff --git a/src/components/ConnectToDB/ConnectToDBDialog.tsx b/src/components/ConnectToDB/ConnectToDBDialog.tsx index b2c0fc7837..fe0a115678 100644 --- a/src/components/ConnectToDB/ConnectToDBDialog.tsx +++ b/src/components/ConnectToDB/ConnectToDBDialog.tsx @@ -5,8 +5,8 @@ import {Dialog, Tabs} from '@gravity-ui/uikit'; import {cn} from '../../utils/cn'; import {LinkWithIcon} from '../LinkWithIcon/LinkWithIcon'; +import {YDBSyntaxHighlighterLazy} from '../SyntaxHighlighter/lazy'; -import {ConnectToDBSyntaxHighlighterLazy} from './ConnectToDBSyntaxHighlighter/lazy'; import {getDocsLink} from './getDocsLink'; import i18n from './i18n'; import {getSnippetCode} from './snippets'; @@ -52,7 +52,12 @@ function ConnectToDBDialog({open, onClose, database, endpoint}: ConnectToDBDialo className={b('dialog-tabs')} />
- +
{docsLink ? ( = { - ...dark, - 'pre[class*="language-"]': { - ...dark['pre[class*="language-"]'], - background: vscDarkPlus['pre[class*="language-"]'].background, - scrollbarColor: `var(--g-color-scroll-handle) transparent`, - }, - 'code[class*="language-"]': { - ...dark['code[class*="language-"]'], - whiteSpace: 'pre', - }, -}; - -const lightTheme: Record = { - ...light, - 'pre[class*="language-"]': { - ...light['pre[class*="language-"]'], - background: 'var(--g-color-base-misc-light)', - scrollbarColor: `var(--g-color-scroll-handle) transparent`, - }, - 'code[class*="language-"]': { - ...light['code[class*="language-"]'], - whiteSpace: 'pre', - }, -}; - -const b = cn('ydb-connect-to-db-syntax-highlighter'); - -export function ConnectToDBSyntaxHighlighter({text, language}: ConnectToDBSyntaxHighlighterProps) { - const themeValue = useThemeValue(); - const isDark = themeValue === 'dark' || themeValue === 'dark-hc'; - - return ( -
-
- - {i18n('copy')} - -
- - {text} - -
- ); -} diff --git a/src/components/ConnectToDB/ConnectToDBSyntaxHighlighter/lazy.ts b/src/components/ConnectToDB/ConnectToDBSyntaxHighlighter/lazy.ts deleted file mode 100644 index b908858c48..0000000000 --- a/src/components/ConnectToDB/ConnectToDBSyntaxHighlighter/lazy.ts +++ /dev/null @@ -1,6 +0,0 @@ -import {lazyComponent} from '../../../utils/lazyComponent'; - -export const ConnectToDBSyntaxHighlighterLazy = lazyComponent( - () => import('./ConnectToDBSyntaxHighlighter'), - 'ConnectToDBSyntaxHighlighter', -); diff --git a/src/components/ConnectToDB/i18n/en.json b/src/components/ConnectToDB/i18n/en.json index 055261a991..0fdf24e6bd 100644 --- a/src/components/ConnectToDB/i18n/en.json +++ b/src/components/ConnectToDB/i18n/en.json @@ -5,7 +5,6 @@ "documentation": "Documentation", "close": "Close", - "copy": "Copy", "docs_bash": "https://ydb.tech/docs/en/concepts/connect", "docs_cpp": "https://ydb.tech/docs/en/dev/example-app/example-cpp", diff --git a/src/components/ConnectToDB/ConnectToDBSyntaxHighlighter/ConnectToDBSyntaxHighlighter.scss b/src/components/SyntaxHighlighter/YDBSyntaxHighlighter.scss similarity index 54% rename from src/components/ConnectToDB/ConnectToDBSyntaxHighlighter/ConnectToDBSyntaxHighlighter.scss rename to src/components/SyntaxHighlighter/YDBSyntaxHighlighter.scss index 1520d75410..55a027d140 100644 --- a/src/components/ConnectToDB/ConnectToDBSyntaxHighlighter/ConnectToDBSyntaxHighlighter.scss +++ b/src/components/SyntaxHighlighter/YDBSyntaxHighlighter.scss @@ -1,12 +1,10 @@ -@use '../../../styles/mixins.scss'; +@use '../../styles/mixins.scss'; -.ydb-connect-to-db-syntax-highlighter { - &__wrapper { - position: relative; - z-index: 0; +.ydb-syntax-highlighter { + position: relative; + z-index: 0; - height: 100%; - } + height: 100%; &__sticky-container { z-index: 1; diff --git a/src/components/SyntaxHighlighter/YDBSyntaxHighlighter.tsx b/src/components/SyntaxHighlighter/YDBSyntaxHighlighter.tsx new file mode 100644 index 0000000000..8021ba93c9 --- /dev/null +++ b/src/components/SyntaxHighlighter/YDBSyntaxHighlighter.tsx @@ -0,0 +1,86 @@ +import React from 'react'; + +import {ClipboardButton} from '@gravity-ui/uikit'; +import {nanoid} from '@reduxjs/toolkit'; +import {PrismLight as ReactSyntaxHighlighter} from 'react-syntax-highlighter'; + +import i18n from './i18n'; +import {b} from './shared'; +import {useSyntaxHighlighterStyle} from './themes'; +import type {Language} from './types'; +import {yql} from './yql'; + +import './YDBSyntaxHighlighter.scss'; + +async function registerLanguage(lang: Language) { + if (lang === 'yql') { + ReactSyntaxHighlighter.registerLanguage('yql', yql); + } else { + const {default: syntax} = await import( + `react-syntax-highlighter/dist/esm/languages/prism/${lang}` + ); + ReactSyntaxHighlighter.registerLanguage(lang, syntax); + } +} + +type YDBSyntaxHighlighterProps = { + text: string; + language: Language; + className?: string; + transparentBackground?: boolean; + withCopy?: boolean; +}; + +export function YDBSyntaxHighlighter({ + text, + language, + className, + transparentBackground = true, + withCopy, +}: YDBSyntaxHighlighterProps) { + const [highlighterKey, setHighlighterKey] = React.useState(''); + + const style = useSyntaxHighlighterStyle(transparentBackground); + + React.useEffect(() => { + async function registerLangAndUpdateKey() { + await registerLanguage(language); + setHighlighterKey(nanoid()); + } + registerLangAndUpdateKey(); + }, [language]); + + const renderCopyButton = () => { + if (withCopy) { + return ( +
+ + {i18n('copy')} + +
+ ); + } + + return null; + }; + + return ( +
+ {renderCopyButton()} + + + {text} + +
+ ); +} diff --git a/src/components/SyntaxHighlighter/i18n/en.json b/src/components/SyntaxHighlighter/i18n/en.json new file mode 100644 index 0000000000..65f49e31f7 --- /dev/null +++ b/src/components/SyntaxHighlighter/i18n/en.json @@ -0,0 +1,3 @@ +{ + "copy": "Copy" +} diff --git a/src/components/SyntaxHighlighter/i18n/index.ts b/src/components/SyntaxHighlighter/i18n/index.ts new file mode 100644 index 0000000000..4a8450b7ab --- /dev/null +++ b/src/components/SyntaxHighlighter/i18n/index.ts @@ -0,0 +1,7 @@ +import {registerKeysets} from '../../../utils/i18n'; + +import en from './en.json'; + +const COMPONENT = 'ydb-syntax-highlighter'; + +export default registerKeysets(COMPONENT, {en}); diff --git a/src/components/SyntaxHighlighter/lazy.ts b/src/components/SyntaxHighlighter/lazy.ts new file mode 100644 index 0000000000..5cf310eb8b --- /dev/null +++ b/src/components/SyntaxHighlighter/lazy.ts @@ -0,0 +1,6 @@ +import {lazyComponent} from '../../utils/lazyComponent'; + +export const YDBSyntaxHighlighterLazy = lazyComponent( + () => import('./YDBSyntaxHighlighter'), + 'YDBSyntaxHighlighter', +); diff --git a/src/components/SyntaxHighlighter/shared.ts b/src/components/SyntaxHighlighter/shared.ts new file mode 100644 index 0000000000..855677d5c4 --- /dev/null +++ b/src/components/SyntaxHighlighter/shared.ts @@ -0,0 +1,3 @@ +import {cn} from '../../utils/cn'; + +export const b = cn('ydb-syntax-highlighter'); diff --git a/src/components/SyntaxHighlighter/themes.ts b/src/components/SyntaxHighlighter/themes.ts new file mode 100644 index 0000000000..3c5204731d --- /dev/null +++ b/src/components/SyntaxHighlighter/themes.ts @@ -0,0 +1,123 @@ +import {useThemeValue} from '@gravity-ui/uikit'; +import {materialLight, vscDarkPlus} from 'react-syntax-highlighter/dist/esm/styles/prism'; + +export const lightTransparent = { + ...materialLight, + 'pre[class*="language-"]': { + ...materialLight['pre[class*="language-"]'], + background: 'transparent', + margin: 0, + }, + 'code[class*="language-"]': { + ...materialLight['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 darkTransparent = { + ...vscDarkPlus, + 'pre[class*="language-"]': { + ...vscDarkPlus['pre[class*="language-"]'], + background: 'transparent', + margin: 0, + }, + 'code[class*="language-"]': { + ...vscDarkPlus['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', + }, +}; + +const dark: Record = { + ...darkTransparent, + 'pre[class*="language-"]': { + ...darkTransparent['pre[class*="language-"]'], + background: vscDarkPlus['pre[class*="language-"]'].background, + scrollbarColor: `var(--g-color-scroll-handle) transparent`, + }, + 'code[class*="language-"]': { + ...darkTransparent['code[class*="language-"]'], + whiteSpace: 'pre', + }, +}; + +const light: Record = { + ...lightTransparent, + 'pre[class*="language-"]': { + ...lightTransparent['pre[class*="language-"]'], + background: 'var(--g-color-base-misc-light)', + scrollbarColor: `var(--g-color-scroll-handle) transparent`, + }, + 'code[class*="language-"]': { + ...lightTransparent['code[class*="language-"]'], + whiteSpace: 'pre', + }, +}; + +export function useSyntaxHighlighterStyle(transparentBackground?: boolean) { + const themeValue = useThemeValue(); + const isDark = themeValue === 'dark' || themeValue === 'dark-hc'; + + if (transparentBackground) { + return isDark ? darkTransparent : lightTransparent; + } + + return isDark ? dark : light; +} diff --git a/src/components/SyntaxHighlighter/types.ts b/src/components/SyntaxHighlighter/types.ts new file mode 100644 index 0000000000..62c51d4596 --- /dev/null +++ b/src/components/SyntaxHighlighter/types.ts @@ -0,0 +1,10 @@ +export type Language = + | 'bash' + | 'cpp' + | 'csharp' + | 'go' + | 'java' + | 'javascript' + | 'php' + | 'python' + | 'yql'; diff --git a/src/components/YqlHighlighter/yql.ts b/src/components/SyntaxHighlighter/yql.ts similarity index 53% rename from src/components/YqlHighlighter/yql.ts rename to src/components/SyntaxHighlighter/yql.ts index 05a77f6577..0020280d9e 100644 --- a/src/components/YqlHighlighter/yql.ts +++ b/src/components/SyntaxHighlighter/yql.ts @@ -3,97 +3,11 @@ import { 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', - }, -}; +// eslint-disable-next-line @typescript-eslint/no-explicit-any export function yql(Prism: any) { // Define YQL language + // eslint-disable-next-line no-param-reassign Prism.languages.yql = { comment: [ { diff --git a/src/components/TruncatedQuery/TruncatedQuery.tsx b/src/components/TruncatedQuery/TruncatedQuery.tsx index afac9e56c6..952c2434a1 100644 --- a/src/components/TruncatedQuery/TruncatedQuery.tsx +++ b/src/components/TruncatedQuery/TruncatedQuery.tsx @@ -1,7 +1,7 @@ import React from 'react'; import {cn} from '../../utils/cn'; -import {YqlHighlighter} from '../YqlHighlighter/YqlHighlighter'; +import {YDBSyntaxHighlighter} from '../SyntaxHighlighter/YDBSyntaxHighlighter'; import './TruncatedQuery.scss'; @@ -22,10 +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 ( - {content} + {message} ); } - return {value}; + return ; }; diff --git a/src/components/YqlHighlighter/YqlHighlighter.tsx b/src/components/YqlHighlighter/YqlHighlighter.tsx deleted file mode 100644 index 90d62f0b23..0000000000 --- a/src/components/YqlHighlighter/YqlHighlighter.tsx +++ /dev/null @@ -1,28 +0,0 @@ -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 ( -
- - {children} - -
- ); -}; diff --git a/src/containers/Tenant/Diagnostics/Overview/TransferInfo/TransferInfo.tsx b/src/containers/Tenant/Diagnostics/Overview/TransferInfo/TransferInfo.tsx index 6981941f11..f103b7c341 100644 --- a/src/containers/Tenant/Diagnostics/Overview/TransferInfo/TransferInfo.tsx +++ b/src/containers/Tenant/Diagnostics/Overview/TransferInfo/TransferInfo.tsx @@ -2,8 +2,8 @@ import type {DefinitionListItem} from '@gravity-ui/components'; import {Flex, Text} from '@gravity-ui/uikit'; import {AsyncReplicationState} from '../../../../../components/AsyncReplicationState'; +import {YDBSyntaxHighlighter} from '../../../../../components/SyntaxHighlighter/YDBSyntaxHighlighter'; import {YDBDefinitionList} from '../../../../../components/YDBDefinitionList/YDBDefinitionList'; -import {YqlHighlighter} from '../../../../../components/YqlHighlighter/YqlHighlighter'; import type {TEvDescribeSchemeResult} from '../../../../../types/api/schema'; import {getEntityName} from '../../../utils'; @@ -92,7 +92,9 @@ function prepareTransferItems(data: TEvDescribeSchemeResult) { info.push({ name: i18n('transformLambda.label'), copyText: transformLambda, - content: transformLambda ? {transformLambda} : null, + content: transformLambda ? ( + + ) : null, }); return info; diff --git a/src/containers/Tenant/Diagnostics/TopQueries/columns/columns.tsx b/src/containers/Tenant/Diagnostics/TopQueries/columns/columns.tsx index 657cde5fe3..5ca5bd52f9 100644 --- a/src/containers/Tenant/Diagnostics/TopQueries/columns/columns.tsx +++ b/src/containers/Tenant/Diagnostics/TopQueries/columns/columns.tsx @@ -1,8 +1,8 @@ import DataTable from '@gravity-ui/react-data-table'; import type {Column} from '@gravity-ui/react-data-table'; +import {YDBSyntaxHighlighter} from '../../../../../components/SyntaxHighlighter/YDBSyntaxHighlighter'; 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'; @@ -80,7 +80,9 @@ const userSIDColumn: Column = { const oneLineQueryTextColumn: Column = { name: TOP_QUERIES_COLUMNS_IDS.OneLineQueryText, header: TOP_QUERIES_COLUMNS_TITLES.OneLineQueryText, - render: ({row}) => {row.QueryText?.toString() || ''}, + render: ({row}) => ( + + ), sortable: false, width: 500, }; diff --git a/src/containers/Tenant/Info/View/View.tsx b/src/containers/Tenant/Info/View/View.tsx index 14cc06d3e8..ff1e74d834 100644 --- a/src/containers/Tenant/Info/View/View.tsx +++ b/src/containers/Tenant/Info/View/View.tsx @@ -1,7 +1,7 @@ import type {DefinitionListItem} from '@gravity-ui/components'; +import {YDBSyntaxHighlighter} from '../../../../components/SyntaxHighlighter/YDBSyntaxHighlighter'; 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'; @@ -13,7 +13,7 @@ const prepareViewItems = (data: TEvDescribeSchemeResult): DefinitionListItem[] = { name: i18n('view.query-text'), copyText: queryText, - content: queryText ? {queryText} : null, + content: queryText ? : null, }, ]; }; diff --git a/tests/suites/tenant/queryHistory/models/QueriesHistoryTable.ts b/tests/suites/tenant/queryHistory/models/QueriesHistoryTable.ts index cde7af3bc4..aad1c5187d 100644 --- a/tests/suites/tenant/queryHistory/models/QueriesHistoryTable.ts +++ b/tests/suites/tenant/queryHistory/models/QueriesHistoryTable.ts @@ -22,7 +22,7 @@ export class QueriesHistoryTable { async getQueryRow(query: string) { return this.table.locator('.ydb-queries-history__table-row', { - has: this.page.locator('.yql-highlighter', {hasText: query}), + has: this.page.locator('.ydb-syntax-highlighter', {hasText: query}), }); } @@ -33,7 +33,7 @@ export class QueriesHistoryTable { async getQueryText(index: number) { const row = this.table.locator('.ydb-queries-history__table-row').nth(index); - return row.locator('.yql-highlighter').innerText(); + return row.locator('.ydb-syntax-highlighter').innerText(); } async isVisible() {