Skip to content
Snippets Groups Projects
Unverified Commit 21fb561e authored by Romeo Van Snick's avatar Romeo Van Snick Committed by GitHub
Browse files

List metrics in native editor data reference (#48191)

* Add metrics to table pane

* Add test for metric in data reference sidebar

* Clean up other reference tests

* Add test for when the table has no metrics

* Use helper for sidebar header title

* Rename sidebar to create distinction from existing helper
parent 4b278779
No related branches found
No related tags found
No related merge requests found
......@@ -3,8 +3,10 @@ import {
USER_GROUPS,
WRITABLE_DB_ID,
} from "e2e/support/cypress_data";
import { SAMPLE_DATABASE } from "e2e/support/cypress_sample_database";
import { THIRD_COLLECTION_ID } from "e2e/support/cypress_sample_instance_data";
import {
createQuestion,
entityPickerModal,
filter,
filterField,
......@@ -19,6 +21,19 @@ import {
visitQuestionAdhoc,
} from "e2e/support/helpers";
const { ORDERS_ID } = SAMPLE_DATABASE;
const ORDERS_SCALAR_METRIC = {
name: "Count of orders",
type: "metric",
description: "A metric",
query: {
"source-table": ORDERS_ID,
aggregation: [["count"]],
},
display: "scalar",
};
describe("scenarios > question > native", () => {
beforeEach(() => {
cy.intercept("POST", "api/card").as("card");
......@@ -495,32 +510,25 @@ describe("scenarios > native question > data reference sidebar", () => {
it("should show tables", () => {
openNativeEditor();
cy.icon("reference").click();
cy.get("[data-testid='sidebar-header-title']").findByText(
"Sample Database",
);
// eslint-disable-next-line no-unscoped-text-selectors -- deprecated usage
cy.findByText("ORDERS").click();
// eslint-disable-next-line no-unscoped-text-selectors -- deprecated usage
cy.findByText(
"Confirmed Sample Company orders for a product, from a user.",
);
// eslint-disable-next-line no-unscoped-text-selectors -- deprecated usage
cy.findByText("9 columns");
// eslint-disable-next-line no-unscoped-text-selectors -- deprecated usage
cy.findByText("QUANTITY").click();
// eslint-disable-next-line no-unscoped-text-selectors -- deprecated usage
cy.findByText("Number of products bought.");
// clicking the title should navigate back
// eslint-disable-next-line no-unscoped-text-selectors -- deprecated usage
cy.findByText("QUANTITY").click();
// eslint-disable-next-line no-unscoped-text-selectors -- deprecated usage
cy.findByText("ORDERS").click();
cy.get("[data-testid='sidebar-header-title']")
.findByText("Sample Database")
.click();
// eslint-disable-next-line no-unscoped-text-selectors -- deprecated usage
cy.findByText("Data Reference");
referenceButton().click();
sidebarHeaderTitle().should("have.text", "Sample Database");
dataReferenceSidebar().within(() => {
cy.findByText("ORDERS").click();
cy.findByText(
"Confirmed Sample Company orders for a product, from a user.",
);
cy.findByText("9 columns");
cy.findByText("QUANTITY").click();
cy.findByText("Number of products bought.");
cy.log("clicking the title should navigate back");
cy.findByText("QUANTITY").click();
cy.findByText("ORDERS").click();
sidebarHeaderTitle().findByText("Sample Database").click();
cy.findByText("Data Reference");
});
});
it("should show models", () => {
......@@ -544,24 +552,64 @@ describe("scenarios > native question > data reference sidebar", () => {
});
openNativeEditor();
cy.icon("reference").click();
// eslint-disable-next-line no-unscoped-text-selectors -- deprecated usage
cy.findByText("2 models");
// eslint-disable-next-line no-unscoped-text-selectors -- deprecated usage
cy.findByText("Native Products Model").click();
// eslint-disable-next-line no-unscoped-text-selectors -- deprecated usage
cy.findByText("A model of the Products table"); // description
// eslint-disable-next-line no-unscoped-text-selectors -- deprecated usage
cy.findByText("Bobby Tables's Personal Collection"); // collection
// eslint-disable-next-line no-unscoped-text-selectors -- deprecated usage
cy.findByText("1 column");
// eslint-disable-next-line no-unscoped-text-selectors -- deprecated usage
cy.findByText("RENAMED_ID").click();
// eslint-disable-next-line no-unscoped-text-selectors -- deprecated usage
cy.findByText("No description");
referenceButton().click();
dataReferenceSidebar().within(() => {
cy.findByText("2 models");
cy.findByText("Native Products Model").click();
cy.findByText("A model of the Products table"); // description
cy.findByText("Bobby Tables's Personal Collection"); // collection
cy.findByText("1 column");
cy.findByText("RENAMED_ID").click();
cy.findByText("No description");
});
});
describe("metrics", () => {
it("should not show metrics when they are not defined on the selected table", () => {
openNativeEditor();
referenceButton().click();
sidebarHeaderTitle().should("have.text", "Sample Database");
dataReferenceSidebar().within(() => {
cy.findByText("ORDERS").click();
cy.findByText(/metric/).should("not.exist");
});
});
it("should show metrics defined on tables", () => {
createQuestion(ORDERS_SCALAR_METRIC);
openNativeEditor();
referenceButton().click();
sidebarHeaderTitle().should("have.text", "Sample Database");
dataReferenceSidebar().within(() => {
cy.findByText("ORDERS").click();
cy.findByText("1 metric").should("be.visible");
cy.findByText("Count of orders").should("be.visible").click();
cy.findByText("A metric").should("be.visible");
cy.log("clicking the title should navigate back");
cy.findByText("Count of orders").should("be.visible").click();
});
});
});
});
function referenceButton() {
return cy.icon("reference");
}
function sidebarHeaderTitle() {
return cy.findByTestId("sidebar-header-title");
}
function dataReferenceSidebar() {
return cy.findByTestId("sidebar-right");
}
const runQuery = () => {
cy.findByTestId("native-query-editor-container").within(() => {
cy.button("Get Answer").click();
......
import { connect } from "react-redux";
import { t } from "ttag";
import { msgid, ngettext, t } from "ttag";
import _ from "underscore";
import {
......@@ -14,6 +14,15 @@ import type Table from "metabase-lib/v1/metadata/Table";
import type { State } from "metabase-types/store";
import FieldList from "./FieldList";
import {
NodeListIcon,
NodeListItemIcon,
NodeListItemLink,
NodeListItemName,
NodeListTitle,
NodeListTitleText,
QuestionId,
} from "./NodeList.styled";
import { PaneContent } from "./Pane.styled";
import TableInfoLoader from "./TableInfoLoader";
......@@ -28,42 +37,74 @@ const mapStateToProps = (state: State, props: TablePaneProps) => ({
table: Tables.selectors.getObject(state, { entityId: props.table.id }),
});
const TablePane = ({ table, onItemClick, onBack, onClose }: TablePaneProps) => (
<SidebarContent
title={table.name}
icon={"table"}
onBack={onBack}
onClose={onClose}
>
<PaneContent>
<TableInfoLoader table={table}>
<div className={CS.ml1}>
{table.description ? (
<Description>{table.description}</Description>
) : (
<EmptyDescription>{t`No description`}</EmptyDescription>
)}
</div>
<div className={CS.my2}>
{table.fields?.length ? (
<>
<FieldList
fields={table.fields}
onFieldClick={f => onItemClick("field", f)}
/>
{table.connectedTables() && (
<ConnectedTableList
tables={table.connectedTables()}
onTableClick={t => onItemClick("table", t)}
function TablePane({ table, onItemClick, onBack, onClose }: TablePaneProps) {
return (
<SidebarContent
title={table.name}
icon={"table"}
onBack={onBack}
onClose={onClose}
>
<PaneContent>
<TableInfoLoader table={table}>
<div className={CS.ml1}>
{table.description ? (
<Description>{table.description}</Description>
) : (
<EmptyDescription>{t`No description`}</EmptyDescription>
)}
</div>
<div className={CS.my2}>
{table.fields?.length ? (
<>
<FieldList
fields={table.fields}
onFieldClick={f => onItemClick("field", f)}
/>
)}
</>
) : null}
</div>
</TableInfoLoader>
</PaneContent>
</SidebarContent>
);
{table.connectedTables() && (
<ConnectedTableList
tables={table.connectedTables()}
onTableClick={t => onItemClick("table", t)}
/>
)}
</>
) : null}
{table.metrics?.length ? (
<>
<NodeListTitle>
<NodeListIcon name="metric" />
<NodeListTitleText>
{ngettext(
msgid`${table.metrics.length} metric`,
`${table.metrics.length} metrics`,
table.metrics.length,
)}
</NodeListTitleText>
</NodeListTitle>
<ul>
{table.metrics?.map(metric => (
<li key={metric.card().id}>
<NodeListItemLink
onClick={() => onItemClick("question", metric.card())}
>
<NodeListItemIcon name="metric" />
<NodeListItemName>
{metric.card().name}
</NodeListItemName>
<QuestionId>{`#${metric.id()}`}</QuestionId>
</NodeListItemLink>
</li>
))}
</ul>
<br></br>
</>
) : null}
</div>
</TableInfoLoader>
</PaneContent>
</SidebarContent>
);
}
// eslint-disable-next-line import/no-default-export -- deprecated usage
export default _.compose(
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment