import React, { useState, useCallback } from 'react'; import { Icon, renderOrCallToRender, stylesFactory, useTheme } from '@grafana/ui'; import { GrafanaTheme } from '@grafana/data'; import { css, cx } from '@emotion/css'; import { useUpdateEffect } from 'react-use'; import { Draggable } from 'react-beautiful-dnd'; interface QueryOperationRowProps { index: number; id: string; title?: string; headerElement?: QueryOperationRowRenderProp; actions?: QueryOperationRowRenderProp; onOpen?: () => void; onClose?: () => void; children: React.ReactNode; isOpen?: boolean; draggable?: boolean; disabled?: boolean; } export type QueryOperationRowRenderProp = ((props: QueryOperationRowRenderProps) => React.ReactNode) | React.ReactNode; export interface QueryOperationRowRenderProps { isOpen: boolean; onOpen: () => void; onClose: () => void; } export const QueryOperationRow: React.FC = ({ children, actions, title, headerElement, onClose, onOpen, isOpen, disabled, draggable, index, id, }: QueryOperationRowProps) => { const [isContentVisible, setIsContentVisible] = useState(isOpen !== undefined ? isOpen : true); const theme = useTheme(); const styles = getQueryOperationRowStyles(theme); const onRowToggle = useCallback(() => { setIsContentVisible(!isContentVisible); }, [isContentVisible, setIsContentVisible]); useUpdateEffect(() => { if (isContentVisible) { if (onOpen) { onOpen(); } } else { if (onClose) { onClose(); } } }, [isContentVisible]); 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 = (
{title && (
{titleElement}
)} {headerElementRendered}
{actionsElement} {draggable && ( )}
); if (draggable) { return ( {(provided) => { return ( <>
{rowHeader}
{isContentVisible &&
{children}
}
); }}
); } return (
{rowHeader} {isContentVisible &&
{children}
}
); }; const getQueryOperationRowStyles = stylesFactory((theme: GrafanaTheme) => { return { 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}; `, }; }); QueryOperationRow.displayName = 'QueryOperationRow';