diff --git a/.betterer.results b/.betterer.results
index aaf775e4ec8..8a00f51b03b 100644
--- a/.betterer.results
+++ b/.betterer.results
@@ -104,7 +104,7 @@ exports[`no enzyme tests`] = {
"public/app/core/components/QueryOperationRow/QueryOperationAction.test.tsx:3032694716": [
[0, 19, 13, "RegExp match", "2409514259"]
],
- "public/app/core/components/QueryOperationRow/QueryOperationRow.test.tsx:2026575657": [
+ "public/app/core/components/QueryOperationRow/QueryOperationRow.test.tsx:3743889097": [
[0, 26, 13, "RegExp match", "2409514259"]
],
"public/app/core/components/Select/MetricSelect.test.tsx:3351544014": [
diff --git a/public/app/core/components/QueryOperationRow/QueryOperationRow.test.tsx b/public/app/core/components/QueryOperationRow/QueryOperationRow.test.tsx
index afcccbf93fb..b046539d99f 100644
--- a/public/app/core/components/QueryOperationRow/QueryOperationRow.test.tsx
+++ b/public/app/core/components/QueryOperationRow/QueryOperationRow.test.tsx
@@ -60,7 +60,7 @@ describe('QueryOperationRow', () => {
describe('headerElement rendering', () => {
it('should render headerElement provided as element', () => {
const title =
Test
;
- const wrapper = shallow(
+ const wrapper = mount(
Test
@@ -72,7 +72,7 @@ describe('QueryOperationRow', () => {
it('should render headerElement provided as function', () => {
const title = () => Test
;
- const wrapper = shallow(
+ const wrapper = mount(
Test
@@ -101,7 +101,7 @@ describe('QueryOperationRow', () => {
describe('actions rendering', () => {
it('should render actions provided as element', () => {
const actions = Test
;
- const wrapper = shallow(
+ const wrapper = mount(
Test
@@ -112,7 +112,7 @@ describe('QueryOperationRow', () => {
});
it('should render actions provided as function', () => {
const actions = () => Test
;
- const wrapper = shallow(
+ const wrapper = mount(
Test
diff --git a/public/app/core/components/QueryOperationRow/QueryOperationRow.tsx b/public/app/core/components/QueryOperationRow/QueryOperationRow.tsx
index 85f32fdfa08..331e189e976 100644
--- a/public/app/core/components/QueryOperationRow/QueryOperationRow.tsx
+++ b/public/app/core/components/QueryOperationRow/QueryOperationRow.tsx
@@ -1,11 +1,13 @@
-import { css, cx } from '@emotion/css';
+import { css } from '@emotion/css';
import React, { useCallback, useState } from 'react';
import { Draggable } from 'react-beautiful-dnd';
import { useUpdateEffect } from 'react-use';
import { GrafanaTheme } from '@grafana/data';
import { reportInteraction } from '@grafana/runtime';
-import { Icon, ReactUtils, stylesFactory, useTheme } from '@grafana/ui';
+import { ReactUtils, stylesFactory, useTheme } from '@grafana/ui';
+
+import { QueryOperationRowHeader } from './QueryOperationRowHeader';
interface QueryOperationRowProps {
index: number;
@@ -93,41 +95,25 @@ export const QueryOperationRow: React.FC = ({
const actionsElement = actions && ReactUtils.renderOrCallToRender(actions, renderPropArgs);
const headerElementRendered = headerElement && ReactUtils.renderOrCallToRender(headerElement, renderPropArgs);
- const rowHeader = (
-
-
-
- {title && (
-
- )}
- {headerElementRendered}
-
-
-
- {actionsElement}
- {draggable && (
-
- )}
-
-
- );
-
if (draggable) {
return (
{(provided) => {
- const dragHandleProps = { ...provided.dragHandleProps, role: 'group' }; // replace the role="button" because it causes https://dequeuniversity.com/rules/axe/4.3/nested-interactive?application=msftAI
return (
<>
-
- {rowHeader}
+
+
{isContentVisible &&
{children}
}
@@ -140,7 +126,16 @@ export const QueryOperationRow: React.FC
= ({
return (
- {rowHeader}
+
{isContentVisible &&
{children}
}
);
@@ -151,63 +146,10 @@ const getQueryOperationRowStyles = stylesFactory((theme: GrafanaTheme) => {
wrapper: css`
margin-bottom: ${theme.spacing.md};
`,
- header: css`
- label: Header;
- padding: ${theme.spacing.xs} ${theme.spacing.sm};
- border-radius: ${theme.border.radius.sm};
- background: ${theme.colors.bg2};
- min-height: ${theme.spacing.formInputHeight}px;
- display: grid;
- grid-template-columns: minmax(100px, max-content) min-content;
- align-items: center;
- justify-content: space-between;
- white-space: nowrap;
-
- &:focus {
- outline: none;
- }
- `,
- column: css`
- label: Column;
- display: flex;
- align-items: center;
- `,
- dragIcon: css`
- cursor: grab;
- color: ${theme.colors.textWeak};
- &:hover {
- color: ${theme.colors.text};
- }
- `,
- collapseIcon: css`
- color: ${theme.colors.textWeak};
- cursor: pointer;
- &:hover {
- color: ${theme.colors.text};
- }
- `,
- titleWrapper: css`
- display: flex;
- align-items: center;
- flex-grow: 1;
- cursor: pointer;
- overflow: hidden;
- margin-right: ${theme.spacing.sm};
- `,
- title: css`
- font-weight: ${theme.typography.weight.semibold};
- color: ${theme.colors.textBlue};
- margin-left: ${theme.spacing.sm};
- overflow: hidden;
- text-overflow: ellipsis;
- `,
content: css`
margin-top: ${theme.spacing.inlineFormMargin};
margin-left: ${theme.spacing.lg};
`,
- disabled: css`
- color: ${theme.colors.textWeak};
- `,
};
});
diff --git a/public/app/core/components/QueryOperationRow/QueryOperationRowHeader.tsx b/public/app/core/components/QueryOperationRow/QueryOperationRowHeader.tsx
new file mode 100644
index 00000000000..9b71a51a226
--- /dev/null
+++ b/public/app/core/components/QueryOperationRow/QueryOperationRowHeader.tsx
@@ -0,0 +1,123 @@
+import { css, cx } from '@emotion/css';
+import React, { MouseEventHandler } from 'react';
+import { DraggableProvidedDragHandleProps } from 'react-beautiful-dnd';
+
+import { GrafanaTheme2 } from '@grafana/data';
+import { Icon, useStyles2 } from '@grafana/ui';
+
+interface QueryOperationRowHeaderProps {
+ actionsElement?: React.ReactNode;
+ disabled?: boolean;
+ draggable: boolean;
+ dragHandleProps?: DraggableProvidedDragHandleProps;
+ headerElement?: React.ReactNode;
+ isContentVisible: boolean;
+ onRowToggle: () => void;
+ reportDragMousePosition: MouseEventHandler;
+ titleElement?: React.ReactNode;
+}
+
+export const QueryOperationRowHeader: React.FC = ({
+ actionsElement,
+ disabled,
+ draggable,
+ dragHandleProps,
+ headerElement,
+ isContentVisible,
+ onRowToggle,
+ reportDragMousePosition,
+ titleElement,
+}: QueryOperationRowHeaderProps) => {
+ const styles = useStyles2(getStyles);
+
+ return (
+
+
+
+ {titleElement && (
+
+ )}
+ {headerElement}
+
+
+
+ {actionsElement}
+ {draggable && (
+
+ )}
+
+
+ );
+};
+
+const getStyles = (theme: GrafanaTheme2) => ({
+ header: css`
+ label: Header;
+ padding: ${theme.spacing(0.5, 0.5)};
+ border-radius: ${theme.shape.borderRadius(1)};
+ background: ${theme.colors.background.secondary};
+ min-height: ${theme.spacing(4)};
+ display: grid;
+ grid-template-columns: minmax(100px, max-content) min-content;
+ align-items: center;
+ justify-content: space-between;
+ white-space: nowrap;
+
+ &:focus {
+ outline: none;
+ }
+ `,
+ column: css`
+ label: Column;
+ display: flex;
+ align-items: center;
+ `,
+ dragIcon: css`
+ cursor: grab;
+ color: ${theme.colors.text.disabled};
+ margin: ${theme.spacing(0, 0.5)};
+ &:hover {
+ color: ${theme.colors.text};
+ }
+ `,
+ collapseIcon: css`
+ color: ${theme.colors.text.disabled};
+ cursor: pointer;
+ &:hover {
+ color: ${theme.colors.text};
+ }
+ `,
+ titleWrapper: css`
+ display: flex;
+ align-items: center;
+ flex-grow: 1;
+ cursor: pointer;
+ overflow: hidden;
+ margin-right: ${theme.spacing(0.5)};
+ `,
+ title: css`
+ font-weight: ${theme.typography.fontWeightBold};
+ color: ${theme.colors.text.link};
+ margin-left: ${theme.spacing(0.5)};
+ overflow: hidden;
+ text-overflow: ellipsis;
+ `,
+ disabled: css`
+ color: ${theme.colors.text.disabled};
+ `,
+});
+
+QueryOperationRowHeader.displayName = 'QueryOperationRowHeader';
diff --git a/public/app/features/transformers/editors/OrganizeFieldsTransformerEditor.tsx b/public/app/features/transformers/editors/OrganizeFieldsTransformerEditor.tsx
index 1365aaf58dc..3fc97f52fa1 100644
--- a/public/app/features/transformers/editors/OrganizeFieldsTransformerEditor.tsx
+++ b/public/app/features/transformers/editors/OrganizeFieldsTransformerEditor.tsx
@@ -131,15 +131,16 @@ const DraggableFieldName: React.FC = ({
return (
{(provided) => (
-