mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Traces: Fixed missing CopyButton on KeyValueTables and overlapping of panels (#49271)
* rewrote `CopyIcon` to an functional component - fixed missing `CopyIcon` on `KeyValuesTable` * added fixed height of `30px` to `KeyValuesTable` to fix overlapping * removed unused CopyIcon snapshot * KeyValuesTable: moved `30px` height from `tr` to `td` to fix vertical alignment
This commit is contained in:
@@ -110,9 +110,6 @@ exports[`no enzyme tests`] = {
|
|||||||
"packages/jaeger-ui-components/src/TraceTimelineViewer/index.test.js:381298544": [
|
"packages/jaeger-ui-components/src/TraceTimelineViewer/index.test.js:381298544": [
|
||||||
[14, 19, 13, "RegExp match", "2409514259"]
|
[14, 19, 13, "RegExp match", "2409514259"]
|
||||||
],
|
],
|
||||||
"packages/jaeger-ui-components/src/common/CopyIcon.test.js:187212136": [
|
|
||||||
[15, 19, 13, "RegExp match", "2409514259"]
|
|
||||||
],
|
|
||||||
"packages/jaeger-ui-components/src/common/NewWindowIcon.test.js:1750458349": [
|
"packages/jaeger-ui-components/src/common/NewWindowIcon.test.js:1750458349": [
|
||||||
[14, 19, 13, "RegExp match", "2409514259"]
|
[14, 19, 13, "RegExp match", "2409514259"]
|
||||||
],
|
],
|
||||||
|
@@ -46,6 +46,7 @@ export const getStyles = (theme: GrafanaTheme2) => {
|
|||||||
label: row;
|
label: row;
|
||||||
& > td {
|
& > td {
|
||||||
padding: 0rem 0.5rem;
|
padding: 0rem 0.5rem;
|
||||||
|
height: 30px;
|
||||||
}
|
}
|
||||||
&:nth-child(2n) > td {
|
&:nth-child(2n) > td {
|
||||||
background: ${autoColor(theme, '#f5f5f5')};
|
background: ${autoColor(theme, '#f5f5f5')};
|
||||||
|
@@ -12,12 +12,10 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
import { render, screen } from '@testing-library/react';
|
||||||
import * as copy from 'copy-to-clipboard';
|
import * as copy from 'copy-to-clipboard';
|
||||||
import { shallow } from 'enzyme';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { Button, Tooltip } from '@grafana/ui';
|
|
||||||
|
|
||||||
import CopyIcon from './CopyIcon';
|
import CopyIcon from './CopyIcon';
|
||||||
|
|
||||||
jest.mock('copy-to-clipboard');
|
jest.mock('copy-to-clipboard');
|
||||||
@@ -29,7 +27,6 @@ describe('<CopyIcon />', () => {
|
|||||||
tooltipTitle: 'tooltipTitleValue',
|
tooltipTitle: 'tooltipTitleValue',
|
||||||
};
|
};
|
||||||
let copySpy;
|
let copySpy;
|
||||||
let wrapper;
|
|
||||||
|
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
copySpy = jest.spyOn(copy, 'default');
|
copySpy = jest.spyOn(copy, 'default');
|
||||||
@@ -37,24 +34,18 @@ describe('<CopyIcon />', () => {
|
|||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
copySpy.mockReset();
|
copySpy.mockReset();
|
||||||
wrapper = shallow(<CopyIcon {...props} />);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders as expected', () => {
|
it('renders as expected', () => {
|
||||||
expect(wrapper).toMatchSnapshot();
|
expect(() => render(<CopyIcon {...props} />)).not.toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('updates state and copies when clicked', () => {
|
it('copies when clicked', () => {
|
||||||
expect(wrapper.state().hasCopied).toBe(false);
|
render(<CopyIcon {...props} />);
|
||||||
expect(copySpy).not.toHaveBeenCalled();
|
|
||||||
|
const button = screen.getByRole('button');
|
||||||
|
button.click();
|
||||||
|
|
||||||
wrapper.find(Button).simulate('click');
|
|
||||||
expect(wrapper.state().hasCopied).toBe(true);
|
|
||||||
expect(copySpy).toHaveBeenCalledWith(props.copyText);
|
expect(copySpy).toHaveBeenCalledWith(props.copyText);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('persists state when tooltip opens', () => {
|
|
||||||
wrapper.setState({ hasCopied: true });
|
|
||||||
expect(wrapper.state().hasCopied).toBe(true);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
@@ -15,11 +15,11 @@
|
|||||||
import { css } from '@emotion/css';
|
import { css } from '@emotion/css';
|
||||||
import cx from 'classnames';
|
import cx from 'classnames';
|
||||||
import copy from 'copy-to-clipboard';
|
import copy from 'copy-to-clipboard';
|
||||||
import * as React from 'react';
|
import React, { useState } from 'react';
|
||||||
|
|
||||||
import { Button, IconName, stylesFactory, Tooltip } from '@grafana/ui';
|
import { Button, IconName, Tooltip, useStyles2 } from '@grafana/ui';
|
||||||
|
|
||||||
const getStyles = stylesFactory(() => {
|
const getStyles = () => {
|
||||||
return {
|
return {
|
||||||
CopyIcon: css`
|
CopyIcon: css`
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
@@ -27,14 +27,13 @@ const getStyles = stylesFactory(() => {
|
|||||||
color: inherit;
|
color: inherit;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
padding: 0px;
|
|
||||||
&:focus {
|
&:focus {
|
||||||
background-color: rgba(255, 255, 255, 0.25);
|
background-color: rgba(255, 255, 255, 0.25);
|
||||||
color: inherit;
|
color: inherit;
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
};
|
};
|
||||||
});
|
};
|
||||||
|
|
||||||
type PropsType = {
|
type PropsType = {
|
||||||
className?: string;
|
className?: string;
|
||||||
@@ -43,46 +42,24 @@ type PropsType = {
|
|||||||
tooltipTitle: string;
|
tooltipTitle: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
type StateType = {
|
export default function CopyIcon(props: PropsType) {
|
||||||
hasCopied: boolean;
|
const styles = useStyles2(getStyles);
|
||||||
};
|
|
||||||
|
|
||||||
export default class CopyIcon extends React.PureComponent<PropsType, StateType> {
|
const [hasCopied, setHasCopied] = useState(false);
|
||||||
static defaultProps: Partial<PropsType> = {
|
|
||||||
className: undefined,
|
const handleClick = () => {
|
||||||
icon: 'copy',
|
copy(props.copyText);
|
||||||
|
setHasCopied(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
state = {
|
return (
|
||||||
hasCopied: false,
|
<Tooltip content={hasCopied ? 'Copied' : props.tooltipTitle}>
|
||||||
};
|
<Button className={cx(styles.CopyIcon)} type="button" icon={props.icon} onClick={handleClick} />
|
||||||
|
</Tooltip>
|
||||||
handleClick = () => {
|
);
|
||||||
this.setState({
|
|
||||||
hasCopied: true,
|
|
||||||
});
|
|
||||||
copy(this.props.copyText);
|
|
||||||
};
|
|
||||||
|
|
||||||
handleTooltipVisibilityChange = (visible: boolean) => {
|
|
||||||
if (!visible && this.state.hasCopied) {
|
|
||||||
this.setState({
|
|
||||||
hasCopied: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const styles = getStyles();
|
|
||||||
return (
|
|
||||||
<Tooltip content={this.state.hasCopied ? 'Copied' : this.props.tooltipTitle}>
|
|
||||||
<Button
|
|
||||||
className={cx(styles.CopyIcon, this.props.className)}
|
|
||||||
type="button"
|
|
||||||
icon={this.props.icon}
|
|
||||||
onClick={this.handleClick}
|
|
||||||
/>
|
|
||||||
</Tooltip>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CopyIcon.defaultProps = {
|
||||||
|
icon: 'copy',
|
||||||
|
className: undefined,
|
||||||
|
};
|
||||||
|
@@ -1,14 +0,0 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
||||||
|
|
||||||
exports[`<CopyIcon /> renders as expected 1`] = `
|
|
||||||
<Tooltip
|
|
||||||
content="tooltipTitleValue"
|
|
||||||
>
|
|
||||||
<Button
|
|
||||||
className="css-oqwzau classNameValue"
|
|
||||||
icon="copy"
|
|
||||||
onClick={[Function]}
|
|
||||||
type="button"
|
|
||||||
/>
|
|
||||||
</Tooltip>
|
|
||||||
`;
|
|
Reference in New Issue
Block a user