Skip to content
Snippets Groups Projects
Unverified Commit 73e7b965 authored by Alexander Polyankin's avatar Alexander Polyankin Committed by GitHub
Browse files

Do not show preview settings for pinned models in collections (#24258)

parent e704b2cc
No related branches found
No related tags found
No related merge requests found
Showing
with 174 additions and 92 deletions
export type BookmarkableEntities = "card" | "collection" | "dashboard";
export type BookmarkType = "card" | "collection" | "dashboard";
export interface Bookmark {
authority_level?: string;
......@@ -7,7 +7,5 @@ export interface Bookmark {
id: string;
item_id: number;
name: string;
type: BookmarkableEntities;
type: BookmarkType;
}
export type BookmarksType = Bookmark[];
......@@ -24,3 +24,20 @@ export interface Collection {
originalName?: string;
path?: CollectionId[];
}
export interface CollectionItem {
id: number;
model: string;
name: string;
description: string | null;
copy?: boolean;
collection_position?: number | null;
collection_preview?: boolean | null;
fully_parametrized?: boolean | null;
getIcon: () => { name: string };
getUrl: () => string;
setArchived?: (isArchived: boolean) => void;
setPinned?: (isPinned: boolean) => void;
setCollection?: (collection: Collection) => void;
setCollectionPreview?: (isEnabled: boolean) => void;
}
import { Collection } from "metabase-types/api";
import { Collection, CollectionItem } from "metabase-types/api";
export const createMockCollection = (
opts?: Partial<Collection>,
......@@ -10,3 +10,18 @@ export const createMockCollection = (
archived: false,
...opts,
});
export const createMockCollectionItem = (
opts?: Partial<CollectionItem>,
): CollectionItem => ({
id: 1,
model: "card",
name: "Question",
description: null,
collection_position: null,
collection_preview: true,
fully_parametrized: true,
getIcon: () => ({ name: "card" }),
getUrl: () => "/question/1",
...opts,
});
import React, { useCallback } from "react";
import { Collection } from "metabase-types/api";
import { Bookmark, Collection, CollectionItem } from "metabase-types/api";
import { ANALYTICS_CONTEXT } from "metabase/collections/constants";
import {
isFullyParametrized,
isItemPinned,
isPreviewShown,
isItemQuestion,
isPreviewEnabled,
Item,
isPreviewShown,
} from "metabase/collections/utils";
import EventSandbox from "metabase/components/EventSandbox";
import { EntityItemMenu } from "./ActionMenu.styled";
import { BookmarksType } from "metabase-types/api/bookmark";
interface ActionMenuProps {
export interface ActionMenuProps {
className?: string;
item: Item;
item: CollectionItem;
collection: Collection;
bookmarks?: BookmarksType;
onCopy: (items: Item[]) => void;
onMove: (items: Item[]) => void;
bookmarks?: Bookmark[];
onCopy: (items: CollectionItem[]) => void;
onMove: (items: CollectionItem[]) => void;
createBookmark?: (id: string, collection: string) => void;
deleteBookmark?: (id: string, collection: string) => void;
}
function getIsBookmarked(item: Item, bookmarks: BookmarksType) {
function getIsBookmarked(item: CollectionItem, bookmarks: Bookmark[]) {
const normalizedItemModel = normalizeItemModel(item);
return bookmarks.some(
......@@ -36,7 +35,7 @@ function getIsBookmarked(item: Item, bookmarks: BookmarksType) {
// If item.model is `dataset`, that is, this is a Model in a product sense,
// let’s call it "card" because `card` and `dataset` are treated the same in the back-end.
function normalizeItemModel(item: Item) {
function normalizeItemModel(item: CollectionItem) {
return item.model === "dataset" ? "card" : item.model;
}
......@@ -52,10 +51,10 @@ function ActionMenu({
}: ActionMenuProps) {
const isBookmarked = bookmarks && getIsBookmarked(item, bookmarks);
const isPreviewOptionShown =
isItemPinned(item) && collection.can_write && item.setCollectionPreview;
isItemPinned(item) && isItemQuestion(item) && collection.can_write;
const handlePin = useCallback(() => {
item.setPinned(!isItemPinned(item));
item.setPinned?.(!isItemPinned(item));
}, [item]);
const handleCopy = useCallback(() => {
......@@ -67,7 +66,7 @@ function ActionMenu({
}, [item, onMove]);
const handleArchive = useCallback(() => {
item.setArchived(true);
item.setArchived?.(true);
}, [item]);
const handleToggleBookmark = useCallback(() => {
......
import React from "react";
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import {
createMockCollection,
createMockCollectionItem,
} from "metabase-types/api/mocks";
import ActionMenu, { ActionMenuProps } from "./ActionMenu";
describe("ActionMenu", () => {
it("should show an option to hide preview for a pinned question", () => {
const props = getProps({
item: createMockCollectionItem({
model: "card",
collection_position: 1,
collection_preview: true,
setCollectionPreview: jest.fn(),
}),
collection: createMockCollection({
can_write: true,
}),
});
render(<ActionMenu {...props} />);
userEvent.click(screen.getByLabelText("ellipsis icon"));
userEvent.click(screen.getByText("Don’t show visualization"));
expect(props.item.setCollectionPreview).toHaveBeenCalledWith(false);
});
it("should show an option to show preview for a pinned question", () => {
const props = getProps({
item: createMockCollectionItem({
model: "card",
collection_position: 1,
collection_preview: false,
setCollectionPreview: jest.fn(),
}),
collection: createMockCollection({
can_write: true,
}),
});
render(<ActionMenu {...props} />);
userEvent.click(screen.getByLabelText("ellipsis icon"));
userEvent.click(screen.getByText("Show visualization"));
expect(props.item.setCollectionPreview).toHaveBeenCalledWith(true);
});
it("should not show an option to hide preview for a pinned model", () => {
const props = getProps({
item: createMockCollectionItem({
model: "model",
collection_position: 1,
setCollectionPreview: jest.fn(),
}),
collection: createMockCollection({
can_write: true,
}),
});
render(<ActionMenu {...props} />);
userEvent.click(screen.getByLabelText("ellipsis icon"));
expect(
screen.queryByText("Don’t show visualization"),
).not.toBeInTheDocument();
});
});
const getProps = (opts?: Partial<ActionMenuProps>): ActionMenuProps => ({
item: createMockCollectionItem(),
collection: createMockCollection(),
onCopy: jest.fn(),
onMove: jest.fn(),
...opts,
});
import React, { useState } from "react";
import { t } from "ttag";
import { BookmarksType, Collection } from "metabase-types/api";
import Tooltip from "metabase/components/Tooltip";
import { Item } from "metabase/collections/utils";
import { Bookmark, Collection, CollectionItem } from "metabase-types/api";
import {
ItemLink,
ItemCard,
Header,
Body,
ItemIcon,
Title,
Description,
Header,
HoverMenu,
ItemCard,
ItemIcon,
ItemLink,
Title,
} from "./PinnedItemCard.styled";
type Props = {
bookmarks?: BookmarksType;
bookmarks?: Bookmark[];
createBookmark: (id: string, collection: string) => void;
deleteBookmark: (id: string, collection: string) => void;
className?: string;
item: Item;
item: CollectionItem;
collection: Collection;
onCopy: (items: Item[]) => void;
onMove: (items: Item[]) => void;
onCopy: (items: CollectionItem[]) => void;
onMove: (items: CollectionItem[]) => void;
};
const TOOLTIP_MAX_WIDTH = 450;
......
......@@ -2,17 +2,13 @@ import React from "react";
import _ from "underscore";
import { t } from "ttag";
import { BookmarksType, Collection } from "metabase-types/api";
import { Bookmark, Collection, CollectionItem } from "metabase-types/api";
import Metadata from "metabase-lib/lib/metadata/Metadata";
import PinnedItemCard from "metabase/collections/components/PinnedItemCard";
import PinnedQuestionCard from "metabase/collections/components/PinnedQuestionCard";
import PinnedItemSortDropTarget from "metabase/collections/components/PinnedItemSortDropTarget";
import {
Item,
isRootCollection,
isPreviewShown,
} from "metabase/collections/utils";
import { isPreviewShown, isRootCollection } from "metabase/collections/utils";
import PinDropZone from "metabase/collections/components/PinDropZone";
import ItemDragSource from "metabase/containers/dnd/ItemDragSource";
......@@ -24,14 +20,14 @@ import {
} from "./PinnedItemOverview.styled";
type Props = {
bookmarks?: BookmarksType;
bookmarks?: Bookmark[];
createBookmark: (id: string, collection: string) => void;
deleteBookmark: (id: string, collection: string) => void;
items: Item[];
items: CollectionItem[];
collection: Collection;
metadata: Metadata;
onCopy: (items: Item[]) => void;
onMove: (items: Item[]) => void;
onCopy: (items: CollectionItem[]) => void;
onMove: (items: CollectionItem[]) => void;
};
function PinnedItemOverview({
......
......@@ -3,11 +3,10 @@ import { t } from "ttag";
import {
isFullyParametrized,
isPreviewShown,
Item,
} from "metabase/collections/utils";
import Visualization from "metabase/visualizations/components/Visualization";
import Metadata from "metabase-lib/lib/metadata/Metadata";
import { Bookmark, Collection } from "metabase-types/api";
import { Bookmark, Collection, CollectionItem } from "metabase-types/api";
import PinnedQuestionLoader from "./PinnedQuestionLoader";
import {
CardActionMenu,
......@@ -17,12 +16,12 @@ import {
} from "./PinnedQuestionCard.styled";
export interface PinnedQuestionCardProps {
item: Item;
item: CollectionItem;
collection: Collection;
metadata: Metadata;
bookmarks?: Bookmark[];
onCopy: (items: Item[]) => void;
onMove: (items: Item[]) => void;
onCopy: (items: CollectionItem[]) => void;
onMove: (items: CollectionItem[]) => void;
onCreateBookmark?: (id: string, model: string) => void;
onDeleteBookmark?: (id: string, model: string) => void;
}
......@@ -82,7 +81,7 @@ const PinnedQuestionCard = ({
);
};
const getSkeletonTooltip = (item: Item) => {
const getSkeletonTooltip = (item: CollectionItem) => {
if (!isFullyParametrized(item)) {
return t`Open this question and fill in its variables to see it.`;
} else {
......
import { t } from "ttag";
import { Collection } from "metabase-types/api";
export type Item = {
id: number;
model: string;
name: string;
description: string | null;
copy?: boolean;
collection_position?: number | null;
collection_preview?: boolean | null;
fully_parametrized?: boolean | null;
getIcon: () => { name: string };
getUrl: () => string;
setArchived: (isArchived: boolean) => void;
setPinned: (isPinned: boolean) => void;
setCollection?: (collection: Collection) => void;
setCollectionPreview?: (isEnabled: boolean) => void;
};
import { Collection, CollectionItem } from "metabase-types/api";
export function nonPersonalOrArchivedCollection(
collection: Collection,
......@@ -76,19 +59,23 @@ export function isRootCollection(collection: Collection): boolean {
return collection.id === "root";
}
export function isItemPinned(item: Item) {
export function isItemPinned(item: CollectionItem) {
return item.collection_position != null;
}
export function isPreviewShown(item: Item) {
export function isItemQuestion(item: CollectionItem) {
return item.model === "card";
}
export function isPreviewShown(item: CollectionItem) {
return isPreviewEnabled(item) && isFullyParametrized(item);
}
export function isPreviewEnabled(item: Item) {
export function isPreviewEnabled(item: CollectionItem) {
return item.collection_preview ?? true;
}
export function isFullyParametrized(item: Item) {
export function isFullyParametrized(item: CollectionItem) {
return item.fully_parametrized ?? true;
}
......
......@@ -12,7 +12,7 @@ import CollapseSection from "metabase/components/CollapseSection";
import Icon from "metabase/components/Icon";
import Tooltip from "metabase/components/Tooltip";
import { Bookmark, BookmarksType } from "metabase-types/api";
import { Bookmark } from "metabase-types/api";
import { PLUGIN_COLLECTIONS } from "metabase/plugins";
import Bookmarks from "metabase/entities/bookmarks";
import * as Urls from "metabase/lib/urls";
......@@ -27,7 +27,7 @@ const mapDispatchToProps = {
};
interface CollectionSidebarBookmarksProps {
bookmarks: BookmarksType;
bookmarks: Bookmark[];
selectedItem?: SelectedItem;
onSelect: () => void;
onDeleteBookmark: (bookmark: Bookmark) => void;
......
......@@ -10,35 +10,29 @@ import Modal from "metabase/components/Modal";
import LoadingSpinner from "metabase/components/LoadingSpinner";
import Question from "metabase-lib/lib/Question";
import {
Bookmark,
BookmarksType,
Collection,
Dashboard,
User,
} from "metabase-types/api";
import { Bookmark, Collection, Dashboard, User } from "metabase-types/api";
import { State } from "metabase-types/store";
import Bookmarks, { getOrderedBookmarks } from "metabase/entities/bookmarks";
import Collections, {
ROOT_COLLECTION,
getCollectionIcon,
buildCollectionTree,
getCollectionIcon,
ROOT_COLLECTION,
} from "metabase/entities/collections";
import { openNavbar, closeNavbar } from "metabase/redux/app";
import { closeNavbar, openNavbar } from "metabase/redux/app";
import { logout } from "metabase/auth/actions";
import { getUserIsAdmin, getUser } from "metabase/selectors/user";
import { getUser, getUserIsAdmin } from "metabase/selectors/user";
import {
getHasOwnDatabase,
getHasDataAccess,
getHasOwnDatabase,
} from "metabase/new_query/selectors";
import { getQuestion } from "metabase/query_builder/selectors";
import { getDashboard } from "metabase/dashboard/selectors";
import {
nonPersonalOrArchivedCollection,
currentUserPersonalCollections,
coerceCollectionId,
currentUserPersonalCollections,
nonPersonalOrArchivedCollection,
} from "metabase/collections/utils";
import * as Urls from "metabase/lib/urls";
......@@ -47,10 +41,10 @@ import CollectionCreate from "metabase/collections/containers/CollectionCreate";
import { SelectedItem } from "./types";
import MainNavbarView from "./MainNavbarView";
import {
Sidebar,
NavRoot,
LoadingContainer,
LoadingTitle,
NavRoot,
Sidebar,
} from "./MainNavbar.styled";
type NavbarModal = "MODAL_NEW_COLLECTION" | null;
......@@ -84,7 +78,7 @@ type Props = {
isOpen: boolean;
isAdmin: boolean;
currentUser: User;
bookmarks: BookmarksType;
bookmarks: Bookmark[];
collections: Collection[];
rootCollection: Collection;
question?: Question;
......
......@@ -2,7 +2,7 @@ import React, { useCallback } from "react";
import { t } from "ttag";
import _ from "underscore";
import { BookmarksType, Collection, User } from "metabase-types/api";
import { Bookmark, Collection, User } from "metabase-types/api";
import { IconProps } from "metabase/components/Icon";
import { Tree } from "metabase/components/tree";
......@@ -21,14 +21,14 @@ import { SidebarCollectionLink, SidebarLink } from "./SidebarItems";
import {
AddYourOwnDataLink,
BrowseLink,
CollectionsMoreIconContainer,
CollectionsMoreIcon,
CollectionMenuList,
CollectionsMoreIcon,
CollectionsMoreIconContainer,
HomePageLink,
SidebarContentRoot,
SidebarHeading,
SidebarSection,
SidebarHeadingWrapper,
SidebarSection,
} from "./MainNavbar.styled";
interface CollectionTreeItem extends Collection {
......@@ -40,7 +40,7 @@ type Props = {
isAdmin: boolean;
isOpen: boolean;
currentUser: User;
bookmarks: BookmarksType;
bookmarks: Bookmark[];
hasDataAccess: boolean;
hasOwnDatabase: boolean;
collections: CollectionTreeItem[];
......
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