From 1c0bb298080670ad69b12864999cdd24655fbeea Mon Sep 17 00:00:00 2001 From: Ryan Laurie <30528226+iethree@users.noreply.github.com> Date: Tue, 24 May 2022 16:55:19 -0600 Subject: [PATCH] Support Segments in Bulk Filter Modal (#22899) * support for segment filters in modal --- .../lib/queries/StructuredQuery.ts | 42 ++++++- .../core/components/Select/Select.jsx | 6 +- frontend/src/metabase/lib/query/filter.js | 4 + frontend/src/metabase/lib/query/query.js | 2 + .../modals/BulkFilterList/BulkFilterList.tsx | 61 +++++++++- .../BulkFilterModal.styled.tsx | 7 +- .../BulkFilterModal/BulkFilterModal.tsx | 15 ++- .../BulkFilterSelect.styled.tsx | 5 + .../BulkFilterSelect/BulkFilterSelect.tsx | 79 +++++++++++- .../filters/modals/BulkFilterSelect/index.ts | 2 +- .../scenarios/filters/filter-bulk.cy.spec.js | 113 +++++++++++++++++- 11 files changed, 313 insertions(+), 23 deletions(-) diff --git a/frontend/src/metabase-lib/lib/queries/StructuredQuery.ts b/frontend/src/metabase-lib/lib/queries/StructuredQuery.ts index 202f5e030b6..3b8d9e2a8f7 100644 --- a/frontend/src/metabase-lib/lib/queries/StructuredQuery.ts +++ b/frontend/src/metabase-lib/lib/queries/StructuredQuery.ts @@ -33,6 +33,7 @@ import Dimension, { ExpressionDimension, AggregationDimension, } from "metabase-lib/lib/Dimension"; +import { isSegment } from "metabase/lib/query/filter"; import DimensionOptions from "metabase-lib/lib/DimensionOptions"; import Segment from "../metadata/Segment"; import { DatabaseEngine, DatabaseId } from "metabase-types/types/Database"; @@ -50,8 +51,10 @@ import Table from "../metadata/Table"; import Field from "../metadata/Field"; import { TYPE } from "metabase/lib/types"; import { fieldRefForColumn } from "metabase/lib/dataset"; + type DimensionFilter = (dimension: Dimension) => boolean; type FieldFilter = (filter: Field) => boolean; + export const STRUCTURED_QUERY_TEMPLATE = { database: null, type: "query", @@ -63,13 +66,27 @@ export const STRUCTURED_QUERY_TEMPLATE = { export interface FilterSection { name: string; icon: string; - items: DimensionOption[]; + items: (DimensionOption | SegmentOption)[]; } export interface DimensionOption { dimension: Dimension; } +// type guards for determining data types +export const isSegmentOption = (content: any): content is SegmentOption => + content?.filter && isSegment(content.filter); + +export const isDimensionOption = (content: any): content is DimensionOption => + !!content?.dimension; + +export interface SegmentOption { + name: string; + filter: ["segment", number]; + icon: string; + query: StructuredQuery; +} + /** * A wrapper around an MBQL (`query` type @type {DatasetQuery}) object */ @@ -849,10 +866,11 @@ class StructuredQueryInner extends AtomicQuery { filterFieldOptionSections( filter?: (Filter | FilterWrapper) | null | undefined, { includeSegments = true } = {}, + includeAppliedSegments = false, ) { const filterDimensionOptions = this.filterDimensionOptions(); const filterSegmentOptions = includeSegments - ? this.filterSegmentOptions(filter) + ? this.filterSegmentOptions(filter, includeAppliedSegments) : []; return filterDimensionOptions.sections({ extraItems: filterSegmentOptions.map(segment => ({ @@ -867,6 +885,7 @@ class StructuredQueryInner extends AtomicQuery { topLevelFilterFieldOptionSections( filter = null, stages = 2, + includeAppliedSegments = false, ): FilterSection[] { const queries = this.queries().slice(-stages); @@ -877,7 +896,9 @@ class StructuredQueryInner extends AtomicQuery { queries.reverse(); const sections = [].concat( - ...queries.map(q => q.filterFieldOptionSections(filter)), + ...queries.map(q => + q.filterFieldOptionSections(filter, undefined, includeAppliedSegments), + ), ); // special logic to only show aggregation dimensions for post-aggregation dimensions @@ -913,7 +934,10 @@ class StructuredQueryInner extends AtomicQuery { /** * @returns @type {Segment}s that can be used as filters. */ - filterSegmentOptions(filter?: Filter | FilterWrapper): Segment[] { + filterSegmentOptions( + filter?: Filter | FilterWrapper, + includeAppliedSegments = false, + ): Segment[] { if (filter && !(filter instanceof FilterWrapper)) { filter = new FilterWrapper(filter, null, this); } @@ -922,7 +946,8 @@ class StructuredQueryInner extends AtomicQuery { return this.table().segments.filter( segment => (currentSegmentId != null && currentSegmentId === segment.id) || - (!segment.archived && !this.segments().includes(segment)), + (!segment.archived && + (includeAppliedSegments || !this.segments().includes(segment))), ); } @@ -974,6 +999,13 @@ class StructuredQueryInner extends AtomicQuery { return this._updateQuery(Q.clearFilters, arguments); } + /** + * @returns {StructuredQuery} new query with all segment filters removed + */ + clearSegments() { + return this._updateQuery(Q.clearSegments, arguments); + } + // SORTS // TODO: standardize SORT vs ORDER_BY terminology sorts(): OrderByWrapper[] { diff --git a/frontend/src/metabase/core/components/Select/Select.jsx b/frontend/src/metabase/core/components/Select/Select.jsx index cd0c9e30f64..99119eff386 100644 --- a/frontend/src/metabase/core/components/Select/Select.jsx +++ b/frontend/src/metabase/core/components/Select/Select.jsx @@ -41,6 +41,7 @@ class Select extends Component { // SelectButton props buttonProps: PropTypes.object, + buttonText: PropTypes.string, // will override selected options text // AccordianList props searchProp: PropTypes.string, @@ -136,6 +137,7 @@ class Select extends Component { value = this.itemIsSelected(option) ? values.filter(value => value !== optionValue) : [...values, optionValue]; + value.changedItem = optionValue; } else { value = optionValue; } @@ -216,7 +218,9 @@ class Select extends Component { disabled={disabled} {...buttonProps} > - {selectedNames.length > 0 + {this.props.buttonText + ? this.props.buttonText + : selectedNames.length > 0 ? selectedNames.map((name, index) => ( <span key={index}> {name} diff --git a/frontend/src/metabase/lib/query/filter.js b/frontend/src/metabase/lib/query/filter.js index 7fa3733ac1a..a9d5660b36e 100644 --- a/frontend/src/metabase/lib/query/filter.js +++ b/frontend/src/metabase/lib/query/filter.js @@ -45,6 +45,10 @@ export function removeFilter(filter, index) { export function clearFilters(filter) { return getFilterClause(clear()); } +export function clearSegments(filters) { + const newFilters = filters.filter(f => !isSegment(f)); + return getFilterClause(newFilters); +} // MISC diff --git a/frontend/src/metabase/lib/query/query.js b/frontend/src/metabase/lib/query/query.js index 85931dae778..e7e9d98ea70 100644 --- a/frontend/src/metabase/lib/query/query.js +++ b/frontend/src/metabase/lib/query/query.js @@ -52,6 +52,8 @@ export const removeFilter = (query, index) => setFilterClause(query, F.removeFilter(query.filter, index)); export const clearFilters = query => setFilterClause(query, F.clearFilters(query.filter)); +export const clearSegments = query => + setFilterClause(query, F.clearSegments(getFilters(query))); export const canAddFilter = query => F.canAddFilter(query.filter); diff --git a/frontend/src/metabase/query_builder/components/filters/modals/BulkFilterList/BulkFilterList.tsx b/frontend/src/metabase/query_builder/components/filters/modals/BulkFilterList/BulkFilterList.tsx index 791b33b234a..fc0820cdcfa 100644 --- a/frontend/src/metabase/query_builder/components/filters/modals/BulkFilterList/BulkFilterList.tsx +++ b/frontend/src/metabase/query_builder/components/filters/modals/BulkFilterList/BulkFilterList.tsx @@ -1,10 +1,17 @@ import React, { useMemo } from "react"; +import { t } from "ttag"; + import StructuredQuery, { DimensionOption, + SegmentOption, + isDimensionOption, + isSegmentOption, } from "metabase-lib/lib/queries/StructuredQuery"; import Dimension from "metabase-lib/lib/Dimension"; +import { isSegment } from "metabase/lib/query/filter"; +import { ModalDivider } from "../BulkFilterModal/BulkFilterModal.styled"; import Filter from "metabase-lib/lib/queries/structured/Filter"; -import BulkFilterSelect from "../BulkFilterSelect"; +import { BulkFilterSelect, SegmentFilterSelect } from "../BulkFilterSelect"; import { ListRoot, ListRow, @@ -15,10 +22,11 @@ import { export interface BulkFilterListProps { query: StructuredQuery; filters: Filter[]; - options: DimensionOption[]; + options: (DimensionOption | SegmentOption)[]; onAddFilter: (filter: Filter) => void; onChangeFilter: (filter: Filter, newFilter: Filter) => void; onRemoveFilter: (filter: Filter) => void; + onClearSegments: () => void; } const BulkFilterList = ({ @@ -28,10 +36,25 @@ const BulkFilterList = ({ onAddFilter, onChangeFilter, onRemoveFilter, + onClearSegments, }: BulkFilterListProps): JSX.Element => { + const [dimensions, segments] = useMemo( + () => [options.filter(isDimensionOption), options.filter(isSegmentOption)], + [options], + ); + return ( <ListRoot> - {options.map(({ dimension }, index) => ( + {!!segments.length && ( + <SegmentListItem + query={query} + segments={segments} + onAddFilter={onAddFilter} + onRemoveFilter={onRemoveFilter} + onClearSegments={onClearSegments} + /> + )} + {dimensions.map(({ dimension }, index) => ( <BulkFilterListItem key={index} query={query} @@ -96,4 +119,36 @@ const BulkFilterListItem = ({ ); }; +interface SegmentListItemProps { + query: StructuredQuery; + segments: SegmentOption[]; + onAddFilter: (filter: Filter) => void; + onRemoveFilter: (filter: Filter) => void; + onClearSegments: () => void; +} + +const SegmentListItem = ({ + query, + segments, + onAddFilter, + onRemoveFilter, + onClearSegments, +}: SegmentListItemProps): JSX.Element => ( + <> + <ListRow> + <ListRowLabel>{t`Segments`}</ListRowLabel> + <ListRowContent> + <SegmentFilterSelect + query={query} + segments={segments} + onAddFilter={onAddFilter} + onRemoveFilter={onRemoveFilter} + onClearSegments={onClearSegments} + /> + </ListRowContent> + </ListRow> + <ModalDivider marginY="0.5rem" /> + </> +); + export default BulkFilterList; diff --git a/frontend/src/metabase/query_builder/components/filters/modals/BulkFilterModal/BulkFilterModal.styled.tsx b/frontend/src/metabase/query_builder/components/filters/modals/BulkFilterModal/BulkFilterModal.styled.tsx index 973d885bc53..561a276b4cd 100644 --- a/frontend/src/metabase/query_builder/components/filters/modals/BulkFilterModal/BulkFilterModal.styled.tsx +++ b/frontend/src/metabase/query_builder/components/filters/modals/BulkFilterModal/BulkFilterModal.styled.tsx @@ -47,8 +47,13 @@ export const ModalTabPanel = styled(TabPanel)` padding: 0 2rem; `; -export const ModalDivider = styled.div` +interface ModalDividerProps { + marginY?: string; +} + +export const ModalDivider = styled.div<ModalDividerProps>` border-top: 1px solid ${color("border")}; + margin: ${props => (props.marginY ? props.marginY : "0")} 0; `; export const ModalCloseButton = styled(IconButtonWrapper)` diff --git a/frontend/src/metabase/query_builder/components/filters/modals/BulkFilterModal/BulkFilterModal.tsx b/frontend/src/metabase/query_builder/components/filters/modals/BulkFilterModal/BulkFilterModal.tsx index eda72d5ea35..61ed4f69f9e 100644 --- a/frontend/src/metabase/query_builder/components/filters/modals/BulkFilterModal/BulkFilterModal.tsx +++ b/frontend/src/metabase/query_builder/components/filters/modals/BulkFilterModal/BulkFilterModal.tsx @@ -39,7 +39,7 @@ const BulkFilterModal = ({ }, [query]); const sections = useMemo(() => { - return query.topLevelFilterFieldOptionSections(); + return query.topLevelFilterFieldOptionSections(null, 2, true); }, [query]); const handleAddFilter = useCallback((filter: Filter) => { @@ -60,6 +60,11 @@ const BulkFilterModal = ({ setIsChanged(true); }, []); + const handleClearSegments = useCallback(() => { + setQuery(query.clearSegments()); + setIsChanged(true); + }, [query]); + const handleApplyQuery = useCallback(() => { query.update(undefined, { run: true }); onClose?.(); @@ -81,6 +86,7 @@ const BulkFilterModal = ({ onAddFilter={handleAddFilter} onChangeFilter={handleChangeFilter} onRemoveFilter={handleRemoveFilter} + onClearSegments={handleClearSegments} /> ) : ( <BulkFilterModalSectionList @@ -90,6 +96,7 @@ const BulkFilterModal = ({ onAddFilter={handleAddFilter} onChangeFilter={handleChangeFilter} onRemoveFilter={handleRemoveFilter} + onClearSegments={handleClearSegments} /> )} <ModalDivider /> @@ -112,6 +119,7 @@ interface BulkFilterModalSectionProps { onAddFilter: (filter: Filter) => void; onChangeFilter: (filter: Filter, newFilter: Filter) => void; onRemoveFilter: (filter: Filter) => void; + onClearSegments: () => void; } const BulkFilterModalSection = ({ @@ -121,6 +129,7 @@ const BulkFilterModalSection = ({ onAddFilter, onChangeFilter, onRemoveFilter, + onClearSegments, }: BulkFilterModalSectionProps): JSX.Element => { return ( <ModalBody> @@ -131,6 +140,7 @@ const BulkFilterModalSection = ({ onAddFilter={onAddFilter} onChangeFilter={onChangeFilter} onRemoveFilter={onRemoveFilter} + onClearSegments={onClearSegments} /> </ModalBody> ); @@ -143,6 +153,7 @@ interface BulkFilterModalSectionListProps { onAddFilter: (filter: Filter) => void; onChangeFilter: (filter: Filter, newFilter: Filter) => void; onRemoveFilter: (filter: Filter) => void; + onClearSegments: () => void; } const BulkFilterModalSectionList = ({ @@ -152,6 +163,7 @@ const BulkFilterModalSectionList = ({ onAddFilter, onChangeFilter, onRemoveFilter, + onClearSegments, }: BulkFilterModalSectionListProps): JSX.Element => { const [tab, setTab] = useState(0); @@ -178,6 +190,7 @@ const BulkFilterModalSectionList = ({ onAddFilter={onAddFilter} onChangeFilter={onChangeFilter} onRemoveFilter={onRemoveFilter} + onClearSegments={onClearSegments} /> </ModalTabPanel> ))} diff --git a/frontend/src/metabase/query_builder/components/filters/modals/BulkFilterSelect/BulkFilterSelect.styled.tsx b/frontend/src/metabase/query_builder/components/filters/modals/BulkFilterSelect/BulkFilterSelect.styled.tsx index a89394bab08..a670e83e8cc 100644 --- a/frontend/src/metabase/query_builder/components/filters/modals/BulkFilterSelect/BulkFilterSelect.styled.tsx +++ b/frontend/src/metabase/query_builder/components/filters/modals/BulkFilterSelect/BulkFilterSelect.styled.tsx @@ -1,6 +1,7 @@ import styled from "@emotion/styled"; import SelectButton from "metabase/core/components/SelectButton"; import FilterPopover from "../../FilterPopover"; +import Select from "metabase/core/components/Select"; export const SelectFilterButton = styled(SelectButton)` min-height: 2.25rem; @@ -10,6 +11,10 @@ export const SelectFilterButton = styled(SelectButton)` } `; +export const SegmentSelect = styled(Select)` + min-height: 2.25rem; +`; + export const SelectFilterPopover = styled(FilterPopover)` overflow-y: auto; `; diff --git a/frontend/src/metabase/query_builder/components/filters/modals/BulkFilterSelect/BulkFilterSelect.tsx b/frontend/src/metabase/query_builder/components/filters/modals/BulkFilterSelect/BulkFilterSelect.tsx index 166f97a64fe..4fcb1b42cfc 100644 --- a/frontend/src/metabase/query_builder/components/filters/modals/BulkFilterSelect/BulkFilterSelect.tsx +++ b/frontend/src/metabase/query_builder/components/filters/modals/BulkFilterSelect/BulkFilterSelect.tsx @@ -1,11 +1,17 @@ import React, { useCallback, useMemo } from "react"; -import StructuredQuery from "metabase-lib/lib/queries/StructuredQuery"; +import { xor } from "lodash"; + +import StructuredQuery, { + SegmentOption, +} from "metabase-lib/lib/queries/StructuredQuery"; + import Filter from "metabase-lib/lib/queries/structured/Filter"; -import Dimension, { FieldDimension } from "metabase-lib/lib/Dimension"; +import Dimension from "metabase-lib/lib/Dimension"; import TippyPopoverWithTrigger from "metabase/components/PopoverWithTrigger/TippyPopoverWithTrigger"; import { SelectFilterButton, SelectFilterPopover, + SegmentSelect, } from "./BulkFilterSelect.styled"; export interface BulkFilterSelectProps { @@ -17,7 +23,7 @@ export interface BulkFilterSelectProps { onRemoveFilter: (filter: Filter) => void; } -const BulkFilterSelect = ({ +export const BulkFilterSelect = ({ query, filter, dimension, @@ -79,9 +85,72 @@ const BulkFilterSelect = ({ ); }; -const getNewFilter = (query: StructuredQuery, dimension: Dimension) => { +const getNewFilter = (query: StructuredQuery, dimension: Dimension): Filter => { const filter = new Filter([], null, dimension.query() ?? query); return filter.setDimension(dimension.mbql(), { useDefaultOperator: true }); }; -export default BulkFilterSelect; +export interface SegmentFilterSelectProps { + query: StructuredQuery; + segments: SegmentOption[]; + onAddFilter: (filter: Filter) => void; + onRemoveFilter: (filter: Filter) => void; + onClearSegments: () => void; +} + +export const SegmentFilterSelect = ({ + query, + segments, + onAddFilter, + onRemoveFilter, + onClearSegments, +}: SegmentFilterSelectProps): JSX.Element => { + const activeSegmentOptions = useMemo(() => { + const activeSegmentIds = query.segments().map(s => s.id); + return segments.filter(segment => + activeSegmentIds.includes(segment.filter[1]), + ); + }, [query, segments]); + + const toggleSegment = useCallback( + (changedSegment: SegmentOption) => { + const segmentIsActive = activeSegmentOptions.includes(changedSegment); + + const segmentFilter = segmentIsActive + ? (query + .filters() + .find( + f => f[0] === "segment" && f[1] === changedSegment.filter[1], + ) as Filter) + : new Filter(changedSegment.filter, null, query); + + segmentIsActive + ? onRemoveFilter(segmentFilter) + : onAddFilter(segmentFilter); + }, + [query, activeSegmentOptions, onRemoveFilter, onAddFilter], + ); + + return ( + <SegmentSelect + options={segments.map(segment => ({ + name: segment.name, + value: segment, + icon: segment.icon, + }))} + value={activeSegmentOptions} + onChange={(e: any) => toggleSegment(e.target.value.changedItem)} + multiple + buttonProps={{ + hasValue: activeSegmentOptions.length > 0, + highlighted: true, + onClear: onClearSegments, + }} + buttonText={ + activeSegmentOptions.length > 1 + ? `${activeSegmentOptions.length} segments` + : null + } + /> + ); +}; diff --git a/frontend/src/metabase/query_builder/components/filters/modals/BulkFilterSelect/index.ts b/frontend/src/metabase/query_builder/components/filters/modals/BulkFilterSelect/index.ts index 29ea47b7a8d..7d49974d64f 100644 --- a/frontend/src/metabase/query_builder/components/filters/modals/BulkFilterSelect/index.ts +++ b/frontend/src/metabase/query_builder/components/filters/modals/BulkFilterSelect/index.ts @@ -1 +1 @@ -export { default } from "./BulkFilterSelect"; +export * from "./BulkFilterSelect"; diff --git a/frontend/test/metabase/scenarios/filters/filter-bulk.cy.spec.js b/frontend/test/metabase/scenarios/filters/filter-bulk.cy.spec.js index add09525531..c0537910b72 100644 --- a/frontend/test/metabase/scenarios/filters/filter-bulk.cy.spec.js +++ b/frontend/test/metabase/scenarios/filters/filter-bulk.cy.spec.js @@ -1,4 +1,9 @@ -import { popover, restore, visitQuestionAdhoc } from "__support__/e2e/cypress"; +import { + popover, + restore, + visitQuestionAdhoc, + filter, +} from "__support__/e2e/cypress"; import { SAMPLE_DB_ID } from "__support__/e2e/cypress_data"; import { SAMPLE_DATABASE } from "__support__/e2e/cypress_sample_database"; @@ -41,6 +46,10 @@ const aggregatedQuestionDetails = { }, }; +const openFilterModal = () => { + cy.findByLabelText("Show more filters").click(); +}; + describe("scenarios > filters > bulk filtering", () => { beforeEach(() => { restore(); @@ -49,7 +58,7 @@ describe("scenarios > filters > bulk filtering", () => { it("should add a filter for a raw query", () => { visitQuestionAdhoc(rawQuestionDetails); - cy.findByLabelText("Show more filters").click(); + openFilterModal(); modal().within(() => { cy.findByLabelText("Quantity").click(); @@ -72,7 +81,7 @@ describe("scenarios > filters > bulk filtering", () => { it("should add a filter for an aggregated query", () => { visitQuestionAdhoc(aggregatedQuestionDetails); - cy.findByLabelText("Show more filters").click(); + openFilterModal(); modal().within(() => { cy.findByLabelText("Count").click(); @@ -102,7 +111,7 @@ describe("scenarios > filters > bulk filtering", () => { it("should add a filter for linked tables", () => { visitQuestionAdhoc(rawQuestionDetails); - cy.findByLabelText("Show more filters").click(); + openFilterModal(); modal().within(() => { cy.findByText("Product").click(); @@ -125,7 +134,7 @@ describe("scenarios > filters > bulk filtering", () => { it("should update an existing filter", () => { visitQuestionAdhoc(filteredQuestionDetails); - cy.findByLabelText("Show more filters").click(); + openFilterModal(); modal().within(() => { cy.findByText("is less than 30").click(); @@ -153,7 +162,7 @@ describe("scenarios > filters > bulk filtering", () => { it("should remove an existing filter", () => { visitQuestionAdhoc(filteredQuestionDetails); - cy.findByLabelText("Show more filters").click(); + openFilterModal(); modal().within(() => { cy.findByText("is less than 30") @@ -168,6 +177,98 @@ describe("scenarios > filters > bulk filtering", () => { cy.findByText("Quantity is less than 30").should("not.exist"); cy.findByText("Showing 138 rows").should("be.visible"); }); + + describe("segment filters", () => { + const SEGMENT_1_NAME = "Orders < 100"; + const SEGMENT_2_NAME = "Discounted Orders"; + + beforeEach(() => { + cy.request("POST", "/api/segment", { + name: SEGMENT_1_NAME, + description: "All orders with a total under $100.", + table_id: ORDERS_ID, + definition: { + "source-table": ORDERS_ID, + aggregation: [["count"]], + filter: ["<", ["field", ORDERS.TOTAL, null], 100], + }, + }); + + cy.request("POST", "/api/segment", { + name: SEGMENT_2_NAME, + description: "All orders with a discount", + table_id: ORDERS_ID, + definition: { + "source-table": ORDERS_ID, + aggregation: [["count"]], + filter: [">", ["field", ORDERS.DISCOUNT, null], 0], + }, + }); + }); + + it("should apply and remove segment filter", () => { + visitQuestionAdhoc(rawQuestionDetails); + openFilterModal(); + + modal().within(() => { + cy.findByText("Segments") + .parent() + .within(() => cy.get("button").click()); + }); + + popover().within(() => { + cy.findByText(SEGMENT_1_NAME); + cy.findByText(SEGMENT_2_NAME).click(); + }); + + modal().within(() => { + cy.button("Apply").click(); + cy.wait("@dataset"); + }); + + cy.findByTestId("qb-filters-panel").findByText(SEGMENT_2_NAME); + cy.findByText("Showing 1,915 rows"); + + openFilterModal(); + + modal().within(() => { + cy.findByText("Segments") + .parent() + .within(() => cy.get("button").click()); + }); + + popover().within(() => { + cy.findByText(SEGMENT_2_NAME).click(); + }); + + modal().within(() => { + cy.button("Apply").click(); + cy.wait("@dataset"); + }); + + cy.findByTestId("qb-filters-panel").should("not.exist"); + cy.findByText("Showing first 2,000 rows"); + }); + + it("should load already applied segments", () => { + visitQuestionAdhoc(rawQuestionDetails); + filter(); + cy.findByText(SEGMENT_1_NAME).click(); + + cy.findByTestId("qb-filters-panel").findByText(SEGMENT_1_NAME); + + openFilterModal(); + + modal().within(() => { + cy.findByText("Segments") + .parent() + .within(() => { + cy.findByText(SEGMENT_1_NAME); + cy.findByText(SEGMENT_2_NAME).should("not.exist"); + }); + }); + }); + }); }); const modal = () => { -- GitLab