diff --git a/frontend/src/metabase/query_builder/components/AggregationPopover.jsx b/frontend/src/metabase/query_builder/components/AggregationPopover/AggregationPopover.jsx similarity index 90% rename from frontend/src/metabase/query_builder/components/AggregationPopover.jsx rename to frontend/src/metabase/query_builder/components/AggregationPopover/AggregationPopover.jsx index b38536e34835961d7315b1d27221ba8d294a2197..3f5df91d6e76cf4d4d13cbd2764a98351bcb664c 100644 --- a/frontend/src/metabase/query_builder/components/AggregationPopover.jsx +++ b/frontend/src/metabase/query_builder/components/AggregationPopover/AggregationPopover.jsx @@ -3,20 +3,21 @@ import React, { Component } from "react"; import ReactDOM from "react-dom"; import PropTypes from "prop-types"; import { t } from "ttag"; +import _ from "underscore"; import Icon from "metabase/components/Icon"; import Tooltip from "metabase/components/Tooltip"; import AccordionList from "metabase/core/components/AccordionList"; -import FieldList from "./FieldList"; -import QueryDefinitionTooltip from "./QueryDefinitionTooltip"; -import ExpressionPopover from "./ExpressionPopover"; +import FieldList from "../FieldList"; +import QueryDefinitionTooltip from "../QueryDefinitionTooltip"; +import ExpressionPopover from "../ExpressionPopover"; import * as AGGREGATION from "metabase/lib/query/aggregation"; import Aggregation from "metabase-lib/lib/queries/structured/Aggregation"; -import _ from "underscore"; +import { ExpressionPopoverRoot } from "./AggregationPopover.styled"; const COMMON_SECTION_NAME = t`Common Metrics`; const BASIC_SECTION_NAME = t`Basic Metrics`; @@ -301,31 +302,33 @@ export default class AggregationPopover extends Component { if (editingAggregation) { return ( - <ExpressionPopover - title={CUSTOM_SECTION_NAME} - query={query} - expression={aggregation} - startRule="aggregation" - onChange={parsedExpression => - this.setState({ - aggregation: AGGREGATION.setContent( - this.state.aggregation, - parsedExpression, - ), - error: null, - }) - } - onBack={this.onClearAggregation} - onDone={() => this.commitAggregation(this.state.aggregation)} - name={AGGREGATION.getName(this.state.aggregation)} - onChangeName={name => - this.setState({ - aggregation: name - ? AGGREGATION.setName(aggregation, name) - : aggregation, - }) - } - /> + <ExpressionPopoverRoot> + <ExpressionPopover + title={CUSTOM_SECTION_NAME} + query={query} + expression={aggregation} + startRule="aggregation" + onChange={parsedExpression => + this.setState({ + aggregation: AGGREGATION.setContent( + this.state.aggregation, + parsedExpression, + ), + error: null, + }) + } + onBack={this.onClearAggregation} + onDone={() => this.commitAggregation(this.state.aggregation)} + name={AGGREGATION.getName(this.state.aggregation)} + onChangeName={name => + this.setState({ + aggregation: name + ? AGGREGATION.setName(aggregation, name) + : aggregation, + }) + } + /> + </ExpressionPopoverRoot> ); } else if (choosingField) { const [agg, fieldId] = aggregation; diff --git a/frontend/src/metabase/query_builder/components/AggregationPopover/AggregationPopover.styled.tsx b/frontend/src/metabase/query_builder/components/AggregationPopover/AggregationPopover.styled.tsx new file mode 100644 index 0000000000000000000000000000000000000000..b402f676833d5291115819ed24ea1ff954dad62d --- /dev/null +++ b/frontend/src/metabase/query_builder/components/AggregationPopover/AggregationPopover.styled.tsx @@ -0,0 +1,5 @@ +import styled from "@emotion/styled"; + +export const ExpressionPopoverRoot = styled.div` + width: 350px; +`; diff --git a/frontend/src/metabase/query_builder/components/AggregationPopover/index.ts b/frontend/src/metabase/query_builder/components/AggregationPopover/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..3d84e652452473e8abdb0dd6986e824aae24b5ac --- /dev/null +++ b/frontend/src/metabase/query_builder/components/AggregationPopover/index.ts @@ -0,0 +1 @@ +export { default } from "./AggregationPopover"; diff --git a/frontend/src/metabase/query_builder/components/AggregationWidget.jsx b/frontend/src/metabase/query_builder/components/AggregationWidget.jsx index d8c0c7a2fb3caac9ebeda738c9cd74ae9931904e..fa1ada0adf737916d29dbbd675b6c6e2a5821a80 100644 --- a/frontend/src/metabase/query_builder/components/AggregationWidget.jsx +++ b/frontend/src/metabase/query_builder/components/AggregationWidget.jsx @@ -5,7 +5,7 @@ import { t } from "ttag"; import Clearable from "./Clearable"; import AggregationPopover from "./AggregationPopover"; -import TippyPopover from "metabase/components/Popover/TippyPopover"; +import ControlledPopoverWithTrigger from "metabase/components/PopoverWithTrigger/ControlledPopoverWithTrigger"; // NOTE: lots of duplication between AggregationWidget and BreakoutWidget @@ -63,12 +63,20 @@ export default class AggregationWidget extends React.Component { ) : ( children ); - const popover = ( - <TippyPopover + + if (!trigger) { + return null; + } + + return ( + <ControlledPopoverWithTrigger + disableContentSandbox placement="bottom-start" visible={this.state.isOpen} onClose={this.handleClose} - content={ + onOpen={this.handleOpen} + triggerContent={trigger} + popoverContent={ <AggregationPopover query={query} aggregation={aggregation} @@ -77,15 +85,9 @@ export default class AggregationWidget extends React.Component { /> } > - <div>{trigger}</div> - </TippyPopover> + {trigger} + </ControlledPopoverWithTrigger> ); - - if (trigger) { - return <div onClick={this.handleOpen}>{popover}</div>; - } else { - return null; - } } } diff --git a/frontend/test/metabase/scenarios/admin/datamodel/metrics.cy.spec.js b/frontend/test/metabase/scenarios/admin/datamodel/metrics.cy.spec.js index a08c215c3f414cabf3dc3fd61675d752e695e035..f591e43532a1829f6f6d55f04e676c188fb6009a 100644 --- a/frontend/test/metabase/scenarios/admin/datamodel/metrics.cy.spec.js +++ b/frontend/test/metabase/scenarios/admin/datamodel/metrics.cy.spec.js @@ -93,7 +93,7 @@ describe("scenarios > admin > datamodel > metrics", () => { cy.findByText("Learn how to create metrics"); }); - it.skip("custom expression aggregation should work in metrics (metabase#22700)", () => { + it("custom expression aggregation should work in metrics (metabase#22700)", () => { cy.intercept("POST", "/api/dataset").as("dataset"); const customExpression = "Count / Distinct([Product ID])";