diff --git a/frontend/src/metabase/collections/containers/CollectionCreate.jsx b/frontend/src/metabase/collections/containers/CollectionCreate.jsx index 9337332ec174fb848abe4b9ddbaa7830c5d3b066..7622ea23a9ee3054b794d65ec42bc8081364081d 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 f0199fc50f2f35be70bf011ae29dbe4d110a94e3..1064da6cffb2dce73f92229283f293e013323051 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 b7f89564c054b06cc891f42b5626e7952d378d44..a7360df8ad89630d8ef3d3703cc067f044d8bb46 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 0000000000000000000000000000000000000000..98a44b9b615223df864e6219c7fb8bff1e8faba7 --- /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"); + }); +});