add additional bulk popup menus

Co-Authored-By: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
This commit is contained in:
Nate Kelley 2025-01-17 12:10:23 -07:00
parent 58fa171a8e
commit db7d98ec9a
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
12 changed files with 204 additions and 103 deletions

View File

@ -19,7 +19,7 @@ export const PermissionDatasetGroupSelectedPopup: React.FC<{
onSelectChange={onSelectChange}
buttons={[
<PermissionDatasetGroupAssignButton
key="delete"
key="assign"
selectedRowKeys={selectedRowKeys}
onSelectChange={onSelectChange}
datasetId={datasetId}

View File

@ -6,12 +6,12 @@ import { Select } from 'antd';
import { createStyles } from 'antd-style';
import React, { useMemo, useState } from 'react';
import { PermissionDatasetGroupSelectedPopup } from './PermissionDatasetGroupSelectedPopup';
import { PermissionListContainer } from '../_components';
export const PermissionListDatasetGroupContainer: React.FC<{
filteredPermissionGroups: ListDatasetGroupsResponse[];
datasetId: string;
}> = ({ filteredPermissionGroups, datasetId }) => {
const { styles, cx } = useStyles();
const { mutateAsync: updateDatasetGroups } = useDatasetUpdateDatasetGroups(datasetId);
const [selectedRowKeys, setSelectedRowKeys] = useState<string[]>([]);
const numberOfPermissionGroups = filteredPermissionGroups.length;
@ -107,36 +107,28 @@ export const PermissionListDatasetGroupContainer: React.FC<{
);
return (
<>
<div className={cx('', styles.container)}>
<BusterInfiniteList
columns={columns}
rows={rows}
showHeader={false}
showSelectAll={false}
<PermissionListContainer
popupNode={
<PermissionDatasetGroupSelectedPopup
selectedRowKeys={selectedRowKeys}
onSelectChange={setSelectedRowKeys}
emptyState={<div className="py-12">No dataset groups found</div>}
datasetId={datasetId}
/>
</div>
<PermissionDatasetGroupSelectedPopup
}>
<BusterInfiniteList
columns={columns}
rows={rows}
showHeader={false}
showSelectAll={false}
useRowClickSelectChange={true}
selectedRowKeys={selectedRowKeys}
onSelectChange={setSelectedRowKeys}
datasetId={datasetId}
emptyState={<div className="py-12">No dataset groups found</div>}
/>
</>
</PermissionListContainer>
);
};
const useStyles = createStyles(({ css, token }) => ({
container: css`
border: 0.5px solid ${token.colorBorder};
border-radius: ${token.borderRadius}px;
overflow: hidden;
`
}));
const DatasetGroupInfoCell: React.FC<{ name: string }> = ({ name }) => {
return <div>{name}</div>;
};
@ -165,6 +157,10 @@ const DatasetGroupAssignedCell: React.FC<{
onSelect={(value) => {
onSelect({ id, assigned: value });
}}
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
}}
/>
);
});

View File

