finalize permission popup

Co-Authored-By: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
This commit is contained in:
Nate Kelley 2025-01-17 10:50:10 -07:00
parent 43c96cbb09
commit 221a4a6280
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
9 changed files with 140 additions and 56 deletions

View File

@ -8,7 +8,6 @@ import {
useIndividualCollection
} from '@/context/Collections';
import { Breadcrumb, Button, Dropdown, MenuProps } from 'antd';
import { BreadcrumbSeperator } from '@/components';
import Link from 'next/link';
import { useAppLayoutContextSelector } from '@/context/BusterAppLayout';
import { BusterRoutes } from '@/routes';
@ -19,10 +18,10 @@ import { ShareMenu } from '../../_components/ShareMenu';
import { BusterCollection } from '@/api/buster-rest/collection';
import { BusterShareAssetType } from '@/api/buster-rest';
import { Text } from '@/components';
import { useAntToken } from '@/styles/useAntToken';
import { measureTextWidth } from '@/utils';
import { useMemoizedFn } from 'ahooks';
import { BreadcrumbSeperator } from '@/components/breadcrumb';
import { measureTextWidth } from '@/utils/canvas';
export const CollectionsIndividualHeader: React.FC<{}> = () => {
const selectedThreadId = useBusterThreadsContextSelector((x) => x.selectedThreadId);

View File

@ -1,11 +1,16 @@
import { BusterListSelectedOptionPopupContainer } from '@/components/list';
import { Button } from 'antd';
import React from 'react';
import { Button, Dropdown, MenuProps } from 'antd';
import React, { useMemo } from 'react';
import { PERMISSION_GROUP_ASSIGNED_OPTIONS } from './config';
import { useMemoizedFn } from 'ahooks';
import { useDatasetUpdatePermissionGroups } from '@/api/buster-rest';
import { AppMaterialIcons } from '@/components/icons';
export const PermissionGroupSelectedPopup: React.FC<{
selectedRowKeys: string[];
datasetId: string;
onSelectChange: (selectedRowKeys: string[]) => void;
}> = React.memo(({ selectedRowKeys, onSelectChange }) => {
}> = React.memo(({ selectedRowKeys, onSelectChange, datasetId }) => {
return (
<BusterListSelectedOptionPopupContainer
selectedRowKeys={selectedRowKeys}
@ -14,6 +19,7 @@ export const PermissionGroupSelectedPopup: React.FC<{
<PermissionGroupAssignButton
key="assign"
selectedRowKeys={selectedRowKeys}
datasetId={datasetId}
onSelectChange={onSelectChange}
/>
]}
@ -26,6 +32,45 @@ PermissionGroupSelectedPopup.displayName = 'PermissionGroupSelectedPopup';
const PermissionGroupAssignButton: React.FC<{
selectedRowKeys: string[];
onSelectChange: (selectedRowKeys: string[]) => void;
}> = ({ selectedRowKeys, onSelectChange }) => {
return <Button>Assign</Button>;
datasetId: string;
}> = ({ selectedRowKeys, onSelectChange, datasetId }) => {
const { mutateAsync: updatePermissionGroups, isPending } =
useDatasetUpdatePermissionGroups(datasetId);
const onClickItem = useMemoizedFn(async (assigned: boolean) => {
try {
await updatePermissionGroups(
selectedRowKeys.map((id) => ({
id,
assigned
}))
);
onSelectChange([]);
} catch (error) {
//
}
});
const menu: MenuProps = useMemo(() => {
return {
items: PERMISSION_GROUP_ASSIGNED_OPTIONS.map((option) => ({
label: option.label,
key: option.value ? 'true' : 'false',
icon: option.value ? (
<AppMaterialIcons icon="done_all" />
) : (
<AppMaterialIcons icon="remove_done" />
),
onClick: () => {
onClickItem(option.value);
}
}))
};
}, []);
return (
<Dropdown menu={menu} trigger={['click']}>
<Button loading={isPending}>Assign</Button>
</Dropdown>
);
};

View File

@ -10,6 +10,7 @@ import React, { useMemo, useState } from 'react';
import { Text } from '@/components/text';
import { PermissionGroupSelectedPopup } from './PermissionGroupSelectedPopup';
import { BusterInfiniteList } from '@/components/list/BusterInfiniteList';
import { PERMISSION_GROUP_ASSIGNED_OPTIONS } from './config';
export const PermissionListPermissionGroupContainer: React.FC<{
filteredPermissionGroups: ListPermissionGroupsResponse[];
@ -121,11 +122,13 @@ export const PermissionListPermissionGroupContainer: React.FC<{
selectedRowKeys={selectedRowKeys}
onSelectChange={setSelectedRowKeys}
emptyState={<EmptyState />}
useRowClickSelectChange={true}
/>
<div className="fixed bottom-1 left-0 right-0 w-full">
<div className="fixed bottom-0 left-0 right-0 w-full">
<div className="relative ml-[220px] mr-[55px]">
<PermissionGroupSelectedPopup
datasetId={datasetId}
selectedRowKeys={selectedRowKeys}
onSelectChange={setSelectedRowKeys}
/>
@ -149,18 +152,7 @@ const PermissionGroupInfoCell = React.memo(({ name }: { name: string }) => {
});
PermissionGroupInfoCell.displayName = 'PermissionGroupInfoCell';
const options = [
{
label: 'Assigned',
value: true
},
{
label: 'Not Assigned',
value: false
}
];
const PermissionGroupAssignedCell = React.memo(
export const PermissionGroupAssignedCell = React.memo(
({
id,
assigned,
@ -172,9 +164,13 @@ const PermissionGroupAssignedCell = React.memo(
}) => {
return (
<Select
options={options}
options={PERMISSION_GROUP_ASSIGNED_OPTIONS}
defaultValue={assigned}
popupMatchSelectWidth
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
}}
onSelect={(value) => {
onSelect({ id, assigned: value });
}}

View File

@ -0,0 +1,10 @@
export const PERMISSION_GROUP_ASSIGNED_OPTIONS = [
{
label: 'Assigned',
value: true
},
{
label: 'Not Assigned',
value: false
}
];

View File

@ -2,6 +2,7 @@ import React from 'react';
import { useMemoizedFn } from 'ahooks';
import { BusterListProps } from '../BusterList';
import { getAllIdsInSection } from '../BusterList/helpers';
import { WindowVirtualizer } from 'virtua';
import { useEffect, useMemo, useRef, useCallback } from 'react';
import { BusterListHeader } from '../BusterList/BusterListHeader';
import { BusterListRowComponentSelector } from '../BusterList/BusterListRowComponentSelector';
@ -19,6 +20,7 @@ export const BusterInfiniteList: React.FC<BusterInfiniteListProps> = ({
onSelectChange,
emptyState,
showHeader = true,
useRowClickSelectChange = false,
contextMenu,
columnRowVariant = 'containerized',
showSelectAll = true,
@ -26,8 +28,6 @@ export const BusterInfiniteList: React.FC<BusterInfiniteListProps> = ({
loadingNewContent,
scrollEndThreshold = 200 // Default threshold of 200px
}) => {
const containerRef = useRef<HTMLDivElement>(null);
const showEmptyState = useMemo(
() => (!rows || rows.length === 0 || !rows.some((row) => !row.rowSection)) && !!emptyState,
[rows, emptyState]
@ -72,12 +72,14 @@ export const BusterInfiniteList: React.FC<BusterInfiniteListProps> = ({
onSelectChange: onSelectChange ? onSelectChangePreflight : undefined,
onSelectSectionChange: onSelectChange ? onSelectSectionChange : undefined,
onContextMenuClick: undefined,
columnRowVariant
columnRowVariant,
useRowClickSelectChange
};
}, [
columns,
rows,
onSelectChange,
useRowClickSelectChange,
columnRowVariant,
onSelectSectionChange,
contextMenu,
@ -86,29 +88,25 @@ export const BusterInfiniteList: React.FC<BusterInfiniteListProps> = ({
// Add scroll handler
const handleScroll = useCallback(() => {
if (!containerRef.current || !onScrollEnd) return;
const { scrollTop, scrollHeight, clientHeight } = containerRef.current;
const distanceToBottom = scrollHeight - scrollTop - clientHeight;
if (distanceToBottom <= scrollEndThreshold) {
onScrollEnd();
}
// const { scrollTop, scrollHeight, clientHeight } = containerRef.current;
// const distanceToBottom = scrollHeight - scrollTop - clientHeight;
// console.log('distanceToBottom', distanceToBottom);
// if (distanceToBottom <= scrollEndThreshold) {
// onScrollEnd();
// console.log('onScrollEnd');
// }
}, [onScrollEnd, scrollEndThreshold]);
// Add scroll event listener
useEffect(() => {
const container = containerRef.current;
if (!container || !onScrollEnd) return;
container.addEventListener('scroll', handleScroll);
return () => container.removeEventListener('scroll', handleScroll);
// const container = containerRef.current;
// if (!container || !onScrollEnd) return;
// container.addEventListener('scroll', handleScroll);
// return () => container.removeEventListener('scroll', handleScroll);
}, [handleScroll, onScrollEnd]);
return (
<div
className="infinite-list-container relative flex h-full w-full flex-col"
ref={containerRef}>
<div className="infinite-list-container relative flex h-full w-full flex-col">
{showHeader && !showEmptyState && (
<BusterListHeader
columns={columns}

View File

@ -18,10 +18,20 @@ export const BusterListRowComponent = React.memo(
onContextMenuClick?: (e: React.MouseEvent<HTMLDivElement>, id: string) => void;
style?: React.CSSProperties;
columnRowVariant: BusterListProps['columnRowVariant'];
useRowClickSelectChange: boolean;
}
>(
(
{ style, columnRowVariant, row, columns, onSelectChange, checked, onContextMenuClick },
{
style,
columnRowVariant,
row,
columns,
onSelectChange,
checked,
onContextMenuClick,
useRowClickSelectChange
},
ref
) => {
const { styles, cx } = useStyles();
@ -31,14 +41,21 @@ export const BusterListRowComponent = React.memo(
onContextMenuClick?.(e, row.id);
});
const onChange = useMemoizedFn((checked: boolean) => {
onSelectChange?.(checked, row.id);
const onChange = useMemoizedFn((newChecked: boolean) => {
onSelectChange?.(newChecked, row.id);
});
const onContainerClick = useMemoizedFn(() => {
if (useRowClickSelectChange) {
onChange(!checked);
}
row.onClick?.();
});
return (
<LinkWrapper href={link}>
<div
onClick={row.onClick}
onClick={onContainerClick}
style={style}
onContextMenu={onContextMenu}
className={cx(
@ -46,7 +63,7 @@ export const BusterListRowComponent = React.memo(
'group flex items-center',
checked ? 'checked' : '',
columnRowVariant,
{ clickable: !!(link || row.onClick) }
{ clickable: !!(link || row.onClick || (onSelectChange && useRowClickSelectChange)) }
)}
ref={ref}>
{!!onSelectChange ? (
@ -124,15 +141,14 @@ export const useStyles = createStyles(({ css, token }) => ({
row: css`
height: ${HEIGHT_OF_ROW}px;
min-height: ${HEIGHT_OF_ROW}px;
border-bottom: 0.5px solid ${token.colorBorder};
&:hover {
background-color: ${token.controlItemBgHover};
}
&.clickable {
cursor: pointer;
&:hover {
background-color: ${token.controlItemBgHover};
}
}
.row-cell {
@ -149,9 +165,15 @@ export const useStyles = createStyles(({ css, token }) => ({
}
}
&.containerized {
&.containerized:not(.checked) {
background-color: ${token.colorBgContainer};
&.clickable {
&:hover {
background-color: ${token.controlItemBgHover};
}
}
&:last-child {
border-bottom: 0px;
}

View File

@ -16,6 +16,7 @@ export const BusterListRowComponentSelector = React.forwardRef<
rows: BusterListRow[];
style?: React.CSSProperties;
columnRowVariant?: BusterListProps['columnRowVariant'];
useRowClickSelectChange: boolean;
}
>(
(
@ -28,7 +29,8 @@ export const BusterListRowComponentSelector = React.forwardRef<
onSelectSectionChange,
selectedRowKeys,
onContextMenuClick,
columnRowVariant
columnRowVariant,
useRowClickSelectChange = false
},
ref
) => {
@ -58,6 +60,7 @@ export const BusterListRowComponentSelector = React.forwardRef<
ref={ref}
onContextMenuClick={onContextMenuClick}
columnRowVariant={columnRowVariant}
useRowClickSelectChange={useRowClickSelectChange}
/>
);
}

View File

@ -18,7 +18,8 @@ export const BusterListVirtua = React.memo(
emptyState,
showHeader = true,
contextMenu,
showSelectAll = true
showSelectAll = true,
useRowClickSelectChange = false
}: BusterListProps) => {
const contextMenuRef = useRef<HTMLDivElement>(null);
const showEmptyState = (!rows || rows.length === 0) && !!emptyState;
@ -70,9 +71,18 @@ export const BusterListVirtua = React.memo(
selectedRowKeys,
onSelectChange: onSelectChange ? onSelectChangePreflight : undefined,
onSelectSectionChange: onSelectChange ? onSelectSectionChange : undefined,
onContextMenuClick
onContextMenuClick,
useRowClickSelectChange
};
}, [columns, rows, selectedRowKeys, onSelectChange, onSelectSectionChange, onContextMenuClick]);
}, [
columns,
rows,
useRowClickSelectChange,
selectedRowKeys,
onSelectChange,
onSelectSectionChange,
onContextMenuClick
]);
useEffect(() => {
if (contextMenu && contextMenuPosition?.show) {

View File

@ -16,6 +16,7 @@ export interface BusterListProps {
selectedRowKeys?: string[];
contextMenu?: BusterListContextMenu;
showSelectAll?: boolean;
useRowClickSelectChange?: boolean;
}
export interface BusterListColumn {