Fixed infinite load when editing/adding user with invalid username (#8098)

* Add error messages when add/edit user fails. Add help text on username fields.

* fix linting errors

* add myself to contributors list

* Remove unused variable and restore formatting

* restore formatting

---------

Co-authored-by: Bill Thornton <thornbill@users.noreply.github.com>
This commit is contained in:
Alex
2026-07-30 19:11:50 +00:00
committed by GitHub
co-authored by Bill Thornton
parent 8fe63cd6d6
commit 2270114bb3
4 changed files with 28 additions and 0 deletions
+1
View File
@@ -108,6 +108,7 @@
- [lmaotrigine](https://github.com/lmaotrigine) - [lmaotrigine](https://github.com/lmaotrigine)
- [bjorntp](https://github.com/bjorntp) - [bjorntp](https://github.com/bjorntp)
- [austinhardaway](https://github.com/austinhardaway) - [austinhardaway](https://github.com/austinhardaway)
- [Alex Dickens](https://github.com/alex-dicko)
- [shindouj](https://github.com/shindouj) - [shindouj](https://github.com/shindouj)
## Emby Contributors ## Emby Contributors
@@ -17,6 +17,7 @@ import { useChannels } from 'apps/dashboard/features/users/api/useChannels';
import { useUpdateUser } from 'apps/dashboard/features/users/api/useUpdateUser'; import { useUpdateUser } from 'apps/dashboard/features/users/api/useUpdateUser';
import { useUpdateUserPolicy } from 'apps/dashboard/features/users/api/useUpdateUserPolicy'; import { useUpdateUserPolicy } from 'apps/dashboard/features/users/api/useUpdateUserPolicy';
import { useNetworkConfig } from 'apps/dashboard/features/users/api/useNetworkConfig'; import { useNetworkConfig } from 'apps/dashboard/features/users/api/useNetworkConfig';
import Toast from 'apps/dashboard/components/Toast';
interface ProfileProps { interface ProfileProps {
userDto: UserDto; userDto: UserDto;
@@ -45,6 +46,12 @@ const Profile = ({ userDto }: ProfileProps) => {
const { data: channels, isSuccess: isChannelsSuccess } = useChannels({ supportsMediaDeletion: true }); const { data: channels, isSuccess: isChannelsSuccess } = useChannels({ supportsMediaDeletion: true });
const { data: netConfig, isSuccess: isNetConfigSuccess } = useNetworkConfig(); const { data: netConfig, isSuccess: isNetConfigSuccess } = useNetworkConfig();
const [ isErrorToastOpen, setIsErrorToastOpen ] = useState(false);
const handleToastClose = useCallback(() => {
setIsErrorToastOpen(false);
}, []);
const updateUser = useUpdateUser(); const updateUser = useUpdateUser();
const updateUserPolicy = useUpdateUserPolicy(); const updateUserPolicy = useUpdateUserPolicy();
@@ -255,6 +262,10 @@ const Profile = ({ userDto }: ProfileProps) => {
} }
}); });
} }
},
onError: () => {
loading.hide();
setIsErrorToastOpen(true);
} }
}); });
}; };
@@ -306,6 +317,11 @@ const Profile = ({ userDto }: ProfileProps) => {
return ( return (
<div ref={element}> <div ref={element}>
<Toast
open={isErrorToastOpen}
onClose={handleToastClose}
message={globalize.translate('ErrorDefault')}
/>
<div <div
className='lnkEditUserPreferencesContainer' className='lnkEditUserPreferencesContainer'
style={{ paddingBottom: '1em' }} style={{ paddingBottom: '1em' }}
@@ -332,6 +348,9 @@ const Profile = ({ userDto }: ProfileProps) => {
label={globalize.translate('LabelName')} label={globalize.translate('LabelName')}
required required
/> />
<div className='fieldDescription'>
{globalize.translate('LabelUsernameAllowedCharactersHelp')}
</div>
</div> </div>
<div className='selectContainer fldSelectLoginProvider hide'> <div className='selectContainer fldSelectLoginProvider hide'>
<SelectElement <SelectElement
+7
View File
@@ -167,6 +167,10 @@ const UserNew = () => {
setIsErrorToastOpen(true); setIsErrorToastOpen(true);
} }
}); });
},
onError: () => {
loading.hide();
setIsErrorToastOpen(true);
} }
}); });
}; };
@@ -231,6 +235,9 @@ const UserNew = () => {
label={globalize.translate('LabelName')} label={globalize.translate('LabelName')}
required required
/> />
<div className='fieldDescription'>
{globalize.translate('LabelUsernameAllowedCharactersHelp')}
</div>
</div> </div>
<div className='inputContainer'> <div className='inputContainer'>
<Input <Input
+1
View File
@@ -1915,6 +1915,7 @@
"LabelTileWidthHelp": "Maximum number of images per tile in the X direction.", "LabelTileWidthHelp": "Maximum number of images per tile in the X direction.",
"LabelTileHeight": "Tile Height", "LabelTileHeight": "Tile Height",
"LabelTileHeightHelp": "Maximum number of images per tile in the Y direction.", "LabelTileHeightHelp": "Maximum number of images per tile in the Y direction.",
"LabelUsernameAllowedCharactersHelp": "Usernames can contain letters, numbers, spaces, and the following characters: - _ ' . @ +. They cannot begin or end with a space.",
"LabelJpegQuality": "JPEG Quality", "LabelJpegQuality": "JPEG Quality",
"LabelJpegQualityHelp": "The JPEG compression quality for trickplay images.", "LabelJpegQualityHelp": "The JPEG compression quality for trickplay images.",
"LabelQscale": "Qscale", "LabelQscale": "Qscale",