Skip to content

Commit

Permalink
Basic version of Models in Browse Data (#37707)
Browse files Browse the repository at this point in the history
* Add Models and Databases tabs
* Models are organized by collection
* Exclude items in personal collections
* Simplify BrowseHeader
  • Loading branch information
rafpaf committed Jan 31, 2024
1 parent 6657c3c commit 9166c58
Show file tree
Hide file tree
Showing 37 changed files with 1,125 additions and 175 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@ describe("scenarios > admin > databases > sample database", () => {
cy.findByText("Browse data").click();
});

cy.findByRole("tab", { name: "Databases" }).click();
cy.findByTestId("database-browser").within(() => {
cy.findByText("Sample Database").should("exist");
});
Expand Down
4 changes: 2 additions & 2 deletions e2e/test/scenarios/admin/datamodel/hide_tables.cy.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@ describe("scenarios > admin > datamodel > hidden tables (metabase#9759)", () =>

it("hidden table should not show up in various places in UI", () => {
// Visit the main page, we shouldn't be able to see the table
cy.visit(`/browse/${SAMPLE_DB_ID}`);
cy.visit(`/browse/databases/${SAMPLE_DB_ID}`);
// eslint-disable-next-line no-unscoped-text-selectors -- deprecated usage
cy.contains("Products");
// eslint-disable-next-line no-unscoped-text-selectors -- deprecated usage
cy.contains("Orders").should("not.exist");

// It shouldn't show up for a normal user either
cy.signInAsNormalUser();
cy.visit(`/browse/${SAMPLE_DB_ID}`);
cy.visit(`/browse/databases/${SAMPLE_DB_ID}`);
// eslint-disable-next-line no-unscoped-text-selectors -- deprecated usage
cy.contains("Products");
// eslint-disable-next-line no-unscoped-text-selectors -- deprecated usage
Expand Down
4 changes: 2 additions & 2 deletions e2e/test/scenarios/embedding/embedding-full-app.cy.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,8 @@ describeEE("scenarios > embedding > full app", () => {
url: "/browse",
qs: { side_nav: false, logo: false },
});
cy.findByRole("heading", { name: /Our data/ }).should("be.visible");
cy.findByRole("treeitem", { name: /Our data/ }).should("not.exist");
cy.findByRole("heading", { name: /Browse data/ }).should("be.visible");
cy.findByRole("treeitem", { name: /Browse data/ }).should("not.exist");
cy.findByRole("treeitem", { name: "Our analytics" }).should("not.exist");
appBar().should("not.exist");
});
Expand Down
1 change: 1 addition & 0 deletions e2e/test/scenarios/onboarding/auth/signin.cy.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ describe("scenarios > auth > signin", () => {
cy.signInAsAdmin();
cy.visit("/");
browse().click();
cy.findByRole("tab", { name: "Databases" }).click();
cy.findByRole("heading", { name: "Sample Database" }).click();
cy.findByRole("heading", { name: "Orders" }).click();
cy.wait("@dataset");
Expand Down
44 changes: 30 additions & 14 deletions e2e/test/scenarios/onboarding/home/browse.cy.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,38 @@ describe("scenarios > browse data", () => {
cy.signInAsAdmin();
});

it("basic UI flow should work", () => {
it("can browse to a model", () => {
cy.visit("/");
// eslint-disable-next-line no-unscoped-text-selectors -- deprecated usage
cy.findByText(/Browse data/).click();
cy.location("pathname").should("eq", "/browse");
// eslint-disable-next-line no-unscoped-text-selectors -- deprecated usage
cy.findByText(/^Our data$/i);
// eslint-disable-next-line no-unscoped-text-selectors -- deprecated usage
cy.findByText("Learn about our data").click();
cy.findByRole("listitem", { name: "Browse data" }).click();
cy.location("pathname").should("eq", "/browse/models");
cy.findByTestId("data-browser").findByText("Browse data");
cy.findByRole("heading", { name: "Orders Model" }).click();
cy.findByRole("button", { name: "Filter" });
});
it("can view summary of model's last edit", () => {
cy.visit("/");
cy.findByRole("listitem", { name: "Browse data" }).click();
cy.findByRole("note", /Bobby Tables.*7h./).realHover();
cy.findByRole("tooltip", { name: /Last edited by Bobby Tables/ });
});
it("can browse to a database", () => {
cy.visit("/");
cy.findByRole("listitem", { name: "Browse data" }).click();
cy.findByRole("tab", { name: "Databases" }).click();
cy.findByRole("heading", { name: "Sample Database" }).click();
cy.findByRole("heading", { name: "Products" }).click();
cy.findByRole("button", { name: "Summarize" });
cy.findByRole("link", { name: /Sample Database/ }).click();
});
it("can visit 'Learn about our data' page", () => {
cy.visit("/");
cy.findByRole("listitem", { name: "Browse data" }).click();
cy.findByRole("link", { name: /Learn about our data/ }).click();
cy.location("pathname").should("eq", "/reference/databases");
cy.go("back");
// eslint-disable-next-line no-unscoped-text-selectors -- deprecated usage
cy.findByText("Sample Database").click();
// eslint-disable-next-line no-unscoped-text-selectors -- deprecated usage
cy.findByText("Products").click();
// eslint-disable-next-line no-unscoped-text-selectors -- deprecated usage
cy.findByText("Rustic Paper Wallet");
cy.findByRole("tab", { name: "Databases" }).click();
cy.findByRole("heading", { name: "Sample Database" }).click();
cy.findByRole("heading", { name: "Products" }).click();
cy.findByRole("gridcell", { name: "Rustic Paper Wallet" });
});
});
1 change: 1 addition & 0 deletions e2e/test/scenarios/onboarding/setup/setup.cy.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,7 @@ describe("scenarios > setup", () => {
});

cy.visit("/browse");
cy.findByRole("tab", { name: "Databases" }).click();
cy.findByTestId("database-browser").findByText(dbName);
});
});
Expand Down
11 changes: 6 additions & 5 deletions e2e/test/scenarios/onboarding/urls.cy.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,21 @@ describe("URLs", () => {
});

