mirror of https://github.com/buster-so/buster.git
share menu popover
This commit is contained in:
parent
3840d64360
commit
74b832a9df
|
@ -2,7 +2,6 @@ import type { DatasetPermissionOverviewUser } from '@/api/asset_interfaces';
|
|||
import { ChevronRight } from '@/components/ui/icons';
|
||||
import { Popover } from '@/components/ui/tooltip/Popover';
|
||||
import { BusterRoutes, createBusterRoute } from '@/routes';
|
||||
import { useMemoizedFn } from 'ahooks';
|
||||
import Link from 'next/link';
|
||||
import React, { useMemo } from 'react';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import { ShareMenu } from './ShareMenu';
|
||||
import { BusterShare, ShareAssetType, ShareRole } from '@/api/asset_interfaces';
|
||||
import { Button } from 'antd';
|
||||
|
||||
const meta: Meta<typeof ShareMenu> = {
|
||||
title: 'Features/Share/ShareMenu',
|
||||
component: ShareMenu,
|
||||
parameters: {
|
||||
layout: 'centered'
|
||||
},
|
||||
decorators: [
|
||||
(Story) => (
|
||||
<div
|
||||
style={{
|
||||
width: '400px',
|
||||
height: '400px',
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center'
|
||||
}}>
|
||||
<Story />
|
||||
</div>
|
||||
)
|
||||
]
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof ShareMenu>;
|
||||
|
||||
const mockShareConfig: BusterShare = {
|
||||
sharingKey: 'mock-sharing-key',
|
||||
individual_permissions: null,
|
||||
team_permissions: null,
|
||||
organization_permissions: null,
|
||||
password_secret_id: null,
|
||||
public_expiry_date: null,
|
||||
public_enabled_by: null,
|
||||
publicly_accessible: false,
|
||||
public_password: null,
|
||||
permission: ShareRole.OWNER
|
||||
};
|
||||
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
shareAssetConfig: mockShareConfig,
|
||||
assetId: '123',
|
||||
assetType: ShareAssetType.DASHBOARD,
|
||||
children: <Button>Share</Button>
|
||||
}
|
||||
};
|
||||
|
||||
export const ViewerPermission: Story = {
|
||||
args: {
|
||||
...Default.args,
|
||||
shareAssetConfig: {
|
||||
...mockShareConfig,
|
||||
permission: ShareRole.VIEWER
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const PublicAsset: Story = {
|
||||
args: {
|
||||
...Default.args,
|
||||
shareAssetConfig: {
|
||||
...mockShareConfig,
|
||||
publicly_accessible: true
|
||||
}
|
||||
}
|
||||
};
|
|
@ -1,8 +1,7 @@
|
|||
'use client';
|
||||
|
||||
import React, { PropsWithChildren } from 'react';
|
||||
import { PopoverProps } from 'antd';
|
||||
import { AppPopover } from '@/components/ui/tooltip/AppPopover';
|
||||
import { Popover } from '@/components/ui/tooltip/Popover';
|
||||
import { AppTooltip } from '@/components/ui/tooltip';
|
||||
import { useMemoizedFn } from 'ahooks';
|
||||
import { BusterShare, ShareAssetType } from '@/api/asset_interfaces';
|
||||
|
@ -11,12 +10,11 @@ import { isShareMenuVisible } from './publicHelpers';
|
|||
|
||||
export const ShareMenu: React.FC<
|
||||
PropsWithChildren<{
|
||||
placement?: PopoverProps['placement'];
|
||||
shareAssetConfig: BusterShare | null;
|
||||
assetId: string;
|
||||
assetType: ShareAssetType;
|
||||
}>
|
||||
> = ({ children, shareAssetConfig, assetId, assetType, placement = 'bottomLeft' }) => {
|
||||
> = ({ children, shareAssetConfig, assetId, assetType }) => {
|
||||
const [isOpen, setIsOpen] = React.useState(false);
|
||||
|
||||
const onOpenChange = useMemoizedFn((v: boolean) => {
|
||||
|
@ -32,10 +30,8 @@ export const ShareMenu: React.FC<
|
|||
const permission = shareAssetConfig?.permission;
|
||||
|
||||
return (
|
||||
<AppPopover
|
||||
trigger={['click']}
|
||||
destroyTooltipOnHide
|
||||
placement={placement}
|
||||
<Popover
|
||||
size={'none'}
|
||||
onOpenChange={onOpenChange}
|
||||
content={
|
||||
shareAssetConfig ? (
|
||||
|
@ -50,6 +46,6 @@ export const ShareMenu: React.FC<
|
|||
<AppTooltip title={!isOpen ? 'Share item' : ''}>
|
||||
<div className="flex">{children}</div>
|
||||
</AppTooltip>
|
||||
</AppPopover>
|
||||
</Popover>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { BusterShare, ShareRole, ShareAssetType } from '@/api/asset_interfaces';
|
||||
import { type BusterShare, ShareRole, ShareAssetType } from '@/api/asset_interfaces';
|
||||
import { useBusterNotifications } from '@/context/BusterNotifications';
|
||||
import React from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import { ShareMenuTopBar, ShareMenuTopBarOptions } from './ShareMenuTopBar';
|
||||
import { useMemoizedFn } from 'ahooks';
|
||||
import { BusterRoutes, createBusterRoute } from '@/routes/busterRoutes';
|
||||
|
@ -15,7 +15,7 @@ export const ShareMenuContent: React.FC<{
|
|||
}> = React.memo(({ assetId, assetType, shareAssetConfig, permission }) => {
|
||||
const { openSuccessMessage } = useBusterNotifications();
|
||||
const isOwner = permission === ShareRole.OWNER;
|
||||
const [selectedOptions, setSelectedOptions] = React.useState<ShareMenuTopBarOptions>(
|
||||
const [selectedOptions, setSelectedOptions] = useState<ShareMenuTopBarOptions>(
|
||||
isOwner ? ShareMenuTopBarOptions.Share : ShareMenuTopBarOptions.Embed
|
||||
);
|
||||
const previousSelection = React.useRef<ShareMenuTopBarOptions>(selectedOptions);
|
||||
|
|
|
@ -87,7 +87,7 @@ const ShareMenuContentShare: React.FC<{
|
|||
ShareRole.VIEWER
|
||||
);
|
||||
const disableSubmit = !inputHasText(inputValue) || !validate(inputValue);
|
||||
const hasUserTeams = userTeams.length > 0;
|
||||
const hasUserTeams = userTeams?.length > 0;
|
||||
|
||||
const onSubmitNewEmail = useMemoizedFn(async () => {
|
||||
const isValidEmail = validate(inputValue);
|
||||
|
|
|
@ -56,7 +56,7 @@ export const StatusDropdownContent: React.FC<{
|
|||
onSelect={onSelect}
|
||||
selectType="single"
|
||||
menuHeader="Verification status...">
|
||||
<span className="inline-block">{children}</span>
|
||||
{children}
|
||||
</Dropdown>
|
||||
);
|
||||
});
|
||||
|
|
|
@ -71,8 +71,8 @@ const DropdownMenuContent = React.forwardRef<
|
|||
footerContent?: React.ReactNode;
|
||||
}
|
||||
>(({ className, children, sideOffset = 4, footerContent, ...props }, ref) => {
|
||||
const NodeWrapper = footerContent ? 'div' : React.Fragment;
|
||||
const nodeWrapperProps = footerContent ? { className: 'p-2' } : {};
|
||||
const NodeWrapper = footerContent ? 'div' : 'span';
|
||||
const nodeWrapperProps = footerContent ? { className: 'p-2' } : { className: 'inline-block' };
|
||||
|
||||
return (
|
||||
<DropdownMenuPrimitive.Portal>
|
||||
|
|
|
@ -33,14 +33,16 @@ export const Popover = React.memo<PopoverProps>(
|
|||
}) => {
|
||||
return (
|
||||
<PopoverBase trigger={trigger} {...props}>
|
||||
<PopoverTrigger asChild>{children}</PopoverTrigger>
|
||||
<PopoverTrigger asChild>
|
||||
<span className="inline-block">{children}</span>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent
|
||||
align={align}
|
||||
side={side}
|
||||
className={className}
|
||||
size={size}
|
||||
headerContent={headerContent && <PopoverHeaderContent title={headerContent} />}>
|
||||
{content}
|
||||
<>{content}</>
|
||||
</PopoverContent>
|
||||
</PopoverBase>
|
||||
);
|
||||
|
|
|
@ -88,7 +88,9 @@ const PopoverContent = React.forwardRef<
|
|||
)}
|
||||
{...props}>
|
||||
{headerContent && <>{headerContent}</>}
|
||||
<div className={cn(popoverContentVariant({ size }), className)}>{children}</div>
|
||||
<div className={cn(popoverContentVariant({ size }), className)}>
|
||||
<>{children}</>
|
||||
</div>
|
||||
</PopoverPrimitive.Content>
|
||||
</PopoverPrimitive.Portal>
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue