1
0
Fork 0
mirror of https://github.com/jellyfin/jellyfin-web synced 2025-03-30 19:56:21 +00:00
This commit is contained in:
SHestres 2025-03-30 11:01:14 -04:00 committed by GitHub
commit 671e577689
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 46 additions and 7 deletions

View file

@ -149,9 +149,17 @@ const UserNew = () => {
}).catch(err => { }).catch(err => {
console.error('[usernew] failed to update user policy', err); console.error('[usernew] failed to update user policy', err);
}); });
}, function () { }, function (error) {
try {
console.error('[usernew] failed to create new user', error);
error.text().then((errorMessage: string) => {
toast(errorMessage);
loading.hide();
});
} catch {
toast(globalize.translate('ErrorDefault')); toast(globalize.translate('ErrorDefault'));
loading.hide(); loading.hide();
}
}); });
}; };
@ -198,6 +206,7 @@ const UserNew = () => {
type='text' type='text'
id='txtUsername' id='txtUsername'
label='LabelName' label='LabelName'
validator={{ pattern: '^([\\w \\-\'._@+]*)([\\w\\-\'._@+])([\\w \\-\'._@+]*)$', errMessage: globalize.translate('MessageInvalidUsernameFormat') }}
options={'required'} options={'required'}
/> />
</div> </div>

View file

@ -230,7 +230,16 @@ const UserEdit = () => {
)).then(() => { )).then(() => {
onSaveComplete(); onSaveComplete();
}).catch(err => { }).catch(err => {
try {
console.error('[useredit] failed to update user', err); console.error('[useredit] failed to update user', err);
err.text().then((errorMessage: string) => {
toast(errorMessage);
loading.hide();
});
} catch {
toast(globalize.translate('ErrorDefault'));
loading.hide();
}
}); });
}; };
@ -318,6 +327,7 @@ const UserEdit = () => {
type='text' type='text'
id='txtUserName' id='txtUserName'
label='LabelName' label='LabelName'
validator={{ pattern: '^([\\w \\-\'._@+]*)([\\w\\-\'._@+])([\\w \\-\'._@+]*)$', errMessage: globalize.translate('MessageInvalidUsernameFormat') }}
options={'required'} options={'required'}
/> />
</div> </div>

View file

@ -2,23 +2,30 @@ import React, { type FC, useCallback, useEffect, useMemo, useRef } from 'react';
import globalize from 'lib/globalize'; import globalize from 'lib/globalize';
import './InputElementInvalidMessage.scss';
interface CreateInputElementParams { interface CreateInputElementParams {
type?: string type?: string
id?: string id?: string
label?: string label?: string
initialValue?: string initialValue?: string
validator?: { pattern: string, errMessage: string }
options?: string options?: string
} }
const createInputElement = ({ type, id, label, initialValue, options }: CreateInputElementParams) => ({ const createInputElement = ({ type, id, label, initialValue, validator, options }: CreateInputElementParams) => ({
__html: `<input __html: `<input
is="emby-input" is="emby-input"
type="${type}" type="${type}"
id="${id}" id="${id}"
label="${label}" label="${label}"
value="${initialValue}" value="${initialValue}"
${validator ? 'pattern="' + validator.pattern + '"' : ''}
${options} ${options}
/>` />
<div class="inputElementInvalidMessage">
${validator?.errMessage || ''}
</div>`
}); });
type InputElementProps = { type InputElementProps = {
@ -33,7 +40,9 @@ const InputElement: FC<InputElementProps> = ({
type, type,
id, id,
label, label,
validator,
options = '' options = ''
}) => { }) => {
const container = useRef<HTMLDivElement>(null); const container = useRef<HTMLDivElement>(null);
@ -44,14 +53,16 @@ const InputElement: FC<InputElementProps> = ({
id, id,
label: globalize.translate(label), label: globalize.translate(label),
initialValue, initialValue,
validator,
options options
}) })
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
), []); ), []);
const onInput = useCallback((e: Event) => { const onInput = useCallback((e: Event) => {
if (validator) (e.target as HTMLElement).parentElement?.querySelector('.inputElementInvalidMessage')?.classList.add('inputReadyForValidation');
onChange((e.target as HTMLInputElement).value); onChange((e.target as HTMLInputElement).value);
}, [ onChange ]); }, [ onChange, validator ]);
useEffect(() => { useEffect(() => {
const inputElement = container?.current?.querySelector<HTMLInputElement>('input'); const inputElement = container?.current?.querySelector<HTMLInputElement>('input');

View file

@ -0,0 +1,8 @@
.inputElementInvalidMessage {
color: red;
display: none;
}
.emby-input:invalid + .inputElementInvalidMessage.inputReadyForValidation {
display: block;
}

View file

@ -1124,6 +1124,7 @@
"MessageImageTypeNotSelected": "Please select an image type from the drop-down menu.", "MessageImageTypeNotSelected": "Please select an image type from the drop-down menu.",
"MessageInvalidForgotPasswordPin": "An invalid or expired PIN code was entered. Please try again.", "MessageInvalidForgotPasswordPin": "An invalid or expired PIN code was entered. Please try again.",
"MessageInvalidUser": "Invalid username or password. Please try again.", "MessageInvalidUser": "Invalid username or password. Please try again.",
"MessageInvalidUsernameFormat": "Username must not be empty and contain only numbers, letters, spaces, or the following symbols -'._@+",
"MessageItemsAdded": "Items added.", "MessageItemsAdded": "Items added.",
"MessageItemSaved": "Item saved.", "MessageItemSaved": "Item saved.",
"MessageLeaveEmptyToInherit": "Leave empty to inherit settings from a parent item or the global default value.", "MessageLeaveEmptyToInherit": "Leave empty to inherit settings from a parent item or the global default value.",