Skip to content
Snippets Groups Projects
Unverified Commit c22021b9 authored by Anton Kulyk's avatar Anton Kulyk Committed by GitHub
Browse files

Support data app bookmarks (#25174)

* Add `app_id` to `Bookmark` type

* Convert `bookmark` URL utility to TypeScript

* Add unit tests for `bookmark` URL utility

* Fix bookmark URL paths

* we shouldn't use "/card" for questions as this path is actually deprecated
* we shouldn't use "card" for models if we can use "/models" from the get go

* Add support for data app bookmark paths

* Highlight bookmarked app when it's open
parent 7713e512
No related branches found
No related tags found
No related merge requests found
......@@ -8,4 +8,10 @@ export interface Bookmark {
item_id: number;
name: string;
type: BookmarkType;
// For questions and models
dataset?: boolean;
// For data app collections
app_id?: number;
}
......@@ -111,6 +111,10 @@ function getIcon(bookmark) {
return bookmarkEntity.objectSelectors.getIcon(bookmark);
}
export function isDataAppBookmark(bookmark) {
return bookmark.type === "collection" && typeof bookmark.app_id === "number";
}
export const getOrderedBookmarks = createSelector(
[Bookmarks.selectors.getList],
bookmarks => _.sortBy(bookmarks, bookmark => bookmark.index),
......
import slugg from "slugg";
import { isDataAppBookmark } from "metabase/entities/bookmarks";
import { Bookmark, DataApp } from "metabase-types/api";
import { dataApp } from "./dataApps";
import { appendSlug } from "./utils";
function getBookmarkBasePath(bookmark: Bookmark) {
if (bookmark.type === "card") {
return bookmark.dataset ? "model" : "question";
}
return bookmark.type;
}
export function bookmark(bookmark: Bookmark) {
const [, itemId] = bookmark.id.split("-");
if (isDataAppBookmark(bookmark)) {
return dataApp(
{ id: bookmark.app_id, collection: { name: bookmark.name } } as DataApp,
{ mode: "preview" },
);
}
const basePath = getBookmarkBasePath(bookmark);
const itemPath = appendSlug(itemId, slugg(bookmark.name));
return `/${basePath}/${itemPath}`;
}
export * from "./admin";
export * from "./bookmarks";
export * from "./browse";
export * from "./collections";
export * from "./dashboards";
......
import slugg from "slugg";
import { dashboard } from "./dashboards";
import { question, dataset, tableRowsQuery } from "./questions";
import { pulse } from "./pulses";
import { appendSlug } from "./utils";
export const exportFormats = ["csv", "xlsx", "json"];
......@@ -11,11 +8,6 @@ export function accountSettings() {
return "/account/profile";
}
export function bookmark({ id, type, name }) {
const [, idInteger] = id.split("-");
return `/${type}/${appendSlug(idInteger, slugg(name))}`;
}
function prepareModel(item) {
if (item.model_object) {
return item.model_object;
......
......@@ -14,7 +14,7 @@ import Tooltip from "metabase/components/Tooltip";
import { Bookmark } from "metabase-types/api";
import { PLUGIN_COLLECTIONS } from "metabase/plugins";
import Bookmarks from "metabase/entities/bookmarks";
import Bookmarks, { isDataAppBookmark } from "metabase/entities/bookmarks";
import * as Urls from "metabase/lib/urls";
import { SelectedItem } from "../types";
......@@ -52,6 +52,20 @@ interface BookmarkItemProps {
const BOOKMARKS_INITIALLY_VISIBLE =
localStorage.getItem("shouldDisplayBookmarks") !== "false";
function isBookmarkSelected(bookmark: Bookmark, selectedItem?: SelectedItem) {
if (!selectedItem) {
return false;
}
if (isDataAppBookmark(bookmark)) {
return (
selectedItem.type === "data-app" && selectedItem.id === bookmark.app_id
);
}
return (
bookmark.type === selectedItem.type && bookmark.item_id === selectedItem.id
);
}
const BookmarkItem = ({
bookmark,
index,
......@@ -60,9 +74,7 @@ const BookmarkItem = ({
onSelect,
onDeleteBookmark,
}: BookmarkItemProps) => {
const { id, item_id, name, type } = bookmark;
const isSelected =
selectedItem && selectedItem.type === type && selectedItem.id === item_id;
const isSelected = isBookmarkSelected(bookmark, selectedItem);
const url = Urls.bookmark(bookmark);
const icon = Bookmarks.objectSelectors.getIcon(bookmark);
const onRemove = () => onDeleteBookmark(bookmark);
......@@ -74,7 +86,7 @@ const BookmarkItem = ({
return (
<SortableBookmarkItem index={index} key={bookmark.id}>
<SidebarBookmarkItem
key={`bookmark-${id}`}
key={`bookmark-${bookmark.id}`}
url={url}
icon={icon}
isSelected={isSelected}
......@@ -90,7 +102,7 @@ const BookmarkItem = ({
</button>
}
>
{name}
{bookmark.name}
</SidebarBookmarkItem>
</SortableBookmarkItem>
);
......
import {
bookmark,
browseDatabase,
collection,
dashboard,
......@@ -269,6 +270,63 @@ describe("urls", () => {
});
});
describe("bookmarks", () => {
it("returns card bookmark path", () => {
expect(
bookmark({
id: "card-5",
dataset: false,
name: "Orders",
type: "card",
}),
).toBe("/question/5-orders");
});
it("returns model bookmark path", () => {
expect(
bookmark({
id: "card-1",
dataset: true,
name: "Product",
type: "card",
}),
).toBe("/model/1-product");
});
it("returns dashboard bookmark path", () => {
expect(
bookmark({
id: "dashboard-3",
name: "Shop Stats",
type: "dashboard",
}),
).toBe("/dashboard/3-shop-stats");
});
it("returns collection bookmark path", () => {
expect(
bookmark({
id: "collection-8",
item_id: 8,
name: "Growth",
type: "collection",
}),
).toBe("/collection/8-growth");
});
it("returns data app bookmark path", () => {
expect(
bookmark({
id: "collection-3",
item_id: 3,
name: "Shop",
type: "collection",
app_id: 14,
}),
).toBe("/apps/14-shop");
});
});
describe("extractEntityId", () => {
const testCases = [
{ slug: "33", id: 33 },
......
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