describe("browse databases", () => {
it(`should slugify database name when opening it from /browse"`, () => {
cy.visit("/browse");
it(`should slugify database name when opening it from /browse/databases"`, () => {
cy.visit("/browse/databases");
cy.findByRole("tab", { name: "Databases" }).click();
cy.findByTextEnsureVisible("Sample Database").click();
// eslint-disable-next-line no-unscoped-text-selectors -- deprecated usage
cy.findByText("Sample Database");
cy.location("pathname").should(
"eq",
`/browse/${SAMPLE_DB_ID}-sample-database`,
`/browse/databases/${SAMPLE_DB_ID}-sample-database`,
);
});

[
`/browse/${SAVED_QUESTIONS_VIRTUAL_DB_ID}`,
`/browse/${SAVED_QUESTIONS_VIRTUAL_DB_ID}-saved-questions`,
`/browse/databases/${SAVED_QUESTIONS_VIRTUAL_DB_ID}`,
`/browse/databases/${SAVED_QUESTIONS_VIRTUAL_DB_ID}-saved-questions`,
].forEach(url => {
it("should open 'Saved Questions' database correctly", () => {
cy.visit(url);
Expand Down
4 changes: 2 additions & 2 deletions e2e/test/scenarios/permissions/impersonated.cy.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ describeEE("impersonated permission", () => {
});

it("have limited access", () => {
cy.visit(`/browse/${PG_DB_ID}`);
cy.visit(`/browse/databases/${PG_DB_ID}`);

// No access through the visual query builder
cy.get("main").within(() => {
Expand All @@ -340,7 +340,7 @@ describeEE("impersonated permission", () => {
});

// Has access to allowed tables
cy.visit(`/browse/${PG_DB_ID}`);
cy.visit(`/browse/databases/${PG_DB_ID}`);

cy.get("main").findByText("Orders").click();
cy.findAllByTestId("header-cell").contains("Subtotal");
Expand Down
6 changes: 0 additions & 6 deletions e2e/test/scenarios/question/new.cy.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,15 +74,9 @@ describe("scenarios > question > new", () => {

// eslint-disable-next-line no-unscoped-text-selectors -- deprecated usage
cy.contains("Our analytics");
// cy.findAllByRole("link", { name: "Our analytics" })
// .should("have.attr", "href")
// .and("eq", "/collection/root");

// eslint-disable-next-line no-unscoped-text-selectors -- deprecated usage
cy.contains("Sample Database");
// cy.findAllByRole("link", { name: "Sample Database" })
// .should("have.attr", "href")
// .and("eq", `/browse/${SAMPLE_DB_ID}-sample-database`);

// Discarding the search query should take us back to the original selector
// that starts with the list of databases and saved questions
Expand Down
1 change: 1 addition & 0 deletions e2e/test/scenarios/question/settings.cy.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,7 @@ describe("scenarios > question > settings", () => {
// create a new question to see if the "add to a dashboard" modal is still there
openNavigationSidebar();
browse().click();
cy.findByRole("tab", { name: "Databases" }).click();
// eslint-disable-next-line no-unscoped-text-selectors -- deprecated usage
cy.contains("Sample Database").click();
// eslint-disable-next-line no-unscoped-text-selectors -- deprecated usage
Expand Down
7 changes: 6 additions & 1 deletion frontend/src/metabase-types/api/search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,19 @@ export interface SearchResults {
total: number;
}

export type CollectionEssentials = Pick<
Collection,
"id" | "name" | "authority_level"
>;

export interface SearchResult {
id: number;
name: string;
model: SearchModelType;
description: string | null;
archived: boolean | null;
collection_position: number | null;
collection: Pick<Collection, "id" | "name" | "authority_level">;
collection: CollectionEssentials;
table_id: TableId;
bookmark: boolean | null;
database_id: DatabaseId;
Expand Down
6 changes: 0 additions & 6 deletions frontend/src/metabase/browse/components/BrowseApp.jsx

This file was deleted.

81 changes: 71 additions & 10 deletions frontend/src/metabase/browse/components/BrowseApp.styled.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,78 @@
import styled from "@emotion/styled";
import {
breakpointMinSmall,
breakpointMinMedium,
} from "metabase/styled-components/theme";
import { Tabs } from "metabase/ui";
import { color } from "metabase/lib/colors";
import EmptyState from "metabase/components/EmptyState";

export const BrowseAppRoot = styled.div`
margin: 0 0.5rem;
flex: 1;
height: 100%;
`;

${breakpointMinSmall} {
margin: 0 1rem;
}
export const BrowseTabs = styled(Tabs)`
display: flex;
flex-flow: column nowrap;
flex: 1;
`;

export const BrowseTabsList = styled(Tabs.List)`
padding: 0 1rem;
background-color: ${color("white")};
border-bottom-width: 1px;
`;

${breakpointMinMedium} {
margin: 0 4rem;
export const BrowseTab = styled(Tabs.Tab)`
top: 1px;
margin-bottom: 1px;
border-bottom-width: 3px !important;
padding: 10px;
&:hover {
color: ${color("brand")};
background-color: inherit;
border-color: transparent;
}
`;

export const BrowseTabsPanel = styled(Tabs.Panel)`
display: flex;
flex-flow: column nowrap;
flex: 1;
height: 100%;
padding: 0 1rem;
`;

export const BrowseContainer = styled.div`
display: flex;
flex: 1;
flex-flow: column nowrap;
height: 100%;
`;

export const BrowseDataHeader = styled.header`
display: flex;
padding: 1rem;
padding-bottom: 0.375rem;
color: ${color("dark")};
background-color: ${color("white")};
`;

export const BrowseSectionContainer = styled.div`
max-width: 1014px;
margin: 0 auto;
flex: 1;
display: flex;
width: 100%;
`;

export const BrowseTabsContainer = styled(BrowseSectionContainer)`
flex-flow: column nowrap;
justify-content: flex-start;
`;

export const CenteredEmptyState = styled(EmptyState)`
display: flex;
flex: 1;
flex-flow: column nowrap;
align-items: center;
justify-content: center;
height: 100%;
`;

0 comments on commit 9166c58

Please sign in to comment.