Skip to content
Snippets Groups Projects
Unverified Commit b669bd7c authored by Gustavo Saiani's avatar Gustavo Saiani Committed by GitHub
Browse files

Bookmarks: render official icons for collections (#21240)

parent c48a2ea1
Branches
Tags
No related merge requests found
export type BookmarkableEntities = "card" | "collection";
export type BookmarkableEntities = "card" | "collection" | "dashboard";
export interface Bookmark {
authority_level?: string;
card_id: string;
display?: string;
id: string;
......
import styled from "@emotion/styled";
import { css } from "@emotion/react";
import { color } from "metabase/lib/colors";
import { space } from "metabase/styled-components/theme";
......@@ -9,9 +10,13 @@ const CollectionSidebarBookmarksRoot = styled.div`
margin-bottom: ${space(2)};
`;
export const BookmarkTypeIcon = styled(Icon)`
interface BookmarkTypeIconProps {
opacity: number;
}
export const BookmarkTypeIcon = styled(Icon)<BookmarkTypeIconProps>`
margin-right: 6px;
opacity: 0.5;
opacity: ${({ opacity }) => opacity};
`;
export const BookmarkListRoot = styled.div`
......@@ -36,9 +41,11 @@ export const BookmarkContainer = styled.div`
color: ${color("brand")};
cursor: pointer;
padding: ${space(1)};
margin-top: 2px;
position: absolute;
right: 0;
top: 0;
top: 50%;
transform: translateY(-50%);
}
`;
......
import React, { useState } from "react";
import { t } from "ttag";
import { PLUGIN_COLLECTIONS } from "metabase/plugins";
import * as Urls from "metabase/lib/urls";
import { color } from "metabase/lib/colors";
import Icon from "metabase/components/Icon";
import Link from "metabase/collections/components/CollectionSidebar/CollectionSidebarLink";
import Tooltip from "metabase/components/Tooltip";
import { getIcon } from "./getIcon";
import BookmarkEntity from "metabase/entities/bookmarks";
import { LabelContainer } from "../Collections/CollectionsList/CollectionsList.styled";
import BookmarksRoot, {
BookmarkContainer,
......@@ -21,10 +22,8 @@ import {
import { Bookmark, BookmarkableEntities, Bookmarks } from "metabase-types/api";
interface LabelProps {
name: string;
display?: string;
type: BookmarkableEntities;
interface BookmarkProps {
bookmark: Bookmark;
}
interface CollectionSidebarBookmarksProps {
......@@ -32,12 +31,31 @@ interface CollectionSidebarBookmarksProps {
deleteBookmark: (id: string, type: string) => void;
}
const Label = ({ display, name, type }: LabelProps) => {
const iconName = getIcon(display, type);
interface IconProps {
name: string;
tooltip?: string;
isOfficial?: boolean;
}
const BookmarkIcon = ({ bookmark }: BookmarkProps) => {
const icon = BookmarkEntity.objectSelectors.getIcon(bookmark);
const isCollection = bookmark.type === "collection";
const isRegularCollection =
isCollection && PLUGIN_COLLECTIONS.isRegularCollection(bookmark);
const isOfficial = isCollection && !isRegularCollection;
const iconColor = isOfficial ? color("warning") : color("brand");
return <BookmarkTypeIcon {...icon} color={iconColor} />;
};
const Label = ({ bookmark }: BookmarkProps) => {
const icon = BookmarkEntity.objectSelectors.getIcon(bookmark);
return (
<LabelContainer>
<BookmarkTypeIcon name={iconName} />
{name}
<BookmarkIcon bookmark={bookmark} />
{bookmark.name}
</LabelContainer>
);
};
......@@ -87,13 +105,11 @@ const CollectionSidebarBookmarks = ({
return (
<BookmarkContainer key={`bookmark-${id}`}>
<Link to={url}>
<Label name={name} type={type} />
<Label bookmark={bookmark} />
</Link>
<button onClick={() => handleDeleteBookmark(bookmark)}>
<Tooltip tooltip={t`Remove bookmark`} placement="bottom">
<Icon name="bookmark" />
</Tooltip>
<Icon name="bookmark" />
</button>
</BookmarkContainer>
);
......
import { BookmarkableEntities } from "metabase-types/api";
export function getIcon(
display: string | undefined,
type: BookmarkableEntities,
) {
if (display) {
return display;
}
const icons = {
card: "grid",
collection: "folder",
dashboard: "dashboard",
};
return icons[type];
}
import { getIcon } from "./getIcon";
describe("get icon to render alongside bookmark", () => {
it("returns `display` if available", () => {
expect(getIcon("display")).toBe("display");
});
describe("maps to icon that corresponds to type", () => {
it("renders for generic card", () => {
expect(getIcon(null, "card")).toBe("grid");
});
it("renders for collection", () => {
expect(getIcon(null, "collection")).toBe("folder");
});
it("renders for dashboard", () => {
expect(getIcon(null, "dashboard")).toBe("dashboard");
});
});
});
import { createEntity } from "metabase/lib/entities";
import Collection from "metabase/entities/collections";
import Dashboard from "metabase/entities/dashboards";
import Question from "metabase/entities/questions";
import { BookmarkSchema } from "metabase/schema";
import { BookmarkApi } from "metabase/services";
......@@ -17,6 +20,24 @@ const Bookmarks = createEntity({
return BookmarkApi[type].delete({ id });
},
},
objectSelectors: {
getIcon,
},
});
function getEntityFor(type) {
const entities = {
card: Question,
collection: Collection,
dashboard: Dashboard,
};
return entities[type];
}
export function getIcon(bookmark) {
const bookmarkEntity = getEntityFor(bookmark.type);
return bookmarkEntity.objectSelectors.getIcon(bookmark);
}
export default Bookmarks;
......@@ -152,6 +152,7 @@ export function getCollectionIcon(collection, { tooltip = "default" } = {}) {
}
const authorityLevel =
PLUGIN_COLLECTIONS.AUTHORITY_LEVEL[collection.authority_level];
return authorityLevel
? {
name: authorityLevel.icon,
......
......@@ -79,7 +79,7 @@ const AUTHORITY_LEVEL_REGULAR = {
export const PLUGIN_COLLECTIONS = {
authorityLevelFormFields: [],
isRegularCollection: () => true,
isRegularCollection: (_: any) => true,
REGULAR_COLLECTION: AUTHORITY_LEVEL_REGULAR,
AUTHORITY_LEVEL: {
[JSON.stringify(AUTHORITY_LEVEL_REGULAR.type)]: AUTHORITY_LEVEL_REGULAR,
......
......@@ -8,11 +8,8 @@ describe("Bookmarks in a collection page", () => {
});
it("updates sidebar and bookmark icon color when bookmarking a collection in its page", () => {
cy.request("POST", "/api/bookmark/card/1");
cy.request("POST", "/api/bookmark/card/2");
cy.request("POST", "/api/bookmark/card/3");
cy.request("POST", "/api/bookmark/collection/1");
cy.request("POST", "/api/bookmark/dashboard/1");
createAndBookmarkAnOfficialCollection();
bookmarkExistingItems();
cy.visit("/collection/1");
......@@ -23,3 +20,21 @@ describe("Bookmarks in a collection page", () => {
cy.percySnapshot();
});
});
function createAndBookmarkAnOfficialCollection() {
cy.createCollection({
name: "An official collection",
authority_level: "official",
}).then(response => {
const { id } = response.body;
cy.request("POST", `/api/bookmark/collection/${id}`);
});
}
function bookmarkExistingItems() {
cy.request("POST", "/api/bookmark/card/1");
cy.request("POST", "/api/bookmark/card/2");
cy.request("POST", "/api/bookmark/card/3");
cy.request("POST", "/api/bookmark/collection/1");
cy.request("POST", "/api/bookmark/dashboard/1");
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment