Compare commits

...

7 Commits

Author SHA1 Message Date
Raphael Krut-Landau
8f0b88a5e3 wip 2024-08-15 14:52:31 -04:00
Raphael Krut-Landau
6c1dcf32e6 wip 2024-08-15 14:31:21 -04:00
Raphael Krut-Landau
ac3ae72ca2 wip 2024-08-15 12:43:37 -04:00
Raphael Krut-Landau
8d18880f4f wip 2024-08-15 12:37:56 -04:00
Raphael Krut-Landau
19ab70d43e wip 2024-08-15 12:37:54 -04:00
Raphael Krut-Landau
b153ce39f2 wip 2024-08-15 11:31:21 -04:00
Raphael Krut-Landau
9d62d05bed wip 2024-08-15 10:36:21 -04:00
8 changed files with 309 additions and 124 deletions

View File

@@ -238,62 +238,56 @@ export const CollectionContentView = ({
)}
<CollectionMain>
<ErrorBoundary>
<Header
collection={collection}
isAdmin={isAdmin}
isBookmarked={isBookmarked}
isPersonalCollectionChild={isPersonalCollectionChild(
collection,
collectionList,
)}
onCreateBookmark={handleCreateBookmark}
onDeleteBookmark={handleDeleteBookmark}
canUpload={canCreateUpload}
uploadsEnabled={uploadsEnabled}
saveFile={saveFile}
/>
</ErrorBoundary>
<ErrorBoundary>
<PinnedItemOverview
databases={databases}
bookmarks={bookmarks}
createBookmark={createBookmark}
deleteBookmark={deleteBookmark}
items={pinnedItems}
collection={collection}
onMove={handleMove}
onCopy={handleCopy}
/>
</ErrorBoundary>
<ErrorBoundary>
<CollectionItemsTable
collectionId={collectionId}
collection={collection}
getIsSelected={getIsSelected}
selectOnlyTheseItems={selectOnlyTheseItems}
databases={databases}
bookmarks={bookmarks}
createBookmark={createBookmark}
deleteBookmark={deleteBookmark}
loadingPinnedItems={loadingPinnedItems}
hasPinnedItems={hasPinnedItems}
selected={selected}
toggleItem={toggleItem}
clear={clear}
handleMove={handleMove}
handleCopy={handleCopy}
/>
<CollectionBulkActions
collection={collection}
selected={selected}
clearSelected={clear}
selectedItems={selectedItems}
setSelectedItems={setSelectedItems}
selectedAction={selectedAction}
setSelectedAction={setSelectedAction}
/>
</ErrorBoundary>
<Header
collection={collection}
isAdmin={isAdmin}
isBookmarked={isBookmarked}
isPersonalCollectionChild={isPersonalCollectionChild(
collection,
collectionList,
)}
onCreateBookmark={handleCreateBookmark}
onDeleteBookmark={handleDeleteBookmark}
canUpload={canCreateUpload}
uploadsEnabled={uploadsEnabled}
saveFile={saveFile}
/>
<PinnedItemOverview
databases={databases}
bookmarks={bookmarks}
createBookmark={createBookmark}
deleteBookmark={deleteBookmark}
items={pinnedItems}
collection={collection}
onMove={handleMove}
onCopy={handleCopy}
/>
<CollectionItemsTable
collectionId={collectionId}
collection={collection}
getIsSelected={getIsSelected}
selectOnlyTheseItems={selectOnlyTheseItems}
databases={databases}
bookmarks={bookmarks}
createBookmark={createBookmark}
deleteBookmark={deleteBookmark}
loadingPinnedItems={loadingPinnedItems}
hasPinnedItems={hasPinnedItems}
selected={selected}
toggleItem={toggleItem}
clear={clear}
handleMove={handleMove}
handleCopy={handleCopy}
/>
<CollectionBulkActions
collection={collection}
selected={selected}
clearSelected={clear}
selectedItems={selectedItems}
setSelectedItems={setSelectedItems}
selectedAction={selectedAction}
setSelectedAction={setSelectedAction}
/>
</CollectionMain>
<ItemsDragLayer
selectedItems={selected}

View File

@@ -0,0 +1,26 @@
.collectionItemsTable {
background-color: var(--mb-color-bg-white);
/*table-layout: fixed;*/
border-radius: 0.5rem;
/* FIXME: workaround */
height: 70vh;
/* thead { */
/* th { */
/* border-top: 1px solid var(--mb-color-border); */
/* &:first-of-type { */
/* border-start-start-radius: 8px; */
/* border-inline-start: 1px solid var(--mb-color-border); */
/* } */
/* &:last-child { */
/* border-start-end-radius: 8px; */
/* border-inline-end: 1px solid var(--mb-color-border); */
/* } */
/* } */
/* } */
/* [role="row"] { */
/* display: grid; */
/* } */
}

