mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
QueryEditorRow: Ability to change query name (#29779)
* QueryEditorRow: Ability to change query name * Style tweaks * Updated UX * Fixed tests * Added validation messages * Fixed keyboard navigation * Updated tests
This commit is contained in:
@@ -32,7 +32,7 @@ describe('QueryOperationRow', () => {
|
||||
const onOpenSpy = jest.fn();
|
||||
const onCloseSpy = jest.fn();
|
||||
const wrapper = mount(
|
||||
<QueryOperationRow onOpen={onOpenSpy} onClose={onCloseSpy} isOpen={false} id="test-id" index={0}>
|
||||
<QueryOperationRow title="title" onOpen={onOpenSpy} onClose={onCloseSpy} isOpen={false} id="test-id" index={0}>
|
||||
<div>Test</div>
|
||||
</QueryOperationRow>
|
||||
);
|
||||
@@ -56,11 +56,11 @@ describe('QueryOperationRow', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('title rendering', () => {
|
||||
it('should render title provided as element', () => {
|
||||
describe('headerElement rendering', () => {
|
||||
it('should render headerElement provided as element', () => {
|
||||
const title = <div aria-label="test title">Test</div>;
|
||||
const wrapper = shallow(
|
||||
<QueryOperationRow title={title} id="test-id" index={0}>
|
||||
<QueryOperationRow headerElement={title} id="test-id" index={0}>
|
||||
<div>Test</div>
|
||||
</QueryOperationRow>
|
||||
);
|
||||
@@ -68,10 +68,11 @@ describe('QueryOperationRow', () => {
|
||||
const titleEl = wrapper.find({ 'aria-label': 'test title' });
|
||||
expect(titleEl).toHaveLength(1);
|
||||
});
|
||||
it('should render title provided as function', () => {
|
||||
|
||||
it('should render headerElement provided as function', () => {
|
||||
const title = () => <div aria-label="test title">Test</div>;
|
||||
const wrapper = shallow(
|
||||
<QueryOperationRow title={title} id="test-id" index={0}>
|
||||
<QueryOperationRow headerElement={title} id="test-id" index={0}>
|
||||
<div>Test</div>
|
||||
</QueryOperationRow>
|
||||
);
|
||||
@@ -80,14 +81,14 @@ describe('QueryOperationRow', () => {
|
||||
expect(titleEl).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('should expose api to title rendered as function', () => {
|
||||
it('should expose api to headerElement rendered as function', () => {
|
||||
const propsSpy = jest.fn();
|
||||
const title = (props: any) => {
|
||||
propsSpy(props);
|
||||
return <div aria-label="test title">Test</div>;
|
||||
};
|
||||
shallow(
|
||||
<QueryOperationRow title={title} id="test-id" index={0}>
|
||||
<QueryOperationRow headerElement={title} id="test-id" index={0}>
|
||||
<div>Test</div>
|
||||
</QueryOperationRow>
|
||||
);
|
||||
@@ -132,9 +133,7 @@ describe('QueryOperationRow', () => {
|
||||
</QueryOperationRow>
|
||||
);
|
||||
|
||||
expect(Object.keys(propsSpy.mock.calls[0][0])).toContainEqual('isOpen');
|
||||
expect(Object.keys(propsSpy.mock.calls[0][0])).toContainEqual('openRow');
|
||||
expect(Object.keys(propsSpy.mock.calls[0][0])).toContainEqual('closeRow');
|
||||
expect(Object.keys(propsSpy.mock.calls[0][0])).toEqual(['isOpen', 'onOpen', 'onClose']);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -8,11 +8,9 @@ import { Draggable } from 'react-beautiful-dnd';
|
||||
interface QueryOperationRowProps {
|
||||
index: number;
|
||||
id: string;
|
||||
title?: ((props: { isOpen: boolean }) => React.ReactNode) | React.ReactNode;
|
||||
headerElement?: React.ReactNode;
|
||||
actions?:
|
||||
| ((props: { isOpen: boolean; openRow: () => void; closeRow: () => void }) => React.ReactNode)
|
||||
| React.ReactNode;
|
||||
title?: string;
|
||||
headerElement?: QueryOperationRowRenderProp;
|
||||
actions?: QueryOperationRowRenderProp;
|
||||
onOpen?: () => void;
|
||||
onClose?: () => void;
|
||||
children: React.ReactNode;
|
||||
@@ -20,6 +18,14 @@ interface QueryOperationRowProps {
|
||||
draggable?: boolean;
|
||||
}
|
||||
|
||||
export type QueryOperationRowRenderProp = ((props: QueryOperationRowRenderProps) => React.ReactNode) | React.ReactNode;
|
||||
|
||||
export interface QueryOperationRowRenderProps {
|
||||
isOpen: boolean;
|
||||
onOpen: () => void;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
export const QueryOperationRow: React.FC<QueryOperationRowProps> = ({
|
||||
children,
|
||||
actions,
|
||||
@@ -51,26 +57,33 @@ export const QueryOperationRow: React.FC<QueryOperationRowProps> = ({
|
||||
}
|
||||
}, [isContentVisible]);
|
||||
|
||||
const titleElement = title && renderOrCallToRender(title, { isOpen: isContentVisible });
|
||||
const actionsElement =
|
||||
actions &&
|
||||
renderOrCallToRender(actions, {
|
||||
isOpen: isContentVisible,
|
||||
openRow: () => {
|
||||
setIsContentVisible(true);
|
||||
},
|
||||
closeRow: () => {
|
||||
setIsContentVisible(false);
|
||||
},
|
||||
});
|
||||
const renderPropArgs: QueryOperationRowRenderProps = {
|
||||
isOpen: isContentVisible,
|
||||
onOpen: () => {
|
||||
setIsContentVisible(true);
|
||||
},
|
||||
onClose: () => {
|
||||
setIsContentVisible(false);
|
||||
},
|
||||
};
|
||||
|
||||
const titleElement = title && renderOrCallToRender(title, renderPropArgs);
|
||||
const actionsElement = actions && renderOrCallToRender(actions, renderPropArgs);
|
||||
const headerElementRendered = headerElement && renderOrCallToRender(headerElement, renderPropArgs);
|
||||
|
||||
const rowHeader = (
|
||||
<div className={styles.header}>
|
||||
<div className={styles.titleWrapper} onClick={onRowToggle} aria-label="Query operation row title">
|
||||
<Icon name={isContentVisible ? 'angle-down' : 'angle-right'} className={styles.collapseIcon} />
|
||||
{title && <div className={styles.title}>{titleElement}</div>}
|
||||
{headerElement}
|
||||
</div>
|
||||
<Icon
|
||||
name={isContentVisible ? 'angle-down' : 'angle-right'}
|
||||
className={styles.collapseIcon}
|
||||
onClick={onRowToggle}
|
||||
/>
|
||||
{title && (
|
||||
<div className={styles.titleWrapper} onClick={onRowToggle} aria-label="Query operation row title">
|
||||
<div className={styles.title}>{titleElement}</div>
|
||||
</div>
|
||||
)}
|
||||
{headerElementRendered}
|
||||
{actions && <div>{actionsElement}</div>}
|
||||
{draggable && (
|
||||
<Icon title="Drag and drop to reorder" name="draggabledots" size="lg" className={styles.dragIcon} />
|
||||
@@ -126,6 +139,7 @@ const getQueryOperationRowStyles = stylesFactory((theme: GrafanaTheme) => {
|
||||
`,
|
||||
collapseIcon: css`
|
||||
color: ${theme.colors.textWeak};
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
color: ${theme.colors.text};
|
||||
}
|
||||
|
Reference in New Issue
Block a user