@ -5,18 +5,17 @@ import {
import { BusterListColumn, BusterListRowItem } from '@/components/list';
import { useMemoizedFn } from 'ahooks';
import { Select } from 'antd';
import { createStyles } from 'antd-style';
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';
import { PermissionListContainer } from '../_components/PermissionListContainer';
export const PermissionListPermissionGroupContainer: React.FC<{
filteredPermissionGroups: ListPermissionGroupsResponse[];
datasetId: string;
}> = React.memo(({ filteredPermissionGroups, datasetId }) => {
const { styles, cx } = useStyles();
const { mutateAsync: updatePermissionGroups } = useDatasetUpdatePermissionGroups(datasetId);
const [selectedRowKeys, setSelectedRowKeys] = useState<string[]>([]);
@ -113,7 +112,14 @@ export const PermissionListPermissionGroupContainer: React.FC<{
);
return (
<div className={cx('min-h-fit overflow-hidden', styles.container)}>
<PermissionListContainer
popupNode={
<PermissionGroupSelectedPopup
datasetId={datasetId}
selectedRowKeys={selectedRowKeys}
onSelectChange={setSelectedRowKeys}
/>
}>
<BusterInfiniteList
columns={columns}
rows={rows}
@ -124,29 +130,12 @@ export const PermissionListPermissionGroupContainer: React.FC<{
emptyState={<EmptyState />}
useRowClickSelectChange={true}
/>
<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}
/>
</div>
</div>
</div>
</PermissionListContainer>
);
});
PermissionListPermissionGroupContainer.displayName = 'PermissionListTeamContainer';
const useStyles = createStyles(({ css, token }) => ({
container: css`
border: 0.5px solid ${token.colorBorder};
border-radius: ${token.borderRadius}px;
`
}));
const PermissionGroupInfoCell = React.memo(({ name }: { name: string }) => {
return <div>{name}</div>;
});
@ -165,7 +154,7 @@ export const PermissionGroupAssignedCell = React.memo(
return (
<Select
options={PERMISSION_GROUP_ASSIGNED_OPTIONS}
defaultValue={assigned}
value={assigned}
popupMatchSelectWidth
onClick={(e) => {
e.preventDefault();

View File

@ -11,12 +11,14 @@ import { Select } from 'antd';
import { createStyles } from 'antd-style';
import React, { useMemo, useState } from 'react';
import { Text } from '@/components/text';
import { PermissionListContainer } from '../_components';
import { PermissionUsersSelectedPopup } from './PermissionUsersSelectedPopup';
import { PERMISSION_USERS_OPTIONS } from './config';
export const PermissionListUsersContainer: React.FC<{
filteredPermissionUsers: ListPermissionUsersResponse[];
datasetId: string;
}> = React.memo(({ filteredPermissionUsers, datasetId }) => {
const { styles, cx } = useStyles();
const { mutateAsync: updatePermissionUsers } = useDatasetUpdatePermissionUsers(datasetId);
const [selectedRowKeys, setSelectedRowKeys] = useState<string[]>([]);
@ -113,7 +115,14 @@ export const PermissionListUsersContainer: React.FC<{
);
return (
<div className={cx(styles.container)}>
<PermissionListContainer
popupNode={
<PermissionUsersSelectedPopup
datasetId={datasetId}
selectedRowKeys={selectedRowKeys}
onSelectChange={setSelectedRowKeys}
/>
}>
<BusterInfiniteList
columns={columns}
rows={rows}
@ -121,26 +130,19 @@ export const PermissionListUsersContainer: React.FC<{
showSelectAll={false}
selectedRowKeys={selectedRowKeys}
onSelectChange={setSelectedRowKeys}
useRowClickSelectChange={true}
emptyState={
<div className="py-12">
<Text type="tertiary">No users found</Text>
</div>
}
/>
</div>
</PermissionListContainer>
);
});
PermissionListUsersContainer.displayName = 'PermissionListUsersContainer';
const useStyles = createStyles(({ css, token }) => ({
container: css`
border: 0.5px solid ${token.colorBorder};
border-radius: ${token.borderRadius}px;
overflow: hidden;
`
}));
const PermissionGroupInfoCell = React.memo(({ name, email }: { name: string; email: string }) => {
return (
<div className="flex w-full items-center space-x-1.5">
@ -161,39 +163,23 @@ const PermissionGroupInfoCell = React.memo(({ name, email }: { name: string; ema
});
PermissionGroupInfoCell.displayName = 'PermissionGroupInfoCell';
const options = [
{
label: 'Assigned',
value: true
},
{
label: 'Not Assigned',
value: false
}
];
const PermissionGroupAssignedCell = React.memo(
({
id,
assigned,
onSelect
}: {
id: string;
assigned: boolean;
onSelect: (value: { id: string; assigned: boolean }) => void;
}) => {
return (
<Select
options={options}
defaultValue={assigned}
popupMatchSelectWidth
onSelect={(value) => {
onSelect({ id, assigned: value });
}}
/>
);
},
() => true
);
PermissionGroupAssignedCell.displayName = 'PermissionGroupAssignedCell';
const PermissionGroupAssignedCell: React.FC<{
id: string;
assigned: boolean;
onSelect: (value: { id: string; assigned: boolean }) => void;
}> = ({ id, assigned, onSelect }) => {
return (
<Select
options={PERMISSION_USERS_OPTIONS}
value={assigned}
popupMatchSelectWidth
onSelect={(value) => {
onSelect({ id, assigned: value });
}}
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
}}
/>
);
};

View File

@ -19,7 +19,11 @@ export const PermissionUsers: React.FC<{
const { searchText, handleSearchChange, filteredItems } = useDebounceSearch({
items: permissionUsers || [],
searchPredicate: (item, searchText) => {
return item.name.includes(searchText);
const lowerCaseSearchText = searchText.toLowerCase();
return (
item.name.toLocaleLowerCase().includes(lowerCaseSearchText) ||
item.email.toLocaleLowerCase().includes(lowerCaseSearchText)
);
}
});

View File

@ -0,0 +1,81 @@
import { useDatasetUpdatePermissionUsers } from '@/api/buster-rest';
import { AppMaterialIcons } from '@/components';
import { BusterListSelectedOptionPopupContainer } from '@/components/list';
import { useMemoizedFn } from 'ahooks';
import { Button, Dropdown } from 'antd';
import { MenuProps } from 'antd/lib';
import React, { useMemo } from 'react';
import { PERMISSION_USERS_OPTIONS } from './config';
export const PermissionUsersSelectedPopup: React.FC<{
selectedRowKeys: string[];
onSelectChange: (selectedRowKeys: string[]) => void;
datasetId: string;
}> = React.memo(({ selectedRowKeys, onSelectChange, datasetId }) => {
const show = selectedRowKeys.length > 0;
return (
<BusterListSelectedOptionPopupContainer
selectedRowKeys={selectedRowKeys}
onSelectChange={onSelectChange}
buttons={[
<PermissionUsersAssignButton
key="assign"
selectedRowKeys={selectedRowKeys}
onSelectChange={onSelectChange}
datasetId={datasetId}
/>
]}
show={show}
/>
);
});
PermissionUsersSelectedPopup.displayName = 'PermissionUsersSelectedPopup';
const options = PERMISSION_USERS_OPTIONS.map((v) => ({
label: v.label,
value: v.value,
icon: v.value ? <AppMaterialIcons icon="done_all" /> : <AppMaterialIcons icon="remove_done" />
}));
const PermissionUsersAssignButton: React.FC<{
selectedRowKeys: string[];
onSelectChange: (selectedRowKeys: string[]) => void;
datasetId: string;
}> = ({ selectedRowKeys, onSelectChange, datasetId }) => {
const { mutateAsync: updatePermissionUsers } = useDatasetUpdatePermissionUsers(datasetId);
const onAssignClick = useMemoizedFn(async (assigned: boolean) => {
try {
await updatePermissionUsers(selectedRowKeys.map((v) => ({ id: v, assigned })));
onSelectChange([]);
} catch (error) {
// openErrorMessage('Failed to delete collection');
}
});
const menuProps: MenuProps = useMemo(() => {
return {
selectable: true,
items: options.map((v) => ({
icon: v.icon,
label: v.label,
key: v.value ? 'included' : 'not_included',
onClick: () => onAssignClick(v.value)
}))
};
}, [selectedRowKeys]);
const onButtonClick = useMemoizedFn((e: React.MouseEvent<HTMLButtonElement>) => {
e.stopPropagation();
e.preventDefault();
});
return (
<Dropdown menu={menuProps} trigger={['click']}>
<Button icon={<AppMaterialIcons icon="done_all" />} type="default" onClick={onButtonClick}>
{options[0].label}
</Button>
</Dropdown>
);
};

View File

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

View File

@ -0,0 +1,30 @@
import { createStyles } from 'antd-style';
import React from 'react';
export const PermissionListContainer: React.FC<{
children: React.ReactNode;
popupNode?: React.ReactNode;
}> = React.memo(({ children, popupNode }) => {
const { styles, cx } = useStyles();
return (
<div className={cx('overflow-hidden', styles.container)}>
{children}
{popupNode && (
<div className="fixed bottom-0 left-0 right-0 w-full">
<div className="relative ml-[220px] mr-[55px]">{popupNode}</div>
</div>
)}
</div>
);
});
PermissionListContainer.displayName = 'PermissionListContainer';
const useStyles = createStyles(({ css, token }) => ({
container: css`
border: 0.5px solid ${token.colorBorder};
border-radius: ${token.borderRadius}px;
`
}));

View File

@ -0,0 +1 @@
export * from './PermissionListContainer';

View File

@ -8,9 +8,6 @@ import { useMount } from 'ahooks';
const headerHeight = 300;
const ItemSwag = React.memo(({ index }: { index: number }) => {
useMount(() => {
console.log('useMount', index);
});
return <div className="h-[48px] border bg-red-200">Swag {index}</div>;
});
ItemSwag.displayName = 'ItemSwag';

View File

@ -17,7 +17,8 @@ export const BusterListReactWindow: React.FC<BusterListProps> = ({
emptyState,
showHeader = true,
contextMenu,
showSelectAll = true
showSelectAll = true,
useRowClickSelectChange = false
}) => {
const contextMenuRef = useRef<HTMLDivElement>(null);
const containerRef = useRef<HTMLDivElement>(null);
@ -116,9 +117,18 @@ export const BusterListReactWindow: React.FC<BusterListProps> = ({
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
]);
//context menu click away
useEffect(() => {

View File

@ -87,10 +87,7 @@ export const BusterListRowComponent = React.memo(
</LinkWrapper>
);
}
),
(prevProps, nextProps) => {
return prevProps.checked === nextProps.checked && prevProps.row.id === nextProps.row.id;
}
)
);
BusterListRowComponent.displayName = 'BusterListRowComponent';