From 839b713f50e2c1696923dc3e1cf0b5091537272f Mon Sep 17 00:00:00 2001 From: Denis Berezin <denis.berezin@metabase.com> Date: Tue, 5 Nov 2024 19:23:14 +0300 Subject: [PATCH] feat(sdk): Allow to hide columns in CollectionBrowser (#49449) * Add possibility to hide columns in CollectionBrowser * Add tests * Review fixes * Fix e2e --- .../CollectionBrowser.stories.tsx | 32 +++++++ .../CollectionBrowser/CollectionBrowser.tsx | 17 +++- .../CollectionBrowser.unit.spec.tsx | 96 +++++++++++++++++++ .../test/server-mocks/sdk-init.ts | 2 +- .../CollectionContentView.tsx | 15 ++- .../CollectionItemsTable.tsx | 22 ++++- .../components/CollectionContent/constants.ts | 24 +++++ .../ItemsTable/BaseItemTableRow.tsx | 10 +- .../BaseItemsTable/BaseItemsTable.tsx | 65 +++++++------ .../BaseItemsTable.unit.spec.tsx | 5 + .../BaseItemsTableBody/BaseItemsTableBody.tsx | 6 +- .../ItemsTable/DefaultItemRenderer.tsx | 38 +++++--- .../metabase/components/ItemsTable/utils.ts | 12 +++ .../containers/dnd/ItemsDragLayer.jsx | 5 +- 14 files changed, 291 insertions(+), 58 deletions(-) create mode 100644 enterprise/frontend/src/embedding-sdk/components/public/CollectionBrowser/CollectionBrowser.stories.tsx create mode 100644 enterprise/frontend/src/embedding-sdk/components/public/CollectionBrowser/CollectionBrowser.unit.spec.tsx diff --git a/enterprise/frontend/src/embedding-sdk/components/public/CollectionBrowser/CollectionBrowser.stories.tsx b/enterprise/frontend/src/embedding-sdk/components/public/CollectionBrowser/CollectionBrowser.stories.tsx new file mode 100644 index 00000000000..4207a2be5d0 --- /dev/null +++ b/enterprise/frontend/src/embedding-sdk/components/public/CollectionBrowser/CollectionBrowser.stories.tsx @@ -0,0 +1,32 @@ +import type { StoryFn } from "@storybook/react"; +import type { ComponentProps } from "react"; + +import { CollectionBrowser } from "embedding-sdk"; +import { CommonSdkStoryWrapper } from "embedding-sdk/test/CommonSdkStoryWrapper"; + +export default { + title: "EmbeddingSDK/CollectionBrowser", + component: CollectionBrowser, + parameters: { + layout: "fullscreen", + }, + decorators: [CommonSdkStoryWrapper], +}; + +const Template: StoryFn<ComponentProps<typeof CollectionBrowser>> = args => { + return <CollectionBrowser {...args} />; +}; + +export const Default = { + render: Template, + + args: {}, +}; + +export const WithTypeAndNameColumn = { + render: Template, + + args: { + visibleColumns: ["type", "name"], + }, +}; diff --git a/enterprise/frontend/src/embedding-sdk/components/public/CollectionBrowser/CollectionBrowser.tsx b/enterprise/frontend/src/embedding-sdk/components/public/CollectionBrowser/CollectionBrowser.tsx index 8ce98b4b34f..407f95052eb 100644 --- a/enterprise/frontend/src/embedding-sdk/components/public/CollectionBrowser/CollectionBrowser.tsx +++ b/enterprise/frontend/src/embedding-sdk/components/public/CollectionBrowser/CollectionBrowser.tsx @@ -23,6 +23,19 @@ const USER_FACING_ENTITY_NAMES = [ type UserFacingEntityName = (typeof USER_FACING_ENTITY_NAMES)[number]; +type CollectionBrowserListColumns = + | "type" + | "name" + | "lastEditedBy" + | "lastEditedAt"; + +const COLLECTION_BROWSER_LIST_COLUMNS: CollectionBrowserListColumns[] = [ + "type", + "name", + "lastEditedBy", + "lastEditedAt", +]; + const ENTITY_NAME_MAP: Partial< Record<UserFacingEntityName, CollectionItemModel> > = { @@ -38,6 +51,7 @@ type CollectionBrowserProps = { pageSize?: number; visibleEntityTypes?: UserFacingEntityName[]; EmptyContentComponent?: ComponentType | null; + visibleColumns?: CollectionBrowserListColumns[]; className?: string; style?: CSSProperties; }; @@ -48,6 +62,7 @@ export const CollectionBrowserInner = ({ pageSize = COLLECTION_PAGE_SIZE, visibleEntityTypes = [...USER_FACING_ENTITY_NAMES], EmptyContentComponent = null, + visibleColumns = COLLECTION_BROWSER_LIST_COLUMNS, className, style, }: CollectionBrowserProps) => { @@ -85,7 +100,7 @@ export const CollectionBrowserInner = ({ onClick={onClickItem} pageSize={pageSize} models={collectionTypes} - showActionMenu={false} + visibleColumns={visibleColumns} EmptyContentComponent={EmptyContentComponent ?? undefined} /> </Stack> diff --git a/enterprise/frontend/src/embedding-sdk/components/public/CollectionBrowser/CollectionBrowser.unit.spec.tsx b/enterprise/frontend/src/embedding-sdk/components/public/CollectionBrowser/CollectionBrowser.unit.spec.tsx new file mode 100644 index 00000000000..07632d87091 --- /dev/null +++ b/enterprise/frontend/src/embedding-sdk/components/public/CollectionBrowser/CollectionBrowser.unit.spec.tsx @@ -0,0 +1,96 @@ +import type { ComponentProps } from "react"; + +import { + setupCollectionItemsEndpoint, + setupCollectionsEndpoints, +} from "__support__/server-mocks"; +import { renderWithProviders, screen, within } from "__support__/ui"; +import { CollectionBrowserInner } from "embedding-sdk/components/public/CollectionBrowser/CollectionBrowser"; +import { createMockJwtConfig } from "embedding-sdk/test/mocks/config"; +import { setupSdkState } from "embedding-sdk/test/server-mocks/sdk-init"; +import { ROOT_COLLECTION } from "metabase/entities/collections"; +import { + createMockCollection, + createMockCollectionItem, +} from "metabase-types/api/mocks"; + +const BOBBY_TEST_COLLECTION = createMockCollection({ + archived: false, + can_write: true, + description: null, + id: 1, + location: "/", + name: "Bobby Tables's Personal Collection", + personal_owner_id: 100, +}); + +const ROOT_TEST_COLLECTION = createMockCollection({ + ...ROOT_COLLECTION, + can_write: false, + effective_ancestors: [], + id: "root", +}); + +const TEST_COLLECTIONS = [ROOT_TEST_COLLECTION, BOBBY_TEST_COLLECTION]; + +describe("CollectionBrowser", () => { + it("should render", async () => { + await setup(); + + expect(screen.getByText("Type")).toBeInTheDocument(); + expect(screen.getByText("Name")).toBeInTheDocument(); + expect(screen.getByText("Last edited by")).toBeInTheDocument(); + expect(screen.getByText("Last edited at")).toBeInTheDocument(); + }); + + it("should allow to hide certain columns", async () => { + await setup({ + props: { + visibleColumns: ["type", "name"], + }, + }); + + const columnNames: (string | null)[] = []; + + within(screen.getByTestId("items-table-head")) + .getAllByRole("button") + .forEach(el => { + columnNames.push(el.textContent); + }); + + expect(columnNames).toStrictEqual(["Type", "Name"]); + }); +}); + +async function setup({ + props, +}: { + props?: Partial<ComponentProps<typeof CollectionBrowserInner>>; +} = {}) { + setupCollectionsEndpoints({ + collections: TEST_COLLECTIONS, + rootCollection: ROOT_TEST_COLLECTION, + }); + + setupCollectionItemsEndpoint({ + collection: ROOT_TEST_COLLECTION, + collectionItems: [ + createMockCollectionItem({ id: 2, model: "dashboard" }), + createMockCollectionItem({ id: 3, model: "card" }), + ], + }); + + const state = setupSdkState(); + + renderWithProviders(<CollectionBrowserInner {...props} />, { + mode: "sdk", + sdkProviderProps: { + config: createMockJwtConfig({ + jwtProviderUri: "http://TEST_URI/sso/metabase", + }), + }, + storeInitialState: state, + }); + + expect(await screen.findByTestId("collection-table")).toBeInTheDocument(); +} diff --git a/enterprise/frontend/src/embedding-sdk/test/server-mocks/sdk-init.ts b/enterprise/frontend/src/embedding-sdk/test/server-mocks/sdk-init.ts index 669d0b332fc..b8fe8f7a1d2 100644 --- a/enterprise/frontend/src/embedding-sdk/test/server-mocks/sdk-init.ts +++ b/enterprise/frontend/src/embedding-sdk/test/server-mocks/sdk-init.ts @@ -37,7 +37,7 @@ export const setupSdkState = ({ tokenFeatures?: TokenFeatures; settingDefinitions?: SettingDefinition[]; sdkState?: SdkState; -} & Partial<SdkStoreState>) => { +} & Partial<SdkStoreState> = {}) => { const settingValuesWithToken = { ...settingValues, "token-features": tokenFeatures, diff --git a/frontend/src/metabase/collections/components/CollectionContent/CollectionContentView.tsx b/frontend/src/metabase/collections/components/CollectionContent/CollectionContentView.tsx index 795859eaeee..f328ccc398c 100644 --- a/frontend/src/metabase/collections/components/CollectionContent/CollectionContentView.tsx +++ b/frontend/src/metabase/collections/components/CollectionContent/CollectionContentView.tsx @@ -1,4 +1,4 @@ -import { useCallback, useEffect, useState } from "react"; +import { useCallback, useEffect, useMemo, useState } from "react"; import { useDropzone } from "react-dropzone"; import { usePrevious } from "react-use"; import { t } from "ttag"; @@ -7,6 +7,10 @@ import ErrorBoundary from "metabase/ErrorBoundary"; import { deletePermanently } from "metabase/archive/actions"; import { ArchivedEntityBanner } from "metabase/archive/components/ArchivedEntityBanner"; import { CollectionBulkActions } from "metabase/collections/components/CollectionBulkActions"; +import { + type CollectionContentTableColumn, + DEFAULT_VISIBLE_COLUMNS_LIST, +} from "metabase/collections/components/CollectionContent/constants"; import PinnedItemOverview from "metabase/collections/components/PinnedItemOverview"; import Header from "metabase/collections/containers/CollectionHeader"; import type { @@ -20,6 +24,7 @@ import { isRootTrashCollection, isTrashedCollection, } from "metabase/collections/utils"; +import { getVisibleColumnsMap } from "metabase/components/ItemsTable/utils"; import ItemsDragLayer from "metabase/containers/dnd/ItemsDragLayer"; import Bookmarks from "metabase/entities/bookmarks"; import Collections from "metabase/entities/collections"; @@ -58,6 +63,7 @@ export const CollectionContentView = ({ uploadFile, uploadsEnabled, canCreateUploadInDb, + visibleColumns = DEFAULT_VISIBLE_COLUMNS_LIST, }: { databases?: Database[]; bookmarks?: Bookmark[]; @@ -70,6 +76,7 @@ export const CollectionContentView = ({ uploadFile: UploadFile; uploadsEnabled: boolean; canCreateUploadInDb: boolean; + visibleColumns?: CollectionContentTableColumn[]; }) => { const [isBookmarked, setIsBookmarked] = useState(false); const [selectedItems, setSelectedItems] = useState<CollectionItem[] | null>( @@ -122,6 +129,11 @@ export const CollectionContentView = ({ const dispatch = useDispatch(); + const visibleColumnsMap = useMemo( + () => getVisibleColumnsMap(visibleColumns), + [visibleColumns], + ); + const onDrop = (acceptedFiles: File[]) => { if (!acceptedFiles.length) { dispatch( @@ -299,6 +311,7 @@ export const CollectionContentView = ({ selectedItems={selected} pinnedItems={pinnedItems} collection={collection} + visibleColumnsMap={visibleColumnsMap} /> </CollectionRoot> ); diff --git a/frontend/src/metabase/collections/components/CollectionContent/CollectionItemsTable.tsx b/frontend/src/metabase/collections/components/CollectionContent/CollectionItemsTable.tsx index 72d6ee3d4f2..c7bf39a3faa 100644 --- a/frontend/src/metabase/collections/components/CollectionContent/CollectionItemsTable.tsx +++ b/frontend/src/metabase/collections/components/CollectionContent/CollectionItemsTable.tsx @@ -1,10 +1,18 @@ /* eslint-disable react/prop-types */ import cx from "classnames"; -import { type ComponentType, useCallback, useEffect, useState } from "react"; +import { + type ComponentType, + useCallback, + useEffect, + useMemo, + useState, +} from "react"; import { ALL_MODELS, COLLECTION_PAGE_SIZE, + type CollectionContentTableColumn, + DEFAULT_VISIBLE_COLUMNS_LIST, } from "metabase/collections/components/CollectionContent/constants"; import CollectionEmptyState from "metabase/collections/components/CollectionEmptyState"; import type { @@ -13,6 +21,7 @@ import type { } from "metabase/collections/types"; import { isRootTrashCollection } from "metabase/collections/utils"; import { ItemsTable } from "metabase/components/ItemsTable"; +import { getVisibleColumnsMap } from "metabase/components/ItemsTable/utils"; import { PaginationControls } from "metabase/components/PaginationControls"; import CS from "metabase/css/core/index.css"; import Search from "metabase/entities/search"; @@ -68,7 +77,7 @@ export type CollectionItemsTableProps = { selected: CollectionItem[]; toggleItem: (item: CollectionItem) => void; onClick: (item: CollectionItem) => void; - showActionMenu: boolean; + visibleColumns?: CollectionContentTableColumn[]; EmptyContentComponent?: ComponentType<{ collection?: Collection; }>; @@ -105,7 +114,7 @@ export const CollectionItemsTable = ({ pageSize = COLLECTION_PAGE_SIZE, models = ALL_MODELS, onClick, - showActionMenu = true, + visibleColumns = DEFAULT_VISIBLE_COLUMNS_LIST, EmptyContentComponent = DefaultEmptyContentComponent, }: CollectionItemsTableProps) => { const isEmbeddingSdk = useSelector(getIsEmbeddingSdk); @@ -118,6 +127,11 @@ export const CollectionItemsTable = ({ const { handleNextPage, handlePreviousPage, setPage, page, resetPage } = usePagination(); + const visibleColumnsMap = useMemo( + () => getVisibleColumnsMap(visibleColumns), + [visibleColumns], + ); + useEffect(() => { if (collectionId) { resetPage(); @@ -208,7 +222,7 @@ export const CollectionItemsTable = ({ onSelectAll={handleSelectAll} onSelectNone={clear} onClick={onClick} - showActionMenu={showActionMenu} + visibleColumnsMap={visibleColumnsMap} /> <div className={cx(CS.flex, CS.justifyEnd, CS.my3)}> {hasPagination && ( diff --git a/frontend/src/metabase/collections/components/CollectionContent/constants.ts b/frontend/src/metabase/collections/components/CollectionContent/constants.ts index 90f16158432..f40cde096b4 100644 --- a/frontend/src/metabase/collections/components/CollectionContent/constants.ts +++ b/frontend/src/metabase/collections/components/CollectionContent/constants.ts @@ -1,6 +1,30 @@ import type { CollectionItemModel } from "metabase-types/api"; export const COLLECTION_PAGE_SIZE = 25; + +export const COLLECTION_CONTENT_COLUMNS = [ + "type", + "name", + "lastEditedBy", + "lastEditedAt", + "actionMenu", +] as const; + +export type CollectionContentTableColumn = + (typeof COLLECTION_CONTENT_COLUMNS)[number]; + +export type CollectionContentTableColumnsMap = { + [key in CollectionContentTableColumn]: true; +}; + +export const DEFAULT_VISIBLE_COLUMNS_LIST: CollectionContentTableColumn[] = [ + "type", + "name", + "lastEditedBy", + "lastEditedAt", + "actionMenu", +]; + export const ALL_MODELS: CollectionItemModel[] = [ "dashboard", "dataset", diff --git a/frontend/src/metabase/components/ItemsTable/BaseItemTableRow.tsx b/frontend/src/metabase/components/ItemsTable/BaseItemTableRow.tsx index 698ffa04b9f..5dbd0eb66e3 100644 --- a/frontend/src/metabase/components/ItemsTable/BaseItemTableRow.tsx +++ b/frontend/src/metabase/components/ItemsTable/BaseItemTableRow.tsx @@ -28,7 +28,7 @@ type BaseItemTableRowProps = PropsWithChildren< | "onMove" | "onToggleSelected" | "onClick" - | "showActionMenu" + | "visibleColumnsMap" > >; @@ -48,7 +48,7 @@ export const TableRow = ({ itemKey, collection, onClick, - showActionMenu, + visibleColumnsMap, }: BaseItemTableRowProps) => ( <tr key={itemKey} data-testid={testIdPrefix} style={{ height: 48 }}> <ItemComponent @@ -65,7 +65,7 @@ export const TableRow = ({ onCopy={onCopy} onMove={onMove} onToggleSelected={onToggleSelected} - showActionMenu={showActionMenu} + visibleColumnsMap={visibleColumnsMap} /> </tr> ); @@ -88,7 +88,7 @@ export const ItemDragSourceTableRow = ({ onClick, selectedItems, onDrop, - showActionMenu, + visibleColumnsMap, }: BaseItemTableRowProps) => { return ( <ItemDragSource @@ -115,7 +115,7 @@ export const ItemDragSourceTableRow = ({ onMove={onMove} onToggleSelected={onToggleSelected} onClick={onClick} - showActionMenu={showActionMenu} + visibleColumnsMap={visibleColumnsMap} /> </tr> </ItemDragSource> diff --git a/frontend/src/metabase/components/ItemsTable/BaseItemsTable/BaseItemsTable.tsx b/frontend/src/metabase/components/ItemsTable/BaseItemsTable/BaseItemsTable.tsx index ad4c20af8d3..1c95a75c8e2 100644 --- a/frontend/src/metabase/components/ItemsTable/BaseItemsTable/BaseItemsTable.tsx +++ b/frontend/src/metabase/components/ItemsTable/BaseItemsTable/BaseItemsTable.tsx @@ -1,6 +1,7 @@ import type { HTMLAttributes, PropsWithChildren } from "react"; import { useMemo } from "react"; +import type { CollectionContentTableColumnsMap } from "metabase/collections/components/CollectionContent"; import type { CreateBookmark, DeleteBookmark, @@ -119,7 +120,7 @@ export type BaseItemsTableProps = { ItemComponent?: (props: ItemRendererProps) => JSX.Element; includeColGroup?: boolean; onClick?: (item: CollectionItem) => void; - showActionMenu?: boolean; + visibleColumnsMap: CollectionContentTableColumnsMap; } & Partial<Omit<HTMLAttributes<HTMLTableElement>, "onCopy" | "onClick">>; export const BaseItemsTable = ({ @@ -145,7 +146,7 @@ export const BaseItemsTable = ({ isInDragLayer = false, ItemComponent = DefaultItemRenderer, includeColGroup = true, - showActionMenu = true, + visibleColumnsMap, onClick, ...props }: BaseItemsTableProps) => { @@ -158,11 +159,13 @@ export const BaseItemsTable = ({ {includeColGroup && ( <colgroup> {canSelect && <Columns.Select.Col />} - <Columns.Type.Col /> - <Columns.Name.Col isInDragLayer={isInDragLayer} /> - <Columns.LastEditedBy.Col /> - <Columns.LastEditedAt.Col /> - {showActionMenu && <Columns.ActionMenu.Col />} + {visibleColumnsMap["type"] && <Columns.Type.Col />} + {visibleColumnsMap["name"] && ( + <Columns.Name.Col isInDragLayer={isInDragLayer} /> + )} + {visibleColumnsMap["lastEditedBy"] && <Columns.LastEditedBy.Col />} + {visibleColumnsMap["lastEditedAt"] && <Columns.LastEditedAt.Col />} + {visibleColumnsMap["actionMenu"] && <Columns.ActionMenu.Col />} <Columns.RightEdge.Col /> </colgroup> )} @@ -181,25 +184,33 @@ export const BaseItemsTable = ({ onSelectNone={onSelectNone} /> )} - <Columns.Type.Header - sortingOptions={sortingOptions} - onSortingOptionsChange={onSortingOptionsChange} - /> - <Columns.Name.Header - sortingOptions={sortingOptions} - onSortingOptionsChange={onSortingOptionsChange} - /> - <Columns.LastEditedBy.Header - sortingOptions={sortingOptions} - onSortingOptionsChange={onSortingOptionsChange} - isTrashed={isTrashed} - /> - <Columns.LastEditedAt.Header - sortingOptions={sortingOptions} - onSortingOptionsChange={onSortingOptionsChange} - isTrashed={isTrashed} - /> - {showActionMenu && <Columns.ActionMenu.Header />} + {visibleColumnsMap["type"] && ( + <Columns.Type.Header + sortingOptions={sortingOptions} + onSortingOptionsChange={onSortingOptionsChange} + /> + )} + {visibleColumnsMap["name"] && ( + <Columns.Name.Header + sortingOptions={sortingOptions} + onSortingOptionsChange={onSortingOptionsChange} + /> + )} + {visibleColumnsMap["lastEditedBy"] && ( + <Columns.LastEditedBy.Header + sortingOptions={sortingOptions} + onSortingOptionsChange={onSortingOptionsChange} + isTrashed={isTrashed} + /> + )} + {visibleColumnsMap["lastEditedAt"] && ( + <Columns.LastEditedAt.Header + sortingOptions={sortingOptions} + onSortingOptionsChange={onSortingOptionsChange} + isTrashed={isTrashed} + /> + )} + {visibleColumnsMap["actionMenu"] && <Columns.ActionMenu.Header />} <Columns.RightEdge.Header /> </tr> </thead> @@ -220,7 +231,7 @@ export const BaseItemsTable = ({ onMove={onMove} onToggleSelected={onToggleSelected} onClick={onClick} - showActionMenu={showActionMenu} + visibleColumnsMap={visibleColumnsMap} /> </Table> ); diff --git a/frontend/src/metabase/components/ItemsTable/BaseItemsTable/BaseItemsTable.unit.spec.tsx b/frontend/src/metabase/components/ItemsTable/BaseItemsTable/BaseItemsTable.unit.spec.tsx index b2121be4d56..979d6c8e0e3 100644 --- a/frontend/src/metabase/components/ItemsTable/BaseItemsTable/BaseItemsTable.unit.spec.tsx +++ b/frontend/src/metabase/components/ItemsTable/BaseItemsTable/BaseItemsTable.unit.spec.tsx @@ -3,6 +3,8 @@ import moment from "moment-timezone"; // eslint-disable-line no-restricted-impor import { Route } from "react-router"; import { getIcon, renderWithProviders, screen } from "__support__/ui"; +import { DEFAULT_VISIBLE_COLUMNS_LIST } from "metabase/collections/components/CollectionContent"; +import { getVisibleColumnsMap } from "metabase/components/ItemsTable/utils"; import type { ItemWithLastEditInfo } from "metabase/components/LastEditInfoLabel/LastEditInfoLabel"; import { DEFAULT_DATE_STYLE, @@ -53,6 +55,8 @@ function getCollectionItem({ }; } +const VISIBLE_COLUMNS_MAP = getVisibleColumnsMap(DEFAULT_VISIBLE_COLUMNS_LIST); + describe("BaseItemsTable", () => { const ITEM = getCollectionItem(); @@ -71,6 +75,7 @@ describe("BaseItemsTable", () => { sort_direction: SortDirection.Asc, }} onSortingOptionsChange={jest.fn()} + visibleColumnsMap={VISIBLE_COLUMNS_MAP} {...props} /> )} diff --git a/frontend/src/metabase/components/ItemsTable/BaseItemsTableBody/BaseItemsTableBody.tsx b/frontend/src/metabase/components/ItemsTable/BaseItemsTableBody/BaseItemsTableBody.tsx index 80888ef8d9d..89cd90bc82f 100644 --- a/frontend/src/metabase/components/ItemsTable/BaseItemsTableBody/BaseItemsTableBody.tsx +++ b/frontend/src/metabase/components/ItemsTable/BaseItemsTableBody/BaseItemsTableBody.tsx @@ -26,7 +26,7 @@ export const BaseItemsTableBody = ({ onMove, onToggleSelected, onClick, - showActionMenu, + visibleColumnsMap, }: Pick< BaseItemsTableProps, | "onClick" @@ -44,7 +44,7 @@ export const BaseItemsTableBody = ({ | "onCopy" | "onMove" | "onToggleSelected" - | "showActionMenu" + | "visibleColumnsMap" >) => { const isDndAvailable = useSelector(getIsDndAvailable); @@ -77,7 +77,7 @@ export const BaseItemsTableBody = ({ onToggleSelected={onToggleSelected} items={items} onClick={onClick} - showActionMenu={showActionMenu} + visibleColumnsMap={visibleColumnsMap} /> ); })} diff --git a/frontend/src/metabase/components/ItemsTable/DefaultItemRenderer.tsx b/frontend/src/metabase/components/ItemsTable/DefaultItemRenderer.tsx index 9bfea995ee0..aaa36f14ceb 100644 --- a/frontend/src/metabase/components/ItemsTable/DefaultItemRenderer.tsx +++ b/frontend/src/metabase/components/ItemsTable/DefaultItemRenderer.tsx @@ -19,7 +19,7 @@ export type ItemRendererProps = { databases?: Database[]; bookmarks?: Bookmark[]; } & ActionMenuProps & - Pick<BaseItemsTableProps, "onClick" | "showActionMenu">; + Pick<BaseItemsTableProps, "onClick" | "visibleColumnsMap">; export const DefaultItemRenderer = ({ item, @@ -35,7 +35,7 @@ export const DefaultItemRenderer = ({ bookmarks, testIdPrefix = "item", onClick, - showActionMenu, + visibleColumnsMap, }: ItemRendererProps) => { const canSelect = collection?.can_write && typeof onToggleSelected === "function"; @@ -60,19 +60,27 @@ export const DefaultItemRenderer = ({ handleSelectionToggled={handleSelectionToggled} /> )} - <Columns.Type.Cell - testIdPrefix={testIdPrefix} - icon={icon} - isPinned={isPinned} - /> - <Columns.Name.Cell - item={item} - testIdPrefix={testIdPrefix} - onClick={onClick} - /> - <Columns.LastEditedBy.Cell item={item} testIdPrefix={testIdPrefix} /> - <Columns.LastEditedAt.Cell item={item} testIdPrefix={testIdPrefix} /> - {showActionMenu && ( + {visibleColumnsMap["type"] && ( + <Columns.Type.Cell + testIdPrefix={testIdPrefix} + icon={icon} + isPinned={isPinned} + /> + )} + {visibleColumnsMap["name"] && ( + <Columns.Name.Cell + item={item} + testIdPrefix={testIdPrefix} + onClick={onClick} + /> + )} + {visibleColumnsMap["lastEditedBy"] && ( + <Columns.LastEditedBy.Cell item={item} testIdPrefix={testIdPrefix} /> + )} + {visibleColumnsMap["lastEditedAt"] && ( + <Columns.LastEditedAt.Cell item={item} testIdPrefix={testIdPrefix} /> + )} + {visibleColumnsMap["actionMenu"] && ( <Columns.ActionMenu.Cell item={item} collection={collection} diff --git a/frontend/src/metabase/components/ItemsTable/utils.ts b/frontend/src/metabase/components/ItemsTable/utils.ts index e71f2d1a110..275facc7ad4 100644 --- a/frontend/src/metabase/components/ItemsTable/utils.ts +++ b/frontend/src/metabase/components/ItemsTable/utils.ts @@ -1,3 +1,7 @@ +import type { + CollectionContentTableColumn, + CollectionContentTableColumnsMap, +} from "metabase/collections/components/CollectionContent"; import { type BreakpointName, breakpoints } from "metabase/ui/theme"; export interface ResponsiveProps { @@ -12,3 +16,11 @@ export const getContainerQuery = (props: ResponsiveProps) => breakpoints[props.hideAtContainerBreakpoint] }) { display: none; }` : ""; + +export const getVisibleColumnsMap = ( + visibleColumns: CollectionContentTableColumn[], +) => + visibleColumns.reduce((result, item) => { + result[item] = true; + return result; + }, {} as CollectionContentTableColumnsMap); diff --git a/frontend/src/metabase/containers/dnd/ItemsDragLayer.jsx b/frontend/src/metabase/containers/dnd/ItemsDragLayer.jsx index f8ae9262b11..3fb787d0932 100644 --- a/frontend/src/metabase/containers/dnd/ItemsDragLayer.jsx +++ b/frontend/src/metabase/containers/dnd/ItemsDragLayer.jsx @@ -19,6 +19,7 @@ class ItemsDragLayerInner extends Component { pinnedItems, item, collection, + visibleColumnsMap, } = this.props; if (!isDragging || !currentOffset) { return null; @@ -43,6 +44,7 @@ class ItemsDragLayerInner extends Component { draggedItem={item.item} pinnedItems={pinnedItems} collection={collection} + visibleColumnsMap={visibleColumnsMap} /> </div> ); @@ -107,7 +109,7 @@ class DraggedItems extends Component { }; render() { - const { items, draggedItem } = this.props; + const { items, draggedItem, visibleColumnsMap } = this.props; const index = _.findIndex(items, draggedItem); const allPinned = items.every(item => this.checkIsPinned(item)); return ( @@ -124,6 +126,7 @@ class DraggedItems extends Component { isInDragLayer style={{ width: allPinned ? 400 : undefined }} includeColGroup={!allPinned} + visibleColumnsMap={visibleColumnsMap} /> </div> ); -- GitLab