View File

@@ -1,6 +1,7 @@
/* eslint-disable react/prop-types */
import cx from "classnames";
import { type ComponentType, useCallback, useEffect, useState } from "react";
import DataGrid, { type RenderRowProps } from "react-data-grid";
import CollectionItemsTableS from "./CollectionItemsTable.module.css";
import {
ALL_MODELS,
@@ -12,9 +13,6 @@ import type {
DeleteBookmark,
} from "metabase/collections/types";
import { isRootTrashCollection } from "metabase/collections/utils";
import { ItemsTable } from "metabase/components/ItemsTable";
import { PaginationControls } from "metabase/components/PaginationControls";
import CS from "metabase/css/core/index.css";
import Search from "metabase/entities/search";
import { usePagination } from "metabase/hooks/use-pagination";
import { useSelector } from "metabase/lib/redux";
@@ -29,10 +27,12 @@ import type {
} from "metabase-types/api";
import { SortDirection, type SortingOptions } from "metabase-types/api/sorting";
import { CollectionEmptyContent } from "./CollectionContent.styled";
import {
CollectionEmptyContent,
CollectionTable,
} from "./CollectionContent.styled";
DefaultItemRenderer,
ItemRendererProps,
} from "metabase/components/ItemsTable/DefaultItemRenderer";
import { Columns } from "metabase/components/ItemsTable/Columns";
const getDefaultSortingOptions = (
collection: Collection | undefined,
@@ -183,47 +183,192 @@ export const CollectionItemsTable = ({
const isEmpty =
!loading && !hasPinnedItems && unpinnedItems.length === 0;
const manyItems =
unpinnedItems.length < 50
? [
...unpinnedItems,
...unpinnedItems,
...unpinnedItems,
...unpinnedItems,
...unpinnedItems,
...unpinnedItems,
...unpinnedItems,
...unpinnedItems,
...unpinnedItems,
...unpinnedItems,
...unpinnedItems,
...unpinnedItems,
...unpinnedItems,
...unpinnedItems,
...unpinnedItems,
...unpinnedItems,
...unpinnedItems,
...unpinnedItems,
...unpinnedItems,
...unpinnedItems,
...unpinnedItems,
...unpinnedItems,
...unpinnedItems,
...unpinnedItems,
...unpinnedItems,
...unpinnedItems,
...unpinnedItems,
]
: unpinnedItems;
if (isEmpty && !loadingUnpinnedItems) {
return <EmptyContentComponent collection={collection} />;
}
// <ItemsTable
// databases={databases}
// bookmarks={bookmarks}
// createBookmark={createBookmark}
// deleteBookmark={deleteBookmark}
// items={unpinnedItems}
// collection={collection}
// sortingOptions={unpinnedItemsSorting}
// onSortingOptionsChange={handleUnpinnedItemsSortingChange}
// selectedItems={selected}
// hasUnselected={hasUnselected}
// getIsSelected={getIsSelected}
// onToggleSelected={toggleItem}
// onDrop={clear}
// onMove={handleMove}
// onCopy={handleCopy}
// onSelectAll={handleSelectAll}
// onSelectNone={clear}
// onClick={onClick}
// showActionMenu={showActionMenu}
// />
// <div className={cx(CS.flex, CS.justifyEnd, CS.my3)}>
// {hasPagination && (
// <PaginationControls
// showTotal
// page={page}
// pageSize={pageSize}
// total={total ?? undefined}
// itemsLength={unpinnedItems.length}
// onNextPage={handleNextPage}
// onPreviousPage={handlePreviousPage}
// />
// )}
// </div>
// {canSelect && <Columns.Select.Col />}
// <Columns.Type.Col />
// <Columns.Name.Col isInDragLayer={isInDragLayer} />
// <Columns.LastEditedBy.Col />
// <Columns.LastEditedAt.Col />
// {showActionMenu && <Columns.ActionMenu.Col />}
const headerSortingProps = {
onSortingOptionsChange: handleUnpinnedItemsSortingChange,
sortingOptions: unpinnedItemsSorting,
};
// FIXME: Note I have removed <CollectionTable> which used to wrap this datagrid
return (
<CollectionTable data-testid="collection-table">
<ItemsTable
databases={databases}
bookmarks={bookmarks}
createBookmark={createBookmark}
deleteBookmark={deleteBookmark}
items={unpinnedItems}
collection={collection}
sortingOptions={unpinnedItemsSorting}
onSortingOptionsChange={handleUnpinnedItemsSortingChange}
selectedItems={selected}
hasUnselected={hasUnselected}
getIsSelected={getIsSelected}
onToggleSelected={toggleItem}
onDrop={clear}
onMove={handleMove}
onCopy={handleCopy}
onSelectAll={handleSelectAll}
onSelectNone={clear}
onClick={onClick}
showActionMenu={showActionMenu}
/>
<div className={cx(CS.flex, CS.justifyEnd, CS.my3)}>
{hasPagination && (
<PaginationControls
showTotal
page={page}
pageSize={pageSize}
total={total ?? undefined}
itemsLength={unpinnedItems.length}
onNextPage={handleNextPage}
onPreviousPage={handlePreviousPage}
/>
<>
<DataGrid
enableVirtualization
className={CollectionItemsTableS.collectionItemsTable}
rows={manyItems.map(
(item: CollectionItem) =>
({
item: { ...item, getUrl: () => "" },
isSelected: false,
isPinned: false,
onToggleSelected: () => null,
collection: { ...item.collection, can_write: true },
onCopy: () => null,
showActionMenu: false,
onSortingOptionsChange: handleUnpinnedItemsSortingChange,
icon: { name: "model" }, // FIXME
} as ItemRendererProps),
)}
</div>
</CollectionTable>
rowHeight={50}
columns={[
{
key: "select",
name: "",
width: 70,
renderHeaderCell: _props => <Columns.Select.Header />,
renderCell: props => <Columns.Select.Cell {...props.row} />,
},
{
key: "type",
name: "Type",
width: 70,
sortable: true,
renderHeaderCell: _props => (
<Columns.Type.Header {...headerSortingProps} />
),
renderCell: props => <Columns.Type.Cell {...props.row} />,
},
{
key: "name",
name: "Name",
width: 300,
sortable: true,
renderCell: props => <Columns.Name.Cell {...props.row} />,
renderHeaderCell: _props => (
<Columns.Name.Header {...headerSortingProps} />
),
},
{
key: "last_edited_by",
name: "Last edited by",
width: 140,
sortable: true,
renderCell: props => (
<Columns.LastEditedBy.Cell item={props.row} />
),
renderHeaderCell: _props => (
<Columns.LastEditedBy.Header {...headerSortingProps} />
),
},
{
key: "last_edited_at",
name: "Last edited at",
width: 140,
sortable: true,
renderCell: props => (
<Columns.LastEditedAt.Cell {...props.row} />
),
renderHeaderCell: _props => (
<Columns.LastEditedAt.Header {...headerSortingProps} />
),
},
{
key: "action_menu",
name: "",
width: 100,
renderCell: props => (
<Columns.ActionMenu.Cell {...props.row} />
),
renderHeaderCell: _props => <Columns.ActionMenu.Header />,
},
{
key: "right_edge",
name: "",
width: 5,
renderCell: _props => <Columns.RightEdge.Cell />,
renderHeaderCell: _props => <Columns.RightEdge.Header />,
},
]}
defaultColumnOptions={{
sortable: true,
resizable: true,
}}
//renderers={{
// renderRow: (key, props: RenderRowProps<ItemRendererProps>) => (
// <tr>
// <DefaultItemRenderer key={key} {...props.row} />
// </tr>
// ),
//}}
/>
</>
);
}}
</Search.ListLoader>

View File

@@ -54,8 +54,9 @@ export const hideResponsively = ({
})}
`;
export const ColumnHeader = styled.th<ResponsiveProps>`
th& {
// FIXME: Changed this from <th>
export const ColumnHeader = styled.div<ResponsiveProps>`
div& {
padding: 0.75em 1em 0.75em;
}
@@ -69,7 +70,7 @@ export const BulkSelectWrapper = styled(IconButtonWrapper)`
width: 3em;
`;
export const ItemCell = styled.td<ResponsiveProps>`
export const ItemCell = styled.div<ResponsiveProps>`
padding: 0.25em 0 0.25em 1em !important;
${hideResponsively}
`;
@@ -101,7 +102,7 @@ export const ItemLink = styled(Link)(itemLinkStyle);
export const MaybeItemLink = styled(RawMaybeLink)(itemLinkStyle);
export const ItemNameCell = styled.td`
export const ItemNameCell = styled.div`
padding: 0 !important;
${ItemLink}, ${MaybeItemLink}, ${ItemButton} {

View File

@@ -71,26 +71,20 @@ export const SortableColumnHeader = ({
}, [direction, isSortable, name, onSortingOptionsChange]);
return (
<ColumnHeader
hideAtContainerBreakpoint={hideAtContainerBreakpoint}
containerName={containerName}
{...columnHeaderProps}
<SortingControlContainer
{...props}
isActive={isSortingThisColumn}
onClick={onSortingControlClick}
role="button"
isSortable={isSortable}
>
<SortingControlContainer
{...props}
isActive={isSortingThisColumn}
onClick={onSortingControlClick}
role="button"
isSortable={isSortable}
>
{children}
{isSortable && (
<SortingIcon
name={direction === SortDirection.Asc ? "chevronup" : "chevrondown"}
/>
)}
</SortingControlContainer>
</ColumnHeader>
{children}
{isSortable && (
<SortingIcon
name={direction === SortDirection.Asc ? "chevronup" : "chevrondown"}
/>
)}
</SortingControlContainer>
);
};

View File

@@ -1,6 +1,8 @@
import type { PropsWithChildren } from "react";
import { c, t } from "ttag";
import "react-data-grid/lib/styles.css";
import type { ActionMenuProps } from "metabase/collections/components/ActionMenu";
import ActionMenu from "metabase/collections/components/ActionMenu";
import DateTime from "metabase/components/DateTime";
@@ -48,8 +50,17 @@ const ItemLinkComponent = ({
if (isEmbeddingSdk) {
return <ItemButton onClick={() => onClick?.(item)}>{children}</ItemButton>;
}
console.log("item in itemlinkcomponent", item);
console.log("item.getUrl()", item?.getUrl?.());
return (
<ItemLink to={item.getUrl()} onClick={() => onClick?.(item)}>
<ItemLink
to={
// FIXME: remove workaround
"getUrl" in item ? item.getUrl() : ""
}
onClick={() => onClick?.(item)}
>
{children}
</ItemLink>
);
@@ -160,6 +171,7 @@ export const Columns = {
includeDescription?: boolean;
onClick?: (item: CollectionItem) => void;
}) => {
console.log("item in namecell", item);
return (
<ItemNameCell data-testid={`${testIdPrefix}-name`}>
<ItemLinkComponent onClick={onClick} item={item}>
@@ -197,7 +209,7 @@ export const Columns = {
onSortingOptionsChange,
isTrashed,
}: HeaderProps & {
isTrashed: boolean;
isTrashed?: boolean;
}) => (
<SortableColumnHeader
name="last_edited_by"
@@ -245,7 +257,7 @@ export const Columns = {
onSortingOptionsChange,
isTrashed,
}: HeaderProps & {
isTrashed: boolean;
isTrashed?: boolean;
}) => (
<SortableColumnHeader
name="last_edited_at"

View File

@@ -84,6 +84,7 @@
"react-beautiful-dnd": "^13.1.1",
"react-color": "^2.14.1",
"react-copy-to-clipboard": "^5.0.1",
"react-data-grid": "^7.0.0-beta.46",
"react-dnd": "4",
"react-dnd-html5-backend": "4",
"react-dom": "^18.2.0",

View File

@@ -8476,6 +8476,11 @@ clsx@^1.1.1:
resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12"
integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==
clsx@^2.0.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.1.tgz#eed397c9fd8bd882bfb18deab7102049a2f32999"
integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==
co@^4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
@@ -19534,6 +19539,13 @@ react-copy-to-clipboard@^5.0.1:
copy-to-clipboard "^3"
prop-types "^15.5.8"
react-data-grid@^7.0.0-beta.46:
version "7.0.0-beta.46"
resolved "https://registry.yarnpkg.com/react-data-grid/-/react-data-grid-7.0.0-beta.46.tgz#701dcfb091da59ad9571b47b1aaf7dacb6175e51"
integrity sha512-tU6sYNgbMw3mQphPyLN5jtG2TD84I0XcebPQQ2apCZuDX9Nqu7MCkTTIluXBnIzIW3LLS8XEp+Ml7OhEQoFKRA==
dependencies:
clsx "^2.0.0"
react-devtools-core@^4.19.1:
version "4.28.5"
resolved "https://registry.yarnpkg.com/react-devtools-core/-/react-devtools-core-4.28.5.tgz#c8442b91f068cdf0c899c543907f7f27d79c2508"