Skip to content
Snippets Groups Projects
Unverified Commit 98761e7e authored by Ryan Laurie's avatar Ryan Laurie Committed by GitHub
Browse files

Display Custom Parameter Fields on Mobile (#21189)

* allow question paramater fields on mobile

* hide editor bar on mobile when there are no params

* show editor controls when already open

* add parameter mobile visibility test

* add visibilityToggler unit tests
parent 20dea324
Branches
Tags
No related merge requests found
......@@ -418,17 +418,19 @@ export default class NativeQueryEditor extends Component {
return (
<div className="NativeQueryEditor bg-light full">
{hasTopBar && (
<div className="flex align-center" style={{ minHeight: 55 }}>
<DataSourceSelectors
isNativeEditorOpen={isNativeEditorOpen}
query={query}
readOnly={readOnly}
setDatabaseId={this.setDatabaseId}
setTableId={this.setTableId}
/>
<div className="flex align-center">
<div className={!isNativeEditorOpen ? "hide sm-show" : ""}>
<DataSourceSelectors
isNativeEditorOpen={isNativeEditorOpen}
query={query}
readOnly={readOnly}
setDatabaseId={this.setDatabaseId}
setTableId={this.setTableId}
/>
</div>
{hasParametersList && (
<SyncedParametersList
className="mt1"
className="mt1 mx2"
parameters={parameters}
setParameterValue={setParameterValue}
setParameterIndex={this.setParameterIndex}
......@@ -438,6 +440,7 @@ export default class NativeQueryEditor extends Component {
)}
{query.hasWritePermission() && (
<VisibilityToggler
className={!isNativeEditorOpen ? "hide sm-show" : ""}
isOpen={isNativeEditorOpen}
readOnly={readOnly}
toggleEditor={this.toggleEditor}
......
......@@ -10,20 +10,27 @@ const propTypes = {
isOpen: PropTypes.bool.isRequired,
readOnly: PropTypes.bool.isRequired,
toggleEditor: PropTypes.func.isRequired,
className: PropTypes.string,
};
const VisibilityToggler = ({ isOpen, readOnly, toggleEditor }) => {
const VisibilityToggler = ({
isOpen,
readOnly,
toggleEditor,
className = "",
}) => {
const text = isOpen ? null : t`Open Editor`;
const icon = isOpen ? "contract" : "expand";
const className = cx(
const classNames = cx(
className,
"Query-label no-decoration flex align-center mx3 text-brand-hover transition-all",
{ hide: readOnly },
);
return (
<Container>
<a className={className} onClick={toggleEditor}>
<a className={classNames} onClick={toggleEditor}>
<Span>{text}</Span>
<Icon name={icon} size={18} />
</a>
......
......@@ -306,7 +306,7 @@ export default class View extends React.Component {
return (
<QueryBuilderMain isSidebarOpen={isSidebarOpen}>
{isNative ? (
<NativeQueryEditorContainer className="hide sm-show">
<NativeQueryEditorContainer>
<NativeQueryEditor
{...this.props}
viewHeight={height}
......
import React from "react";
import { render, fireEvent } from "@testing-library/react";
import VisibilityToggler from "metabase/query_builder/components/NativeQueryEditor/VisibilityToggler/VisibilityToggler";
describe("VisibilityToggler", () => {
it("should render collapse icon when open", () => {
const { container } = render(
<VisibilityToggler
isOpen={true}
isReadOnly={false}
toggleEditor={() => null}
/>,
);
const icons = container.querySelectorAll(".Icon-contract");
expect(icons.length).toBe(1);
});
it("should render expand icon when closed", () => {
const { container } = render(
<VisibilityToggler
isOpen={false}
readOnly={false}
toggleEditor={() => null}
/>,
);
const icons = container.querySelectorAll(".Icon-expand");
expect(icons.length).toBe(1);
});
it("should render passed class names", () => {
const testClassName = "test-class-name-" + Math.round(Math.random() * 1000);
const { container } = render(
<VisibilityToggler
isOpen={false}
readOnly={false}
toggleEditor={() => null}
className={testClassName}
/>,
);
expect(container.querySelectorAll("." + testClassName).length).toBe(1);
});
it("should render hide class when set to read only", () => {
const { container } = render(
<VisibilityToggler
isOpen={false}
readOnly={true}
toggleEditor={() => null}
/>,
);
expect(container.querySelectorAll(".hide").length).toBe(1);
});
it("should fire toggleEditor function on click", () => {
const spy = jest.fn();
const { container } = render(
<VisibilityToggler isOpen={false} readOnly={true} toggleEditor={spy} />,
);
const [icon] = container.querySelectorAll(".Icon-expand");
expect(spy).toHaveBeenCalledTimes(0);
fireEvent.click(icon);
expect(spy).toHaveBeenCalledTimes(1);
});
});
......@@ -121,6 +121,40 @@ describe("scenarios > filters > sql filters > basic filter types", () => {
});
});
it("displays parameter field on desktop and mobile", () => {
SQLFilter.enterParameterizedQuery(
"SELECT * FROM products WHERE products.category = {{testingparamvisbility77}}",
);
SQLFilter.setWidgetValue("Gizmo");
SQLFilter.runQuery();
cy.get("fieldset")
.findByText("Testingparamvisbility77")
.should("be.visible");
// close sidebar
cy.findByTestId("sidebar-right").within(() => {
cy.get(".Icon-close").click();
});
// resize window to mobile form factor
cy.viewport(480, 800);
cy.get("fieldset")
.findByText("Testingparamvisbility77")
.should("be.visible");
// collapse editor
cy.get(".Icon-contract")
.first()
.click();
cy.get("fieldset")
.findByText("Testingparamvisbility77")
.should("be.visible");
});
// flaky test (#19454)
it.skip("should show an info popover when hovering over fields in the field filter field picker", () => {
SQLFilter.enterParameterizedQuery("SELECT * FROM products WHERE {{cat}}");
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment