mirror of https://github.com/buster-so/buster.git
tag input is updated
This commit is contained in:
parent
11f2f3e550
commit
ce738df0c1
|
@ -1,8 +1,10 @@
|
|||
import React, { useMemo } from 'react';
|
||||
import { useMemoizedFn } from '@/hooks';
|
||||
import { AppModal } from '@/components/ui/modal';
|
||||
import { TagInput } from '@/components/ui/inputs/InputTagInput';
|
||||
import { InputTagInput } from '@/components/ui/inputs/InputTagInput';
|
||||
import { useInviteUser } from '@/api/buster_rest/users';
|
||||
import { validate } from 'email-validator';
|
||||
import { useBusterNotifications } from '@/context/BusterNotifications';
|
||||
|
||||
export const InvitePeopleModal: React.FC<{
|
||||
open: boolean;
|
||||
|
@ -10,16 +12,13 @@ export const InvitePeopleModal: React.FC<{
|
|||
}> = React.memo(({ open, onClose }) => {
|
||||
const [emails, setEmails] = React.useState<string[]>([]);
|
||||
const { mutateAsync: inviteUsers, isPending: inviting } = useInviteUser();
|
||||
const { openErrorMessage } = useBusterNotifications();
|
||||
|
||||
const handleInvite = useMemoizedFn(async () => {
|
||||
await inviteUsers({ emails });
|
||||
onClose();
|
||||
});
|
||||
|
||||
const onCloseEmail = useMemoizedFn((email: string) => {
|
||||
setEmails(emails.filter((e) => e !== email));
|
||||
});
|
||||
|
||||
const memoizedHeader = useMemo(() => {
|
||||
return {
|
||||
title: 'Invite others to join your workspace',
|
||||
|
@ -41,10 +40,14 @@ export const InvitePeopleModal: React.FC<{
|
|||
return (
|
||||
<AppModal open={open} onClose={onClose} header={memoizedHeader} footer={memoizedFooter}>
|
||||
<div className="flex flex-col">
|
||||
<TagInput
|
||||
value={emails}
|
||||
<InputTagInput
|
||||
tags={emails}
|
||||
onTagAdd={(v) => {
|
||||
setEmails([...emails, v]);
|
||||
if (validate(v)) {
|
||||
setEmails([...emails, v]);
|
||||
} else {
|
||||
openErrorMessage(`Invalid email - ${v}`);
|
||||
}
|
||||
}}
|
||||
onTagRemove={(index) => {
|
||||
setEmails(emails.filter((_, i) => i !== index));
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
'use client';
|
||||
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import { TagInput } from './InputTagInput';
|
||||
import { InputTagInput } from './InputTagInput';
|
||||
import { useState } from 'react';
|
||||
import React from 'react';
|
||||
|
||||
const meta: Meta<typeof TagInput> = {
|
||||
const meta: Meta<typeof InputTagInput> = {
|
||||
title: 'UI/Inputs/InputTagInput',
|
||||
component: TagInput,
|
||||
component: InputTagInput,
|
||||
tags: ['autodocs'],
|
||||
argTypes: {
|
||||
variant: {
|
||||
|
@ -31,10 +31,10 @@ const meta: Meta<typeof TagInput> = {
|
|||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof TagInput>;
|
||||
type Story = StoryObj<typeof InputTagInput>;
|
||||
|
||||
// Interactive component for Storybook
|
||||
const InteractiveTagInput = (args: React.ComponentProps<typeof TagInput>) => {
|
||||
const InteractiveTagInput = (args: React.ComponentProps<typeof InputTagInput>) => {
|
||||
const [tags, setTags] = useState<string[]>(args.tags || []);
|
||||
|
||||
const handleTagAdd = (tag: string) => {
|
||||
|
@ -47,7 +47,9 @@ const InteractiveTagInput = (args: React.ComponentProps<typeof TagInput>) => {
|
|||
setTags(newTags);
|
||||
};
|
||||
|
||||
return <TagInput {...args} tags={tags} onTagAdd={handleTagAdd} onTagRemove={handleTagRemove} />;
|
||||
return (
|
||||
<InputTagInput {...args} tags={tags} onTagAdd={handleTagAdd} onTagRemove={handleTagRemove} />
|
||||
);
|
||||
};
|
||||
|
||||
export const Default: Story = {
|
||||
|
|
|
@ -7,18 +7,17 @@ import { useMemoizedFn } from '@/hooks';
|
|||
import { inputVariants } from './Input';
|
||||
import { InputTag } from './InputTag';
|
||||
|
||||
export interface TagInputProps
|
||||
extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size'>,
|
||||
VariantProps<typeof inputVariants> {
|
||||
tags?: string[];
|
||||
export interface TagInputProps extends VariantProps<typeof inputVariants> {
|
||||
tags: string[];
|
||||
onTagAdd?: (tag: string) => void;
|
||||
onTagRemove?: (index: number) => void;
|
||||
placeholder?: string;
|
||||
disabled?: boolean;
|
||||
maxTags?: number;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const TagInput = React.forwardRef<HTMLInputElement, TagInputProps>(
|
||||
const InputTagInput = React.forwardRef<HTMLInputElement, TagInputProps>(
|
||||
(
|
||||
{
|
||||
className,
|
||||
|
@ -116,6 +115,7 @@ const TagInput = React.forwardRef<HTMLInputElement, TagInputProps>(
|
|||
))}
|
||||
<input
|
||||
ref={ref}
|
||||
{...props}
|
||||
type="text"
|
||||
value={inputValue}
|
||||
onChange={handleInputChange}
|
||||
|
@ -123,13 +123,12 @@ const TagInput = React.forwardRef<HTMLInputElement, TagInputProps>(
|
|||
className="placeholder:text-gray-light min-w-[120px] flex-1 bg-transparent outline-none disabled:cursor-not-allowed disabled:opacity-50"
|
||||
placeholder={tags.length === 0 ? placeholder : undefined}
|
||||
disabled={isDisabledInput}
|
||||
{...props}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
TagInput.displayName = 'TagInput';
|
||||
InputTagInput.displayName = 'TagInput';
|
||||
|
||||
export { TagInput };
|
||||
export { InputTagInput };
|
||||
|
|
|
@ -135,32 +135,6 @@ export const BusterInfiniteList: React.FC<BusterInfiniteListProps> = React.memo(
|
|||
return () => scrollableParent.removeEventListener('scroll', handleScroll);
|
||||
}, [onScrollEnd, scrollEndThreshold]);
|
||||
|
||||
useWhyDidYouUpdate('BusterInfiniteList', {
|
||||
columns,
|
||||
rows,
|
||||
selectedRowKeys,
|
||||
onSelectChange,
|
||||
emptyState,
|
||||
contextMenu,
|
||||
hideLastRowBorder,
|
||||
showSelectAll,
|
||||
onScrollEnd,
|
||||
loadingNewContent,
|
||||
rowClassName,
|
||||
scrollEndThreshold,
|
||||
useRowClickSelectChange,
|
||||
showHeader,
|
||||
itemData,
|
||||
globalCheckStatus,
|
||||
lastChildIndex,
|
||||
showEmptyState,
|
||||
containerRef,
|
||||
scrollRef,
|
||||
onGlobalSelectChange,
|
||||
onSelectSectionChange,
|
||||
onSelectChangePreflight
|
||||
});
|
||||
|
||||
return (
|
||||
<div ref={containerRef} className="infinite-list-container relative">
|
||||
{showHeader && !showEmptyState && (
|
||||
|
|
|
@ -10,8 +10,6 @@ interface EmptyStateListProps {
|
|||
|
||||
export const EmptyStateList = React.memo(
|
||||
({ show = true, text, variant = 'default' }: EmptyStateListProps) => {
|
||||
console.log('hit!', show, text, variant);
|
||||
|
||||
if (!show) return null;
|
||||
|
||||
if (variant === 'card') {
|
||||
|
|
|
@ -13,7 +13,7 @@ const SelectGroup = SelectPrimitive.Group;
|
|||
const SelectValue = SelectPrimitive.Value;
|
||||
|
||||
export const selectVariants = cva(
|
||||
'flex w-full gap-x-1.5 transition-colors transition-border duration-200 items-center justify-between rounded border px-3 py-1 text-sm focus:outline-none cursor-pointer disabled:cursor-not-allowed disabled:opacity-60 [&>span]:line-clamp-1',
|
||||
'flex w-full gap-x-1.5 transition-colors transition-border text-foreground duration-200 items-center justify-between rounded border px-3 py-1 text-sm focus:outline-none cursor-pointer disabled:cursor-not-allowed disabled:opacity-60 [&>span]:line-clamp-1',
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
|
|
|
@ -157,9 +157,9 @@ const PermissionGroupAssignedCell: React.FC<{
|
|||
<div className="flex" onClick={(e) => e.stopPropagation()}>
|
||||
<Select
|
||||
items={PERMISSION_USERS_OPTIONS}
|
||||
value={assigned ? 'true' : 'false'}
|
||||
value={assigned ? 'included' : 'not_included'}
|
||||
onChange={(value) => {
|
||||
onSelect({ id, assigned: value === 'true' });
|
||||
onSelect({ id, assigned: value === 'included' });
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -58,10 +58,8 @@ const PermissionUsersAssignButton: React.FC<{
|
|||
return {
|
||||
selectable: true,
|
||||
items: options.map((v) => ({
|
||||
icon: v.icon,
|
||||
label: v.label,
|
||||
value: v.value ? 'included' : 'not_included',
|
||||
onClick: () => onAssignClick(v.value === 'true')
|
||||
...v,
|
||||
onClick: () => onAssignClick(v.value === 'included')
|
||||
}))
|
||||
};
|
||||
}, [selectedRowKeys]);
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import { SelectItem } from '@/components/ui/select';
|
||||
|
||||
export const PERMISSION_USERS_OPTIONS: SelectItem<'true' | 'false'>[] = [
|
||||
export const PERMISSION_USERS_OPTIONS: SelectItem<'included' | 'not_included'>[] = [
|
||||
{
|
||||
label: 'Assigned',
|
||||
value: 'true'
|
||||
value: 'included'
|
||||
},
|
||||
{
|
||||
label: 'Not assigned',
|
||||
value: 'false'
|
||||
value: 'not_included'
|
||||
}
|
||||
];
|
||||
|
|
Loading…
Reference in New Issue