Merge pull request #6729 from thornbill/terite-less-dangerous
This commit is contained in:
@@ -6,7 +6,7 @@ import loading from '../../../../components/loading/loading';
|
||||
import globalize from '../../../../lib/globalize';
|
||||
import toast from '../../../../components/toast/toast';
|
||||
import SectionTabs from '../../../../components/dashboard/users/SectionTabs';
|
||||
import ButtonElement from '../../../../elements/ButtonElement';
|
||||
import Button from '../../../../elements/emby-button/Button';
|
||||
import SectionTitleContainer from '../../../../elements/SectionTitleContainer';
|
||||
import AccessContainer from '../../../../components/dashboard/users/AccessContainer';
|
||||
import CheckBoxElement from '../../../../elements/CheckBoxElement';
|
||||
@@ -316,10 +316,10 @@ const UserLibraryAccess = () => {
|
||||
</AccessContainer>
|
||||
<br />
|
||||
<div>
|
||||
<ButtonElement
|
||||
<Button
|
||||
type='submit'
|
||||
className='raised button-submit block'
|
||||
title='Save'
|
||||
title={globalize.translate('Save')}
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -6,8 +6,8 @@ import globalize from '../../../../lib/globalize';
|
||||
import loading from '../../../../components/loading/loading';
|
||||
import toast from '../../../../components/toast/toast';
|
||||
import SectionTitleContainer from '../../../../elements/SectionTitleContainer';
|
||||
import InputElement from '../../../../elements/InputElement';
|
||||
import ButtonElement from '../../../../elements/ButtonElement';
|
||||
import Input from '../../../../elements/emby-input/Input';
|
||||
import Button from '../../../../elements/emby-button/Button';
|
||||
import AccessContainer from '../../../../components/dashboard/users/AccessContainer';
|
||||
import CheckBoxElement from '../../../../elements/CheckBoxElement';
|
||||
import Page from '../../../../components/Page';
|
||||
@@ -194,18 +194,18 @@ const UserNew = () => {
|
||||
|
||||
<form className='newUserProfileForm'>
|
||||
<div className='inputContainer'>
|
||||
<InputElement
|
||||
<Input
|
||||
type='text'
|
||||
id='txtUsername'
|
||||
label='LabelName'
|
||||
options={'required'}
|
||||
label={globalize.translate('LabelName')}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div className='inputContainer'>
|
||||
<InputElement
|
||||
<Input
|
||||
type='password'
|
||||
id='txtPassword'
|
||||
label='LabelPassword'
|
||||
label={globalize.translate('LabelPassword')}
|
||||
/>
|
||||
</div>
|
||||
<AccessContainer
|
||||
@@ -248,16 +248,16 @@ const UserNew = () => {
|
||||
))}
|
||||
</AccessContainer>
|
||||
<div>
|
||||
<ButtonElement
|
||||
<Button
|
||||
type='submit'
|
||||
className='raised button-submit block'
|
||||
title='Save'
|
||||
title={globalize.translate('Save')}
|
||||
/>
|
||||
<ButtonElement
|
||||
<Button
|
||||
type='button'
|
||||
id='btnCancel'
|
||||
className='raised button-cancel block'
|
||||
title='ButtonCancel'
|
||||
title={globalize.translate('ButtonCancel')}
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -8,7 +8,7 @@ import { useSearchParams } from 'react-router-dom';
|
||||
import globalize from '../../../../lib/globalize';
|
||||
import AccessScheduleList from '../../../../components/dashboard/users/AccessScheduleList';
|
||||
import TagList from '../../../../components/dashboard/users/TagList';
|
||||
import ButtonElement from '../../../../elements/ButtonElement';
|
||||
import Button from '../../../../elements/emby-button/Button';
|
||||
import SectionTitleContainer from '../../../../elements/SectionTitleContainer';
|
||||
import SectionTabs from '../../../../components/dashboard/users/SectionTabs';
|
||||
import loading from '../../../../components/loading/loading';
|
||||
@@ -480,10 +480,10 @@ const UserParentalControl = () => {
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<ButtonElement
|
||||
<Button
|
||||
type='submit'
|
||||
className='raised button-submit block'
|
||||
title='Save'
|
||||
title={globalize.translate('Save')}
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -5,10 +5,10 @@ import { useSearchParams } from 'react-router-dom';
|
||||
|
||||
import Dashboard from '../../../../utils/dashboard';
|
||||
import globalize from '../../../../lib/globalize';
|
||||
import ButtonElement from '../../../../elements/ButtonElement';
|
||||
import Button from '../../../../elements/emby-button/Button';
|
||||
import CheckBoxElement from '../../../../elements/CheckBoxElement';
|
||||
import InputElement from '../../../../elements/InputElement';
|
||||
import LinkButton from '../../../../elements/emby-button/LinkButton';
|
||||
import Input from '../../../../elements/emby-input/Input';
|
||||
import SectionTitleContainer from '../../../../elements/SectionTitleContainer';
|
||||
import SectionTabs from '../../../../components/dashboard/users/SectionTabs';
|
||||
import loading from '../../../../components/loading/loading';
|
||||
@@ -314,11 +314,11 @@ const UserEdit = () => {
|
||||
</div>
|
||||
</div>
|
||||
<div id='fldUserName' className='inputContainer'>
|
||||
<InputElement
|
||||
<Input
|
||||
type='text'
|
||||
id='txtUserName'
|
||||
label='LabelName'
|
||||
options={'required'}
|
||||
label={globalize.translate('LabelName')}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div className='selectContainer fldSelectLoginProvider hide'>
|
||||
@@ -416,11 +416,14 @@ const UserEdit = () => {
|
||||
<br />
|
||||
<div className='verticalSection'>
|
||||
<div className='inputContainer'>
|
||||
<InputElement
|
||||
<Input
|
||||
type='number'
|
||||
id='txtRemoteClientBitrateLimit'
|
||||
label='LabelRemoteClientBitrateLimit'
|
||||
options={'inputMode="decimal" pattern="[0-9]*(.[0-9]+)?" min="{0}" step=".25"'}
|
||||
label={globalize.translate('LabelRemoteClientBitrateLimit')}
|
||||
inputMode='decimal'
|
||||
pattern='[0-9]*(.[0-9]+)?'
|
||||
min='0'
|
||||
step='.25'
|
||||
/>
|
||||
<div className='fieldDescription'>
|
||||
{globalize.translate('LabelRemoteClientBitrateLimitHelp')}
|
||||
@@ -517,11 +520,11 @@ const UserEdit = () => {
|
||||
<br />
|
||||
<div className='verticalSection'>
|
||||
<div className='inputContainer' id='fldLoginAttemptsBeforeLockout'>
|
||||
<InputElement
|
||||
<Input
|
||||
type='number'
|
||||
id='txtLoginAttemptsBeforeLockout'
|
||||
label='LabelUserLoginAttemptsBeforeLockout'
|
||||
options={'min={-1} step={1}'}
|
||||
label={globalize.translate('LabelUserLoginAttemptsBeforeLockout')}
|
||||
min={-1} step={1}
|
||||
/>
|
||||
<div className='fieldDescription'>
|
||||
{globalize.translate('OptionLoginAttemptsBeforeLockout')}
|
||||
@@ -534,11 +537,11 @@ const UserEdit = () => {
|
||||
<br />
|
||||
<div className='verticalSection'>
|
||||
<div className='inputContainer' id='fldMaxActiveSessions'>
|
||||
<InputElement
|
||||
<Input
|
||||
type='number'
|
||||
id='txtMaxActiveSessions'
|
||||
label='LabelUserMaxActiveSessions'
|
||||
options={'min={0} step={1}'}
|
||||
label={globalize.translate('LabelUserMaxActiveSessions')}
|
||||
min={0} step={1}
|
||||
/>
|
||||
<div className='fieldDescription'>
|
||||
{globalize.translate('OptionMaxActiveSessions')}
|
||||
@@ -550,16 +553,16 @@ const UserEdit = () => {
|
||||
</div>
|
||||
<br />
|
||||
<div>
|
||||
<ButtonElement
|
||||
<Button
|
||||
type='submit'
|
||||
className='raised button-submit block'
|
||||
title='Save'
|
||||
title={globalize.translate('Save')}
|
||||
/>
|
||||
<ButtonElement
|
||||
<Button
|
||||
type='button'
|
||||
id='btnCancel'
|
||||
className='raised button-cancel block'
|
||||
title='ButtonCancel'
|
||||
title={globalize.translate('ButtonCancel')}
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { getQuickConnectApi } from '@jellyfin/sdk/lib/utils/api/quick-connect-api';
|
||||
import React, { FC, FormEvent, useCallback, useMemo, useState } from 'react';
|
||||
import React, { FC, FormEvent, useCallback, useState } from 'react';
|
||||
import { Link, useSearchParams } from 'react-router-dom';
|
||||
|
||||
import Page from 'components/Page';
|
||||
import globalize from 'lib/globalize';
|
||||
import InputElement from 'elements/InputElement';
|
||||
import ButtonElement from 'elements/ButtonElement';
|
||||
import Input from 'elements/emby-input/Input';
|
||||
import Button from 'elements/emby-button/Button';
|
||||
import { useApi } from 'hooks/useApi';
|
||||
|
||||
import './quickConnect.scss';
|
||||
@@ -13,14 +13,12 @@ import './quickConnect.scss';
|
||||
const QuickConnectPage: FC = () => {
|
||||
const { api, user } = useApi();
|
||||
const [ searchParams ] = useSearchParams();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
const initialValue = useMemo(() => searchParams.get('code') ?? '', []);
|
||||
const [ code, setCode ] = useState(initialValue);
|
||||
const [ code, setCode ] = useState(searchParams.get('code') ?? '');
|
||||
const [ error, setError ] = useState<string>();
|
||||
const [ success, setSuccess ] = useState(false);
|
||||
|
||||
const onCodeChange = useCallback((value: string) => {
|
||||
setCode(value);
|
||||
const onCodeChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setCode(event.currentTarget.value);
|
||||
}, []);
|
||||
|
||||
const onSubmitCode = useCallback((e: FormEvent<HTMLFormElement>) => {
|
||||
@@ -90,16 +88,21 @@ const QuickConnectPage: FC = () => {
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<InputElement
|
||||
containerClassName='inputContainer'
|
||||
initialValue={initialValue}
|
||||
onChange={onCodeChange}
|
||||
id='txtQuickConnectCode'
|
||||
label='LabelQuickConnectCode'
|
||||
type='text'
|
||||
options="inputmode='numeric' pattern='[0-9\s]*' minlength='6' required autocomplete='off'"
|
||||
/>
|
||||
<ButtonElement
|
||||
<div className='inputContainer'>
|
||||
<Input
|
||||
value={code}
|
||||
onChange={onCodeChange}
|
||||
id='txtQuickConnectCode'
|
||||
label={globalize.translate('LabelQuickConnectCode')}
|
||||
type='text'
|
||||
inputMode='numeric'
|
||||
pattern='[0-9\s]*'
|
||||
minLength={6}
|
||||
required
|
||||
autoComplete='off'
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
type='submit'
|
||||
className='raised button-submit block'
|
||||
title={globalize.translate('Authorize')}
|
||||
|
||||
@@ -7,7 +7,7 @@ import Dashboard from '../../../../utils/dashboard';
|
||||
import globalize from '../../../../lib/globalize';
|
||||
import { appHost } from '../../../../components/apphost';
|
||||
import confirm from '../../../../components/confirm/confirm';
|
||||
import ButtonElement from '../../../../elements/ButtonElement';
|
||||
import Button from '../../../../elements/emby-button/Button';
|
||||
import UserPasswordForm from '../../../../components/dashboard/users/UserPasswordForm';
|
||||
import loading from '../../../../components/loading/loading';
|
||||
import toast from '../../../../components/toast/toast';
|
||||
@@ -197,17 +197,17 @@ const UserProfile: FunctionComponent = () => {
|
||||
{userName}
|
||||
</h2>
|
||||
<br />
|
||||
<ButtonElement
|
||||
<Button
|
||||
type='button'
|
||||
id='btnAddImage'
|
||||
className='raised button-submit hide'
|
||||
title='ButtonAddImage'
|
||||
title={globalize.translate('ButtonAddImage')}
|
||||
/>
|
||||
<ButtonElement
|
||||
<Button
|
||||
type='button'
|
||||
id='btnDeleteImage'
|
||||
className='raised hide'
|
||||
title='DeleteImage'
|
||||
title={globalize.translate('DeleteImage')}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -5,8 +5,8 @@ import globalize from '../../../lib/globalize';
|
||||
import confirm from '../../confirm/confirm';
|
||||
import loading from '../../loading/loading';
|
||||
import toast from '../../toast/toast';
|
||||
import ButtonElement from '../../../elements/ButtonElement';
|
||||
import InputElement from '../../../elements/InputElement';
|
||||
import Button from '../../../elements/emby-button/Button';
|
||||
import Input from '../../../elements/emby-input/Input';
|
||||
|
||||
type IProps = {
|
||||
userId: string | null;
|
||||
@@ -158,41 +158,41 @@ const UserPasswordForm: FunctionComponent<IProps> = ({ userId }: IProps) => {
|
||||
>
|
||||
<div className='detailSection'>
|
||||
<div id='fldCurrentPassword' className='inputContainer hide'>
|
||||
<InputElement
|
||||
<Input
|
||||
type='password'
|
||||
id='txtCurrentPassword'
|
||||
label='LabelCurrentPassword'
|
||||
options={'autoComplete="off"'}
|
||||
label={globalize.translate('LabelCurrentPassword')}
|
||||
autoComplete='off'
|
||||
/>
|
||||
</div>
|
||||
<div className='inputContainer'>
|
||||
<InputElement
|
||||
<Input
|
||||
type='password'
|
||||
id='txtNewPassword'
|
||||
label='LabelNewPassword'
|
||||
options={'autoComplete="off"'}
|
||||
label={globalize.translate('LabelNewPassword')}
|
||||
autoComplete='off'
|
||||
/>
|
||||
</div>
|
||||
<div className='inputContainer'>
|
||||
<InputElement
|
||||
<Input
|
||||
type='password'
|
||||
id='txtNewPasswordConfirm'
|
||||
label='LabelNewPasswordConfirm'
|
||||
options={'autoComplete="off"'}
|
||||
label={globalize.translate('LabelNewPasswordConfirm')}
|
||||
autoComplete='off'
|
||||
/>
|
||||
</div>
|
||||
<br />
|
||||
<div>
|
||||
<ButtonElement
|
||||
<Button
|
||||
type='submit'
|
||||
className='raised button-submit block'
|
||||
title='SavePassword'
|
||||
title={globalize.translate('SavePassword')}
|
||||
/>
|
||||
<ButtonElement
|
||||
<Button
|
||||
type='button'
|
||||
id='btnResetPassword'
|
||||
className='raised button-cancel block hide'
|
||||
title='ResetPassword'
|
||||
title={globalize.translate('ResetPassword')}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
import React, { FunctionComponent } from 'react';
|
||||
|
||||
import globalize from 'lib/globalize';
|
||||
|
||||
const createButtonElement = ({ type, id, className, title, leftIcon, rightIcon }: IProps) => ({
|
||||
__html: `<button
|
||||
is="emby-button"
|
||||
type="${type}"
|
||||
${id}
|
||||
class="${className}"
|
||||
>
|
||||
${leftIcon}
|
||||
<span>${title}</span>
|
||||
${rightIcon}
|
||||
</button>`
|
||||
});
|
||||
|
||||
type IProps = {
|
||||
type?: string;
|
||||
id?: string;
|
||||
className?: string;
|
||||
title?: string;
|
||||
leftIcon?: string;
|
||||
rightIcon?: string;
|
||||
};
|
||||
|
||||
const ButtonElement: FunctionComponent<IProps> = ({ type, id, className, title, leftIcon, rightIcon }: IProps) => {
|
||||
return (
|
||||
<div
|
||||
dangerouslySetInnerHTML={createButtonElement({
|
||||
type: type,
|
||||
id: id ? `id="${id}"` : '',
|
||||
className: className,
|
||||
title: globalize.translate(title),
|
||||
leftIcon: leftIcon ? `<span class="material-icons ${leftIcon}" aria-hidden="true"></span>` : '',
|
||||
rightIcon: rightIcon ? `<span class="material-icons ${rightIcon}" aria-hidden="true"></span>` : ''
|
||||
})}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default ButtonElement;
|
||||
@@ -1,74 +0,0 @@
|
||||
import React, { type FC, useCallback, useEffect, useMemo, useRef } from 'react';
|
||||
|
||||
import globalize from 'lib/globalize';
|
||||
|
||||
interface CreateInputElementParams {
|
||||
type?: string
|
||||
id?: string
|
||||
label?: string
|
||||
initialValue?: string
|
||||
options?: string
|
||||
}
|
||||
|
||||
const createInputElement = ({ type, id, label, initialValue, options }: CreateInputElementParams) => ({
|
||||
__html: `<input
|
||||
is="emby-input"
|
||||
type="${type}"
|
||||
id="${id}"
|
||||
label="${label}"
|
||||
value="${initialValue}"
|
||||
${options}
|
||||
/>`
|
||||
});
|
||||
|
||||
type InputElementProps = {
|
||||
containerClassName?: string
|
||||
onChange?: (value: string) => void
|
||||
} & CreateInputElementParams;
|
||||
|
||||
const InputElement: FC<InputElementProps> = ({
|
||||
containerClassName,
|
||||
initialValue,
|
||||
onChange = () => { /* no-op */ },
|
||||
type,
|
||||
id,
|
||||
label,
|
||||
options = ''
|
||||
}) => {
|
||||
const container = useRef<HTMLDivElement>(null);
|
||||
|
||||
// NOTE: We need to memoize the input html because any re-render will break the webcomponent
|
||||
const inputHtml = useMemo(() => (
|
||||
createInputElement({
|
||||
type,
|
||||
id,
|
||||
label: globalize.translate(label),
|
||||
initialValue,
|
||||
options
|
||||
})
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
), []);
|
||||
|
||||
const onInput = useCallback((e: Event) => {
|
||||
onChange((e.target as HTMLInputElement).value);
|
||||
}, [ onChange ]);
|
||||
|
||||
useEffect(() => {
|
||||
const inputElement = container?.current?.querySelector<HTMLInputElement>('input');
|
||||
inputElement?.addEventListener('input', onInput);
|
||||
|
||||
return () => {
|
||||
inputElement?.removeEventListener('input', onInput);
|
||||
};
|
||||
}, [ container, onInput ]);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={container}
|
||||
className={containerClassName}
|
||||
dangerouslySetInnerHTML={inputHtml}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default InputElement;
|
||||
Reference in New Issue
Block a user