Explore: Fix incorrect interpolation of table title (#80227)

pull/80608/head
Uladzimir Dzmitračkoŭ 1 year ago committed by GitHub
parent 127decee1e
commit 313c43749c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 10
      packages/grafana-ui/src/components/PanelChrome/PanelChrome.tsx
  2. 26
      public/app/core/internationalization/index.test.tsx
  3. 2
      public/app/core/internationalization/index.tsx
  4. 8
      public/app/features/explore/Table/TableContainer.test.tsx
  5. 8
      public/app/features/explore/Table/TableContainer.tsx

@ -25,7 +25,7 @@ export type PanelChromeProps = (AutoSize | FixedDimensions) & (Collapsible | Hov
interface BaseProps { interface BaseProps {
padding?: PanelPadding; padding?: PanelPadding;
title?: string; title?: string | React.ReactElement;
description?: string | (() => string); description?: string | (() => string);
titleItems?: ReactNode; titleItems?: ReactNode;
menu?: ReactElement | (() => ReactElement); menu?: ReactElement | (() => ReactElement);
@ -161,13 +161,13 @@ export function PanelChrome({
actions = leftItems; actions = leftItems;
} }
const testid = title ? selectors.components.Panels.Panel.title(title) : 'Panel'; const testid = typeof title === 'string' ? selectors.components.Panels.Panel.title(title) : 'Panel';
const headerContent = ( const headerContent = (
<> <>
{/* Non collapsible title */} {/* Non collapsible title */}
{!collapsible && title && ( {!collapsible && title && (
<h6 title={title} className={styles.title}> <h6 title={typeof title === 'string' ? title : undefined} className={styles.title}>
{title} {title}
</h6> </h6>
)} )}
@ -246,7 +246,7 @@ export function PanelChrome({
<> <>
<HoverWidget <HoverWidget
menu={menu} menu={menu}
title={title} title={typeof title === 'string' ? title : undefined}
offset={hoverHeaderOffset} offset={hoverHeaderOffset}
dragClass={dragClass} dragClass={dragClass}
onOpenMenu={onOpenMenu} onOpenMenu={onOpenMenu}
@ -275,7 +275,7 @@ export function PanelChrome({
{menu && ( {menu && (
<PanelMenu <PanelMenu
menu={menu} menu={menu}
title={title} title={typeof title === 'string' ? title : undefined}
placement="bottom-end" placement="bottom-end"
menuButtonClass={cx(styles.menuItem, dragClassCancel, showOnHoverClass)} menuButtonClass={cx(styles.menuItem, dragClassCancel, showOnHoverClass)}
onOpenMenu={onOpenMenu} onOpenMenu={onOpenMenu}

@ -0,0 +1,26 @@
import { render } from '@testing-library/react';
import React from 'react';
import { Trans } from './index';
describe('internationalization', () => {
describe('Trans component', () => {
it('should interpolate strings without escaping dangerous characters', () => {
const name = '<script></script>';
const { getByText } = render(<Trans i18nKey="explore.table.title-with-name">Table - {{ name }}</Trans>);
expect(getByText('Table - <script></script>')).toBeInTheDocument();
});
it('should escape dangerous characters when shouldUnescape is false', () => {
const name = '<script></script>';
const { getByText } = render(
<Trans i18nKey="explore.table.title-with-name" shouldUnescape={false}>
Table - {{ name }}
</Trans>
);
expect(getByText('Table - &lt;script&gt;&lt;&#x2F;script&gt;')).toBeInTheDocument();
});
});
});

@ -56,7 +56,7 @@ export function changeLanguage(locale: string) {
} }
export const Trans: typeof I18NextTrans = (props) => { export const Trans: typeof I18NextTrans = (props) => {
return <I18NextTrans {...props} />; return <I18NextTrans shouldUnescape {...props} />;
}; };
// Reassign t() so i18next-parser doesn't warn on dynamic key, and we can have 'failOnWarnings' enabled // Reassign t() so i18next-parser doesn't warn on dynamic key, and we can have 'failOnWarnings' enabled

@ -105,7 +105,15 @@ describe('TableContainerWithTheme', () => {
{ time: '2020-12-31 21:00:00', text: 'test_string_4' }, { time: '2020-12-31 21:00:00', text: 'test_string_4' },
]); ]);
}); });
it('should render table title with Prometheus query', () => {
const dataFrames = [{ ...dataFrame, name: 'metric{label="value"}' }];
const tableProps = { ...defaultProps, tableResult: dataFrames };
render(<TableContainerWithTheme {...tableProps} />);
expect(screen.getByText('Table - metric{label="value"}')).toBeInTheDocument();
});
}); });
describe('With multiple main frames', () => { describe('With multiple main frames', () => {
it('should render multiple tables for multiple frames', () => { it('should render multiple tables for multiple frames', () => {
const dataFrames = [dataFrame, dataFrame]; const dataFrames = [dataFrame, dataFrame];

@ -7,7 +7,7 @@ import { getTemplateSrv } from '@grafana/runtime';
import { TimeZone } from '@grafana/schema'; import { TimeZone } from '@grafana/schema';
import { Table, AdHocFilterItem, PanelChrome, withTheme2, Themeable2 } from '@grafana/ui'; import { Table, AdHocFilterItem, PanelChrome, withTheme2, Themeable2 } from '@grafana/ui';
import { config } from 'app/core/config'; import { config } from 'app/core/config';
import { t } from 'app/core/internationalization'; import { t, Trans } from 'app/core/internationalization';
import { import {
hasDeprecatedParentRowIndex, hasDeprecatedParentRowIndex,
migrateFromParentRowIndexToNestedFrames, migrateFromParentRowIndexToNestedFrames,
@ -59,7 +59,11 @@ export class TableContainer extends PureComponent<Props> {
name = data.refId || `${i}`; name = data.refId || `${i}`;
} }
return name ? t('explore.table.title-with-name', 'Table - {{name}}', { name }) : t('explore.table.title', 'Table'); return name ? (
<Trans i18nKey="explore.table.title-with-name">Table - {{ name }}</Trans>
) : (
t('explore.table.title', 'Table')
);
} }
render() { render() {

Loading…
Cancel
Save