From ef597af3e14f92371acf8e31b5f16c3a6775466e Mon Sep 17 00:00:00 2001 From: Alexander Lesnenko <alxnddr@users.noreply.github.com> Date: Tue, 11 Jan 2022 22:55:35 +0000 Subject: [PATCH] Fix creating a new collection from navbar (#19626) * Fix creating a new collection from navbar * add specs --- .../containers/CollectionCreate.jsx | 17 +++++-- frontend/src/metabase/collections/utils.js | 2 +- .../src/metabase/nav/containers/Navbar.jsx | 38 +++++++++++++--- .../onboarding/navbar/new-menu.cy.spec.js | 45 +++++++++++++++++++ 4 files changed, 91 insertions(+), 11 deletions(-) create mode 100644 frontend/test/metabase/scenarios/onboarding/navbar/new-menu.cy.spec.js diff --git a/frontend/src/metabase/collections/containers/CollectionCreate.jsx b/frontend/src/metabase/collections/containers/CollectionCreate.jsx index 9337332ec17..7622ea23a9e 100644 --- a/frontend/src/metabase/collections/containers/CollectionCreate.jsx +++ b/frontend/src/metabase/collections/containers/CollectionCreate.jsx @@ -28,18 +28,29 @@ const mapDispatchToProps = { @connect(mapStateToProps, mapDispatchToProps) export default class CollectionCreate extends Component { + handleClose = () => { + const { goBack, onClose } = this.props; + return onClose ? onClose() : goBack(); + }; + + handleSaved = collection => { + const { goBack, onSaved } = this.props; + return onSaved ? onSaved(collection) : goBack(); + }; + render() { - const { form, initialCollectionId, goBack } = this.props; + const { form, initialCollectionId } = this.props; return ( <Collection.ModalForm + overwriteOnInitialValuesChange formName={FORM_NAME} form={form} collection={{ parent_id: initialCollectionId, authority_level: REGULAR_COLLECTION.type, }} - onSaved={goBack} - onClose={goBack} + onSaved={this.handleSaved} + onClose={this.handleClose} /> ); } diff --git a/frontend/src/metabase/collections/utils.js b/frontend/src/metabase/collections/utils.js index f0199fc50f2..1064da6cffb 100644 --- a/frontend/src/metabase/collections/utils.js +++ b/frontend/src/metabase/collections/utils.js @@ -54,7 +54,7 @@ function getNonRootParentId(collection) { return nonRootParent ? nonRootParent.id : undefined; } // location is a string like "/1/4" where numbers are parent collection IDs - const [nonRootParentId] = collection.location.split("/"); + const nonRootParentId = collection.location?.split("/")?.[0]; return canonicalCollectionId(nonRootParentId); } diff --git a/frontend/src/metabase/nav/containers/Navbar.jsx b/frontend/src/metabase/nav/containers/Navbar.jsx index b7f89564c05..a7360df8ad8 100644 --- a/frontend/src/metabase/nav/containers/Navbar.jsx +++ b/frontend/src/metabase/nav/containers/Navbar.jsx @@ -20,6 +20,7 @@ import Modal from "metabase/components/Modal"; import ProfileLink from "metabase/nav/components/ProfileLink"; import SearchBar from "metabase/nav/components/SearchBar"; +import CollectionCreate from "metabase/collections/containers/CollectionCreate"; import CreateDashboardModal from "metabase/components/CreateDashboardModal"; import { AdminNavbar } from "../components/AdminNavbar"; @@ -47,6 +48,7 @@ const mapDispatchToProps = { }; const MODAL_NEW_DASHBOARD = "MODAL_NEW_DASHBOARD"; +const MODAL_NEW_COLLECTION = "MODAL_NEW_COLLECTION"; @Database.loadList({ // set this to false to prevent a potential spinner on the main nav @@ -192,7 +194,7 @@ export default class Navbar extends Component { { title: t`Collection`, icon: `all`, - link: Urls.newCollection("root"), + action: () => this.setModal(MODAL_NEW_COLLECTION), event: `NavBar;New Collection Click;`, }, ]} @@ -220,17 +222,39 @@ export default class Navbar extends Component { ); } + renderModalContent() { + const { modal } = this.state; + const { onChangeLocation } = this.props; + + switch (modal) { + case MODAL_NEW_COLLECTION: + return ( + <CollectionCreate + onClose={() => this.setState({ modal: null })} + onSaved={collection => { + this.setState({ modal: null }); + onChangeLocation(Urls.collection(collection)); + }} + /> + ); + case MODAL_NEW_DASHBOARD: + return ( + <CreateDashboardModal + onClose={() => this.setState({ modal: null })} + /> + ); + default: + return null; + } + } + renderModal() { const { modal } = this.state; + if (modal) { return ( <Modal onClose={() => this.setState({ modal: null })}> - {modal === MODAL_NEW_DASHBOARD ? ( - <CreateDashboardModal - createDashboard={this.props.createDashboard} - onClose={() => this.setState({ modal: null })} - /> - ) : null} + {this.renderModalContent()} </Modal> ); } else { diff --git a/frontend/test/metabase/scenarios/onboarding/navbar/new-menu.cy.spec.js b/frontend/test/metabase/scenarios/onboarding/navbar/new-menu.cy.spec.js new file mode 100644 index 00000000000..98a44b9b615 --- /dev/null +++ b/frontend/test/metabase/scenarios/onboarding/navbar/new-menu.cy.spec.js @@ -0,0 +1,45 @@ +import { restore, popover, modal } from "__support__/e2e/cypress"; + +describe("metabase > scenarios > navbar > new menu", () => { + beforeEach(() => { + restore(); + cy.signInAsAdmin(); + + cy.visit("/"); + cy.findByText("New").click(); + }); + + it("question item opens question notebook editor", () => { + popover().within(() => { + cy.findByText("Question").click(); + }); + + cy.url("should.contain", "/question/notebook#"); + }); + + it("question item opens SQL query editor", () => { + popover().within(() => { + cy.findByText("SQL query").click(); + }); + + cy.url("should.contain", "/question#"); + cy.get(".ace_content"); + }); + + it("collection opens modal and redirects to a created collection after saving", () => { + popover().within(() => { + cy.findByText("Collection").click(); + }); + + modal().within(() => { + cy.findByText("Our analytics"); + + cy.findByLabelText("Name").type("Test collection"); + cy.findByLabelText("Description").type("Test collection description"); + + cy.findByText("Create").click(); + }); + + cy.get("h1").should("have.text", "Test collection"); + }); +}); -- GitLab