diff --git a/web/src/app/app/(settings_layout)/settings/(permissions)/users/page.tsx b/web/src/app/app/(settings_layout)/settings/(permissions)/users/page.tsx index 39a084082..c3de19c74 100644 --- a/web/src/app/app/(settings_layout)/settings/(permissions)/users/page.tsx +++ b/web/src/app/app/(settings_layout)/settings/(permissions)/users/page.tsx @@ -11,6 +11,7 @@ import { useInviteModalStore } from '@/context/BusterAppLayout'; import { InvitePeopleModal } from '@/components/features/modal/InvitePeopleModal'; import { useMemoizedFn } from '@/hooks'; import { Button } from '@/components/ui/buttons'; +import { Plus } from '@/components/ui/icons'; export default function Page() { const userOrganization = useUserConfigContextSelector((x) => x.userOrganizations); @@ -43,7 +44,9 @@ export default function Page() { setSearchText={handleSearchChange} /> - + diff --git a/web/src/components/features/auth/LoginForm.tsx b/web/src/components/features/auth/LoginForm.tsx index 3a4ecfc14..c91e71a85 100644 --- a/web/src/components/features/auth/LoginForm.tsx +++ b/web/src/components/features/auth/LoginForm.tsx @@ -67,7 +67,7 @@ export const LoginForm: React.FC<{}> = ({}) => { } catch (error: any) { errorFallback(error); } - setLoading('google'); + setLoading(null); }); const onSignInWithGithub = useMemoizedFn(async () => { @@ -78,7 +78,7 @@ export const LoginForm: React.FC<{}> = ({}) => { } catch (error: any) { errorFallback(error); } - setLoading('github'); + setLoading(null); }); const onSignInWithAzure = useMemoizedFn(async () => { @@ -182,6 +182,10 @@ const LoginOptions: React.FC<{ Object.keys(Cookies.get()).forEach((cookieName) => { Cookies.remove(cookieName); }); + + //also clear local storage + localStorage.clear(); + sessionStorage.clear(); }); const onSubmitClickPreflight = useMemoizedFn(async (d: { email: string; password: string }) => { diff --git a/web/src/components/features/modal/InvitePeopleModal.tsx b/web/src/components/features/modal/InvitePeopleModal.tsx index e0284ec81..658c36f88 100644 --- a/web/src/components/features/modal/InvitePeopleModal.tsx +++ b/web/src/components/features/modal/InvitePeopleModal.tsx @@ -5,6 +5,7 @@ import { InputTagInput } from '@/components/ui/inputs/InputTagInput'; import { useInviteUser } from '@/api/buster_rest/users'; import { validate } from 'email-validator'; import { useBusterNotifications } from '@/context/BusterNotifications'; +import uniq from 'lodash/uniq'; export const InvitePeopleModal: React.FC<{ open: boolean; @@ -12,10 +13,12 @@ export const InvitePeopleModal: React.FC<{ }> = React.memo(({ open, onClose }) => { const [emails, setEmails] = React.useState([]); const { mutateAsync: inviteUsers, isPending: inviting } = useInviteUser(); + const [inputText, setInputText] = React.useState(''); const { openErrorMessage } = useBusterNotifications(); const handleInvite = useMemoizedFn(async () => { - await inviteUsers({ emails }); + const allEmails = uniq([...emails, inputText].filter((email) => !!email && validate(email))); + await inviteUsers({ emails: allEmails }); onClose(); }); @@ -26,22 +29,27 @@ export const InvitePeopleModal: React.FC<{ }; }, []); + const isInputTextValidEmail = useMemo(() => { + return validate(inputText); + }, [inputText]); + const memoizedFooter = useMemo(() => { return { primaryButton: { text: 'Send invites', onClick: handleInvite, loading: inviting, - disabled: emails.length === 0 + disabled: inputText.length ? !isInputTextValidEmail : emails.length === 0 } }; - }, [inviting, emails.length]); + }, [inviting, isInputTextValidEmail, emails.length, inputText.length]); return (
{ if (validate(v)) { setEmails([...emails, v]); diff --git a/web/src/components/ui/inputs/InputTagInput.tsx b/web/src/components/ui/inputs/InputTagInput.tsx index c3edf8a98..f6bd41703 100644 --- a/web/src/components/ui/inputs/InputTagInput.tsx +++ b/web/src/components/ui/inputs/InputTagInput.tsx @@ -11,6 +11,7 @@ export interface TagInputProps extends VariantProps { tags: string[]; onTagAdd?: (tag: string) => void; onTagRemove?: (index: number) => void; + onChangeText?: (text: string) => void; placeholder?: string; disabled?: boolean; maxTags?: number; @@ -26,6 +27,7 @@ const InputTagInput = React.forwardRef( tags = [], onTagAdd, onTagRemove, + onChangeText, placeholder, disabled = false, maxTags, @@ -72,6 +74,7 @@ const InputTagInput = React.forwardRef( } else { setInputValue(value); } + onChangeText?.(value); }); // Focus the container when clicked