Skip to content

Commit

Permalink
Use SearchResult component (#14867)
Browse files Browse the repository at this point in the history
* Use SearchResult component

Update the backend to return much richer match data

[Fixes #14832]

* Increase the memoization cache for search scoring by common subseq (#14894)

* Increase the memoization cache for search scoring by common subseq

Also limit the size of input it can get

(Hopefully) [Fixes #14852]

* Don't group search results by type (#14898)

Respect the sorting done by the backend

* Format metrics and segments in search results; DRY up the code

* Add normalizedCollection(); show "Our Analytics" collection in search results

* Use SearchResult for typeahead results too
  • Loading branch information
tsmacdonald committed Feb 22, 2021
1 parent 94fed25 commit f66d688
Show file tree
Hide file tree
Showing 11 changed files with 180 additions and 126 deletions.
8 changes: 8 additions & 0 deletions frontend/src/metabase/entities/collections.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,14 @@ export const canonicalCollectionId = (
? null
: parseInt(collectionId, 10);

// $FlowFixMe
export function normalizedCollection(collection) {
if (canonicalCollectionId(collection.id) === null) {
return ROOT_COLLECTION;
}
return collection;
}

export const getCollectionType = (collectionId: string, state: {}) =>
collectionId === null || collectionId === "root"
? "root"
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/metabase/entities/dashboards.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { POST, DELETE } from "metabase/lib/api";
import {
canonicalCollectionId,
getCollectionType,
normalizedCollection,
} from "metabase/entities/collections";

const FAVORITE_ACTION = `metabase/entities/dashboards/FAVORITE`;
Expand Down Expand Up @@ -132,6 +133,8 @@ const Dashboards = createEntity({
getFavorited: dashboard => dashboard && dashboard.favorite,
getName: dashboard => dashboard && dashboard.name,
getUrl: dashboard => dashboard && Urls.dashboard(dashboard.id),
getCollection: dashboard =>
dashboard && normalizedCollection(dashboard.collection),
getIcon: dashboard => "dashboard",
getColor: () => color("dashboard"),
},
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/metabase/entities/questions.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { color } from "metabase/lib/colors";
import {
canonicalCollectionId,
getCollectionType,
normalizedCollection,
} from "metabase/entities/collections";

import { POST, DELETE } from "metabase/lib/api";
Expand Down Expand Up @@ -67,6 +68,8 @@ const Questions = createEntity({
getName: question => question && question.name,
getUrl: question => question && Urls.question(question.id),
getColor: () => color("text-medium"),
getCollection: question =>
question && normalizedCollection(question.collection),
getIcon: question =>
(require("metabase/visualizations").default.get(question.display) || {})
.iconName || "beaker",
Expand Down
65 changes: 3 additions & 62 deletions frontend/src/metabase/home/containers/SearchApp.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,10 @@ import Link from "metabase/components/Link";
import { Box, Flex } from "grid-styled";

import Search from "metabase/entities/search";
import Database from "metabase/entities/databases";

import Card from "metabase/components/Card";
import EmptyState from "metabase/components/EmptyState";
import EntityItem from "metabase/components/EntityItem";
import SearchResult from "metabase/search/components/SearchResult";
import Subhead from "metabase/components/type/Subhead";
import { FILTERS } from "metabase/collections/components/ItemTypeFilterBar";

Expand Down Expand Up @@ -50,17 +49,7 @@ export default class SearchApp extends React.Component {
.groupBy("model")
.value();

// either use the specified filter type or order the full set according to our preferred order
// (this should probably just be the default return from the endpoint no?
const resultDisplay = resultsByType[location.query.type] || [
...(resultsByType.dashboard || []),
...(resultsByType.metric || []),
...(resultsByType.table || []),
...(resultsByType.segment || []),
...(resultsByType.card || []),
...(resultsByType.collection || []),
...(resultsByType.pulse || []),
];
const resultDisplay = resultsByType[location.query.type] || list;

const searchFilters = FILTERS.concat(
{
Expand Down Expand Up @@ -147,55 +136,7 @@ export default class SearchApp extends React.Component {
const SearchResultSection = ({ title, items }) => (
<Card>
{items.map(item => {
let extraInfo;
switch (item.model) {
case "table":
case "segment":
case "metric":
extraInfo = (
<Flex align="center" color={color("text-medium")}>
<Icon name="database" size={8} mr="4px" />
<span className="text-small text-bold" style={{ lineHeight: 1 }}>
<Database.Name id={item.database_id} />
</span>
</Flex>
);
break;
case "collection":
break;
default:
extraInfo = (
<div className="inline-block">
<Flex align="center" color={color("text-medium")}>
<Icon name="folder" size={10} mr="4px" />
<span
className="text-small text-bold"
style={{ lineHeight: 1 }}
>
{item.collection_name || t`Our Analytics`}
</span>
</Flex>
</div>
);
break;
}

return (
<Link
to={item.getUrl()}
key={item.id}
data-metabase-event={`Search Results;Item Click;${item.model}`}
>
<EntityItem
variant="list"
name={item.getName()}
iconName={item.getIcon()}
iconColor={item.getColor()}
item={item}
extraInfo={extraInfo}
/>
</Link>
);
return <SearchResult result={item} />;
})}
</Card>
);
3 changes: 3 additions & 0 deletions frontend/src/metabase/lib/entities.js
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,9 @@ export function createEntity(def: EntityDefinition): Entity {
getColor(object) {
return undefined;
},
getCollection(object) {
return object.collection;
},
...(def.objectSelectors || {}),
};

Expand Down
12 changes: 2 additions & 10 deletions frontend/src/metabase/nav/components/SearchBar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,8 @@ import { color, lighten } from "metabase/lib/colors";

import Card from "metabase/components/Card";
import Icon from "metabase/components/Icon";
import EntityItem from "metabase/components/EntityItem";
import Link from "metabase/components/Link";
import OnClickOutsideWrapper from "metabase/components/OnClickOutsideWrapper";
import SearchResult from "metabase/search/components/SearchResult";

import { DefaultSearchColor } from "metabase/nav/constants";

Expand Down Expand Up @@ -104,14 +103,7 @@ export default class SearchBar extends React.Component {
} else {
return results.map(l => (
<li key={`${l.model}:${l.id}`}>
<Link to={l.getUrl()}>
<EntityItem
iconName={l.getIcon()}
name={l.name}
item={l}
variant="small"
/>
</Link>
<SearchResult result={l} compact={true} />
</li>
));
}
Expand Down
85 changes: 58 additions & 27 deletions frontend/src/metabase/search/components/SearchResult.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,16 +54,18 @@ function ItemIcon({ item }) {
);
}

export default function SearchResult({ result }) {
export default function SearchResult(props) {
const { result } = props;
switch (result.model) {
case "card":
return <QuestionResult question={result} />;
case "dashboard":
return <DashboardResult dashboard={result} />;
return <QuestionResult question={result} options={props} />;
case "collection":
return <CollectionResult collection={result} />;
return <CollectionResult collection={result} options={props} />;
case "dashboard":
return <DashboardResult dashboard={result} options={props} />;
default:
return <div>{result.name}</div>;
// metric, segment, and table deliberately included here
return <DefaultResult result={result} options={props} />;
}
}

Expand Down Expand Up @@ -113,14 +115,54 @@ function CollectionResult({ collection }) {
);
}

function QuestionResult({ question }) {
function contextText(context) {
return context.map(function({ is_match, text }) {
if (is_match) {
return <strong> {text}</strong>;
} else {
return <span> {text}</span>;
}
});
}

function formatContext(context, compact) {
return (
!compact &&
context && (
<Box ml="42px" mt="12px">
{contextText(context)}
</Box>
)
);
}

function formatCollection(collection) {
return collection.id && <CollectionBadge collection={collection} />;
}

function DashboardResult({ dashboard, options }) {
return (
<ResultLink to={dashboard.getUrl()}>
<Flex align="center">
<ItemIcon item={dashboard} />
<Box>
<Title>{dashboard.name}</Title>
{formatCollection(dashboard.getCollection())}
</Box>
</Flex>
{formatContext(dashboard.context, options.compact)}
</ResultLink>
);
}

function QuestionResult({ question, options }) {
return (
<ResultLink to={Urls.question(question.id)}>
<ResultLink to={question.getUrl()}>
<Flex align="center">
<ItemIcon item={question} />
<Box>
<Title>{question.name}</Title>
<CollectionBadge collection={question.collection} />
{formatCollection(question.getCollection())}
</Box>
{question.description && (
<Box ml="auto">
Expand All @@ -130,31 +172,20 @@ function QuestionResult({ question }) {
</Box>
)}
</Flex>
{question.context && (
<Box ml="42px" mt="12px">
<strong>{question.context.match}:</strong> {question.context.content}
</Box>
)}
{formatContext(question.context, options.compact)}
</ResultLink>
);
}

function DashboardResult({ dashboard }) {
function DefaultResult({ result, options }) {
return (
<ResultLink>
<ResultLink to={result.getUrl()}>
<Flex align="center">
<ItemIcon item={dashboard} />
<Box>
<Title>{dashboard.name}</Title>
<CollectionBadge collection={dashboard.collection} />
</Box>
<ItemIcon item={result} />
<Title>{result.name}</Title>
{formatCollection(result.getCollection())}
</Flex>
{dashboard.context && (
<Box ml="42px" mt="12px">
<strong>{dashboard.context.match}:</strong>{" "}
{dashboard.context.content}
</Box>
)}
{formatContext(result.context, options.compact)}
</ResultLink>
);
}
6 changes: 3 additions & 3 deletions frontend/test/metabase/scenarios/auth/search.cy.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,21 @@ describe("scenarios > auth > search", () => {
signInAsAdmin();
cy.visit("/");
cy.findByPlaceholderText("Search…").type("product{enter}");
cy.findByText("PRODUCTS");
cy.findByText("Products");
});

it("should work for user with permissions (metabase#12332)", () => {
signInAsNormalUser();
cy.visit("/");
cy.findByPlaceholderText("Search…").type("product{enter}");
cy.findByText("PRODUCTS");
cy.findByText("Products");
});

it("should not work for user without permissions", () => {
signIn("nodata");
cy.visit("/");
cy.findByPlaceholderText("Search…").type("product{enter}");
cy.findByText("PRODUCTS").should("not.exist");
cy.findByText("Products").should("not.exist");
});
});
});

0 comments on commit f66d688

Please sign in to comment.