mirror of
https://github.com/jellyfin/jellyfin-web.git
synced 2024-11-17 19:08:18 -07:00
Refactoring duplicate code
This commit is contained in:
parent
b3b88cf78d
commit
9efc39f828
41
src/components/dashboard/elements/ButtonElement.tsx
Normal file
41
src/components/dashboard/elements/ButtonElement.tsx
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import React, { FunctionComponent } from 'react';
|
||||||
|
import globalize from '../../../scripts/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;
|
57
src/components/dashboard/elements/CheckBoxElement.tsx
Normal file
57
src/components/dashboard/elements/CheckBoxElement.tsx
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import escapeHTML from 'escape-html';
|
||||||
|
import React, { FunctionComponent } from 'react';
|
||||||
|
import globalize from '../../../scripts/globalize';
|
||||||
|
|
||||||
|
const createCheckBoxElement = ({ labelClassName, className, id, dataFilter, dataItemType, dataId, checkedAttribute, renderContent }: { labelClassName?: string, type?: string, className?: string, id?: string, dataFilter?: string, dataItemType?: string, dataId?: string, checkedAttribute?: string, renderContent?: string }) => ({
|
||||||
|
__html: `<label ${labelClassName}>
|
||||||
|
<input
|
||||||
|
is="emby-checkbox"
|
||||||
|
type="checkbox"
|
||||||
|
class="${className}"
|
||||||
|
${id}
|
||||||
|
${dataFilter}
|
||||||
|
${dataItemType}
|
||||||
|
${dataId}
|
||||||
|
${checkedAttribute}
|
||||||
|
/>
|
||||||
|
${renderContent}
|
||||||
|
</label>`
|
||||||
|
});
|
||||||
|
|
||||||
|
type IProps = {
|
||||||
|
labelClassName?: string;
|
||||||
|
className?: string;
|
||||||
|
elementId?: string;
|
||||||
|
dataFilter?: string;
|
||||||
|
itemType?: string;
|
||||||
|
itemId?: string;
|
||||||
|
itemAppName?: string;
|
||||||
|
itemCheckedAttribute?: string;
|
||||||
|
itemName?: string
|
||||||
|
title?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const CheckBoxElement: FunctionComponent<IProps> = ({ labelClassName, className, elementId, dataFilter, itemType, itemId, itemAppName, itemCheckedAttribute, itemName, title }: IProps) => {
|
||||||
|
const appName = itemAppName ? `- ${itemAppName}` : '';
|
||||||
|
const renderContent = itemName ?
|
||||||
|
`<span>${escapeHTML(itemName || '')} ${appName}</span>` :
|
||||||
|
`<span>${globalize.translate(title)}</span>`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className='sectioncheckbox'
|
||||||
|
dangerouslySetInnerHTML={createCheckBoxElement({
|
||||||
|
labelClassName: labelClassName ? `class='${labelClassName}'` : '',
|
||||||
|
className: className,
|
||||||
|
id: elementId ? `id='${elementId}'` : '',
|
||||||
|
dataFilter: dataFilter ? `data-filter='${dataFilter}'` : '',
|
||||||
|
dataItemType: itemType ? `data-itemtype='${itemType}'` : '',
|
||||||
|
dataId: itemId ? `data-id='${itemId}'` : '',
|
||||||
|
checkedAttribute: itemCheckedAttribute ? itemCheckedAttribute : '',
|
||||||
|
renderContent: renderContent
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CheckBoxElement;
|
49
src/components/dashboard/elements/IconButtonElement.tsx
Normal file
49
src/components/dashboard/elements/IconButtonElement.tsx
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import React, { FunctionComponent } from 'react';
|
||||||
|
import globalize from '../../../scripts/globalize';
|
||||||
|
|
||||||
|
type IProps = {
|
||||||
|
is?: string;
|
||||||
|
type?: string;
|
||||||
|
id?: string;
|
||||||
|
title?: string;
|
||||||
|
className?: string;
|
||||||
|
icon?: string,
|
||||||
|
dataIndex?: string | number;
|
||||||
|
dataTag?: string | number;
|
||||||
|
dataProfileid?: string | number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const createIconButtonElement = ({ is, type, id, className, title, icon, dataIndex, dataTag, dataProfileid }: IProps) => ({
|
||||||
|
__html: `<button
|
||||||
|
is="${is}"
|
||||||
|
type="${type}"
|
||||||
|
${id}
|
||||||
|
class="${className}"
|
||||||
|
${title}
|
||||||
|
${dataIndex}
|
||||||
|
${dataTag}
|
||||||
|
${dataProfileid}
|
||||||
|
>
|
||||||
|
<span class="material-icons ${icon}" aria-hidden="true"></span>
|
||||||
|
</button>`
|
||||||
|
});
|
||||||
|
|
||||||
|
const IconButtonElement: FunctionComponent<IProps> = ({ is, type, id, className, title, icon, dataIndex, dataTag, dataProfileid }: IProps) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
dangerouslySetInnerHTML={createIconButtonElement({
|
||||||
|
is: is,
|
||||||
|
type: type,
|
||||||
|
id: id ? `id="${id}"` : '',
|
||||||
|
className: className,
|
||||||
|
title: title ? `title="${globalize.translate(title)}"` : '',
|
||||||
|
icon: icon,
|
||||||
|
dataIndex: dataIndex ? `data-index="${dataIndex}"` : '',
|
||||||
|
dataTag: dataTag ? `data-tag="${dataTag}"` : '',
|
||||||
|
dataProfileid: dataProfileid ? `data-profileid="${dataProfileid}"` : ''
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default IconButtonElement;
|
42
src/components/dashboard/elements/SectionTitleContainer.tsx
Normal file
42
src/components/dashboard/elements/SectionTitleContainer.tsx
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import React, { FunctionComponent } from 'react';
|
||||||
|
import IconButtonElement from './IconButtonElement';
|
||||||
|
import SectionTitleLinkElement from './SectionTitleLinkElement';
|
||||||
|
|
||||||
|
type IProps = {
|
||||||
|
SectionClassName?: string;
|
||||||
|
title?: string;
|
||||||
|
isBtnVisible?: boolean;
|
||||||
|
btnId?: string;
|
||||||
|
btnClassName?: string;
|
||||||
|
btnTitle?: string;
|
||||||
|
btnIcon?: string;
|
||||||
|
isLinkVisible?: boolean;
|
||||||
|
url?: string;
|
||||||
|
}
|
||||||
|
const SectionTitleContainer: FunctionComponent<IProps> = ({SectionClassName, title, isBtnVisible = false, btnId, btnClassName, btnTitle, btnIcon, isLinkVisible = true, url}: IProps) => {
|
||||||
|
return (
|
||||||
|
<div className={`${SectionClassName} sectionTitleContainer flex align-items-center`}>
|
||||||
|
<h2 className='sectionTitle'>
|
||||||
|
{title}
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
{isBtnVisible && <IconButtonElement
|
||||||
|
is='emby-button'
|
||||||
|
type='button'
|
||||||
|
id={btnId}
|
||||||
|
className={btnClassName}
|
||||||
|
title={btnTitle}
|
||||||
|
icon={btnIcon}
|
||||||
|
/>}
|
||||||
|
|
||||||
|
{isLinkVisible && <SectionTitleLinkElement
|
||||||
|
className='raised button-alt headerHelpButton'
|
||||||
|
title='Help'
|
||||||
|
url={url}
|
||||||
|
/>}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SectionTitleContainer;
|
38
src/components/dashboard/elements/SelectElement.tsx
Normal file
38
src/components/dashboard/elements/SelectElement.tsx
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import React, { FunctionComponent } from 'react';
|
||||||
|
import globalize from '../../../scripts/globalize';
|
||||||
|
|
||||||
|
const createSelectElement = ({ name, id, required, label, option }: { name?: string, id?: string, required?: string, label?: string, option?: React.ReactNode }) => ({
|
||||||
|
__html: `<select
|
||||||
|
is="emby-select"
|
||||||
|
${name}
|
||||||
|
id="${id}"
|
||||||
|
${required}
|
||||||
|
label="${label}"
|
||||||
|
>
|
||||||
|
${option}
|
||||||
|
</select>`
|
||||||
|
});
|
||||||
|
|
||||||
|
type IProps = {
|
||||||
|
name?: string;
|
||||||
|
id?: string;
|
||||||
|
required?: string;
|
||||||
|
label?: string;
|
||||||
|
children?: React.ReactNode
|
||||||
|
}
|
||||||
|
|
||||||
|
const SelectElement: FunctionComponent<IProps> = ({ name, id, required, label, children }: IProps) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
dangerouslySetInnerHTML={createSelectElement({
|
||||||
|
name: name ? `name='${name}'` : '',
|
||||||
|
id: id,
|
||||||
|
required: required ? `required='${required}'` : '',
|
||||||
|
label: globalize.translate(label),
|
||||||
|
option: children
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SelectElement;
|
@ -1,6 +1,6 @@
|
|||||||
import React, { FunctionComponent } from 'react';
|
import React, { FunctionComponent } from 'react';
|
||||||
import globalize from '../../../scripts/globalize';
|
import globalize from '../../../scripts/globalize';
|
||||||
import CheckBoxElement from './CheckBoxElement';
|
import CheckBoxElement from '../elements/CheckBoxElement';
|
||||||
|
|
||||||
type IProps = {
|
type IProps = {
|
||||||
containerClassName?: string;
|
containerClassName?: string;
|
||||||
@ -18,7 +18,11 @@ const AccessContainer: FunctionComponent<IProps> = ({containerClassName, headerT
|
|||||||
return (
|
return (
|
||||||
<div className={containerClassName}>
|
<div className={containerClassName}>
|
||||||
<h2>{globalize.translate(headerTitle)}</h2>
|
<h2>{globalize.translate(headerTitle)}</h2>
|
||||||
<CheckBoxElement labelClassName='checkboxContainer' type='checkbox' className={checkBoxClassName} title={checkBoxTitle} />
|
<CheckBoxElement
|
||||||
|
labelClassName='checkboxContainer'
|
||||||
|
className={checkBoxClassName}
|
||||||
|
title={checkBoxTitle}
|
||||||
|
/>
|
||||||
<div className={listContainerClassName}>
|
<div className={listContainerClassName}>
|
||||||
<div className={accessClassName}>
|
<div className={accessClassName}>
|
||||||
<h3 className='checkboxListLabel'>
|
<h3 className='checkboxListLabel'>
|
||||||
|
@ -1,17 +1,7 @@
|
|||||||
import React, { FunctionComponent } from 'react';
|
import React, { FunctionComponent } from 'react';
|
||||||
import datetime from '../../../scripts/datetime';
|
import datetime from '../../../scripts/datetime';
|
||||||
import globalize from '../../../scripts/globalize';
|
import globalize from '../../../scripts/globalize';
|
||||||
|
import IconButtonElement from '../elements/IconButtonElement';
|
||||||
const createButtonElement = (index: number) => ({
|
|
||||||
__html: `<button
|
|
||||||
type='button'
|
|
||||||
is='paper-icon-button-light'
|
|
||||||
class='btnDelete listItemButton'
|
|
||||||
data-index='${index}'
|
|
||||||
>
|
|
||||||
<span class='material-icons delete' aria-hidden='true' />
|
|
||||||
</button>`
|
|
||||||
});
|
|
||||||
|
|
||||||
type IProps = {
|
type IProps = {
|
||||||
index: number;
|
index: number;
|
||||||
@ -48,8 +38,13 @@ const AccessScheduleList: FunctionComponent<IProps> = ({index, DayOfWeek, StartH
|
|||||||
{getDisplayTime(StartHour) + ' - ' + getDisplayTime(EndHour)}
|
{getDisplayTime(StartHour) + ' - ' + getDisplayTime(EndHour)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<IconButtonElement
|
||||||
dangerouslySetInnerHTML={createButtonElement(index)}
|
is='paper-icon-button-light'
|
||||||
|
type='button'
|
||||||
|
className='btnDelete listItemButton'
|
||||||
|
title='Delete'
|
||||||
|
icon='delete'
|
||||||
|
dataIndex={index}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -1,15 +1,5 @@
|
|||||||
import React, { FunctionComponent } from 'react';
|
import React, { FunctionComponent } from 'react';
|
||||||
|
import IconButtonElement from '../elements/IconButtonElement';
|
||||||
const createButtonElement = (tag?: string) => ({
|
|
||||||
__html: `<button
|
|
||||||
type='button'
|
|
||||||
is='paper-icon-button-light'
|
|
||||||
class='blockedTag btnDeleteTag listItemButton'
|
|
||||||
data-tag='${tag}'
|
|
||||||
>
|
|
||||||
<span class='material-icons delete' aria-hidden='true' />
|
|
||||||
</button>`
|
|
||||||
});
|
|
||||||
|
|
||||||
type IProps = {
|
type IProps = {
|
||||||
tag?: string;
|
tag?: string;
|
||||||
@ -24,11 +14,15 @@ const BlockedTagList: FunctionComponent<IProps> = ({tag}: IProps) => {
|
|||||||
{tag}
|
{tag}
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<IconButtonElement
|
||||||
dangerouslySetInnerHTML={createButtonElement(tag)}
|
is='paper-icon-button-light'
|
||||||
|
type='button'
|
||||||
|
className='blockedTag btnDeleteTag listItemButton'
|
||||||
|
title='Delete'
|
||||||
|
icon='delete'
|
||||||
|
dataTag={tag}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,32 +0,0 @@
|
|||||||
import React, { FunctionComponent } from 'react';
|
|
||||||
import globalize from '../../../scripts/globalize';
|
|
||||||
|
|
||||||
const createButtonElement = ({ type, className, title }: { type?: string, className?: string, title?: string }) => ({
|
|
||||||
__html: `<button
|
|
||||||
is="emby-button"
|
|
||||||
type="${type}"
|
|
||||||
class="${className}"
|
|
||||||
>
|
|
||||||
<span>${title}</span>
|
|
||||||
</button>`
|
|
||||||
});
|
|
||||||
|
|
||||||
type IProps = {
|
|
||||||
type?: string;
|
|
||||||
className?: string;
|
|
||||||
title?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
const ButtonElement: FunctionComponent<IProps> = ({ type, className, title }: IProps) => {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
dangerouslySetInnerHTML={createButtonElement({
|
|
||||||
type: type,
|
|
||||||
className: className,
|
|
||||||
title: globalize.translate(title)
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ButtonElement;
|
|
@ -1,36 +0,0 @@
|
|||||||
import React, { FunctionComponent } from 'react';
|
|
||||||
import globalize from '../../../scripts/globalize';
|
|
||||||
|
|
||||||
const createCheckBoxElement = ({ labelClassName, type, className, title }: { labelClassName?: string, type?: string, className?: string, title?: string }) => ({
|
|
||||||
__html: `<label class="${labelClassName}">
|
|
||||||
<input
|
|
||||||
is="emby-checkbox"
|
|
||||||
type="${type}"
|
|
||||||
class="${className}"
|
|
||||||
/>
|
|
||||||
<span>${title}</span>
|
|
||||||
</label>`
|
|
||||||
});
|
|
||||||
|
|
||||||
type IProps = {
|
|
||||||
labelClassName?: string;
|
|
||||||
type?: string;
|
|
||||||
className?: string;
|
|
||||||
title?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
const CheckBoxElement: FunctionComponent<IProps> = ({ labelClassName, type, className, title }: IProps) => {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className='sectioncheckbox'
|
|
||||||
dangerouslySetInnerHTML={createCheckBoxElement({
|
|
||||||
labelClassName: labelClassName ? labelClassName : '',
|
|
||||||
type: type,
|
|
||||||
className: className,
|
|
||||||
title: globalize.translate(title)
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default CheckBoxElement;
|
|
@ -1,41 +0,0 @@
|
|||||||
import escapeHtml from 'escape-html';
|
|
||||||
import React, { FunctionComponent } from 'react';
|
|
||||||
|
|
||||||
type IProps = {
|
|
||||||
className?: string;
|
|
||||||
Name?: string;
|
|
||||||
Id?: string;
|
|
||||||
ItemType?: string;
|
|
||||||
AppName?: string;
|
|
||||||
checkedAttribute?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const createCheckBoxElement = ({className, Name, dataAttributes, AppName, checkedAttribute}: {className?: string, Name?: string, dataAttributes?: string, AppName?: string, checkedAttribute?: string}) => ({
|
|
||||||
__html: `<label>
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
is="emby-checkbox"
|
|
||||||
class="${className}"
|
|
||||||
${dataAttributes} ${checkedAttribute}
|
|
||||||
/>
|
|
||||||
<span>${escapeHtml(Name || '')} ${AppName}</span>
|
|
||||||
</label>`
|
|
||||||
});
|
|
||||||
|
|
||||||
const CheckBoxListItem: FunctionComponent<IProps> = ({className, Name, Id, ItemType, AppName, checkedAttribute}: IProps) => {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className='sectioncheckbox'
|
|
||||||
dangerouslySetInnerHTML={createCheckBoxElement({
|
|
||||||
className: className,
|
|
||||||
Name: Name,
|
|
||||||
dataAttributes: ItemType ? `data-itemtype='${ItemType}'` : `data-id='${Id}'`,
|
|
||||||
AppName: AppName ? `- ${AppName}` : '',
|
|
||||||
checkedAttribute: checkedAttribute
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default CheckBoxListItem;
|
|
||||||
|
|
@ -1,34 +0,0 @@
|
|||||||
import React, { FunctionComponent } from 'react';
|
|
||||||
import globalize from '../../../scripts/globalize';
|
|
||||||
|
|
||||||
type IProps = {
|
|
||||||
title: string;
|
|
||||||
className?: string;
|
|
||||||
icon: string,
|
|
||||||
}
|
|
||||||
|
|
||||||
const createButtonElement = ({ className, title, icon }: { className?: string, title: string, icon: string }) => ({
|
|
||||||
__html: `<button
|
|
||||||
is="emby-button"
|
|
||||||
type="button"
|
|
||||||
class="${className}"
|
|
||||||
style="margin-left:1em;"
|
|
||||||
title="${title}"
|
|
||||||
>
|
|
||||||
<span class="material-icons ${icon}" aria-hidden="true"></span>
|
|
||||||
</button>`
|
|
||||||
});
|
|
||||||
|
|
||||||
const SectionTitleButtonElement: FunctionComponent<IProps> = ({ className, title, icon }: IProps) => {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
dangerouslySetInnerHTML={createButtonElement({
|
|
||||||
className: className,
|
|
||||||
title: globalize.translate(title),
|
|
||||||
icon: icon
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default SectionTitleButtonElement;
|
|
@ -1,35 +0,0 @@
|
|||||||
import React, { FunctionComponent } from 'react';
|
|
||||||
import SectionTitleButtonElement from './SectionTitleButtonElement';
|
|
||||||
import SectionTitleLinkElement from './SectionTitleLinkElement';
|
|
||||||
|
|
||||||
type IProps = {
|
|
||||||
title: string;
|
|
||||||
isBtnVisible?: boolean;
|
|
||||||
titleLink?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const SectionTitleContainer: FunctionComponent<IProps> = ({title, isBtnVisible = false, titleLink}: IProps) => {
|
|
||||||
return (
|
|
||||||
<div className='verticalSection'>
|
|
||||||
<div className='sectionTitleContainer flex align-items-center'>
|
|
||||||
<h2 className='sectionTitle'>
|
|
||||||
{title}
|
|
||||||
</h2>
|
|
||||||
|
|
||||||
{isBtnVisible && <SectionTitleButtonElement
|
|
||||||
className='fab btnAddUser submit sectionTitleButton'
|
|
||||||
title='ButtonAddUser'
|
|
||||||
icon='add'
|
|
||||||
/>}
|
|
||||||
|
|
||||||
<SectionTitleLinkElement
|
|
||||||
className='raised button-alt headerHelpButton'
|
|
||||||
title='Help'
|
|
||||||
url={titleLink}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default SectionTitleContainer;
|
|
@ -1,44 +0,0 @@
|
|||||||
import escapeHtml from 'escape-html';
|
|
||||||
import React, { FunctionComponent } from 'react';
|
|
||||||
import globalize from '../../../scripts/globalize';
|
|
||||||
|
|
||||||
const createSelectElement = ({ className, label, option }: { className?: string, label: string, option: string[] }) => ({
|
|
||||||
__html: `<select
|
|
||||||
class="${className}"
|
|
||||||
is="emby-select"
|
|
||||||
label="${label}"
|
|
||||||
>
|
|
||||||
${option}
|
|
||||||
</select>`
|
|
||||||
});
|
|
||||||
|
|
||||||
type ProvidersArr = {
|
|
||||||
Name?: string;
|
|
||||||
Id?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
type IProps = {
|
|
||||||
className?: string;
|
|
||||||
label?: string;
|
|
||||||
currentProviderId: string;
|
|
||||||
providers: ProvidersArr[]
|
|
||||||
}
|
|
||||||
|
|
||||||
const SelectElement: FunctionComponent<IProps> = ({ className, label, currentProviderId, providers }: IProps) => {
|
|
||||||
const renderOption = providers.map((provider) => {
|
|
||||||
const selected = provider.Id === currentProviderId || providers.length < 2 ? ' selected' : '';
|
|
||||||
return '<option value="' + provider.Id + '"' + selected + '>' + escapeHtml(provider.Name) + '</option>';
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
dangerouslySetInnerHTML={createSelectElement({
|
|
||||||
className: className,
|
|
||||||
label: globalize.translate(label),
|
|
||||||
option: renderOption
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default SelectElement;
|
|
@ -1,47 +0,0 @@
|
|||||||
import escapeHtml from 'escape-html';
|
|
||||||
import React, { FunctionComponent } from 'react';
|
|
||||||
import globalize from '../../../scripts/globalize';
|
|
||||||
|
|
||||||
const createSelectElement = ({ className, label, option }: { className?: string, label: string, option: string }) => ({
|
|
||||||
__html: `<select
|
|
||||||
class="${className}"
|
|
||||||
is="emby-select"
|
|
||||||
label="${label}"
|
|
||||||
>
|
|
||||||
<option value=''></option>
|
|
||||||
${option}
|
|
||||||
</select>`
|
|
||||||
});
|
|
||||||
|
|
||||||
type RatingsArr = {
|
|
||||||
Name: string;
|
|
||||||
Value: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
type IProps = {
|
|
||||||
className?: string;
|
|
||||||
label?: string;
|
|
||||||
parentalRatings: RatingsArr[];
|
|
||||||
}
|
|
||||||
|
|
||||||
const SelectMaxParentalRating: FunctionComponent<IProps> = ({ className, label, parentalRatings }: IProps) => {
|
|
||||||
const renderOption = () => {
|
|
||||||
let content = '';
|
|
||||||
for (const rating of parentalRatings) {
|
|
||||||
content += `<option value='${rating.Value}'>${escapeHtml(rating.Name)}</option>`;
|
|
||||||
}
|
|
||||||
return content;
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
dangerouslySetInnerHTML={createSelectElement({
|
|
||||||
className: className,
|
|
||||||
label: globalize.translate(label),
|
|
||||||
option: renderOption()
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default SelectMaxParentalRating;
|
|
@ -1,35 +0,0 @@
|
|||||||
import React, { FunctionComponent } from 'react';
|
|
||||||
import globalize from '../../../scripts/globalize';
|
|
||||||
|
|
||||||
const createSelectElement = ({ className, id, label }: { className?: string, id?: string, label: string }) => ({
|
|
||||||
__html: `<select
|
|
||||||
class="${className}"
|
|
||||||
is="emby-select"
|
|
||||||
id="${id}"
|
|
||||||
label="${label}"
|
|
||||||
>
|
|
||||||
<option value='CreateAndJoinGroups'>${globalize.translate('LabelSyncPlayAccessCreateAndJoinGroups')}</option>
|
|
||||||
<option value='JoinGroups'>${globalize.translate('LabelSyncPlayAccessJoinGroups')}</option>
|
|
||||||
<option value='None'>${globalize.translate('LabelSyncPlayAccessNone')}</option>
|
|
||||||
</select>`
|
|
||||||
});
|
|
||||||
|
|
||||||
type IProps = {
|
|
||||||
className?: string;
|
|
||||||
id?: string;
|
|
||||||
label?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
const SelectSyncPlayAccessElement: FunctionComponent<IProps> = ({ className, id, label }: IProps) => {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
dangerouslySetInnerHTML={createSelectElement({
|
|
||||||
className: className,
|
|
||||||
id: id,
|
|
||||||
label: globalize.translate(label)
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default SelectSyncPlayAccessElement;
|
|
@ -4,6 +4,8 @@ import { formatDistanceToNow } from 'date-fns';
|
|||||||
import { localeWithSuffix } from '../../../scripts/dfnshelper';
|
import { localeWithSuffix } from '../../../scripts/dfnshelper';
|
||||||
import globalize from '../../../scripts/globalize';
|
import globalize from '../../../scripts/globalize';
|
||||||
import cardBuilder from '../../cardbuilder/cardBuilder';
|
import cardBuilder from '../../cardbuilder/cardBuilder';
|
||||||
|
import IconButtonElement from '../elements/IconButtonElement';
|
||||||
|
import escapeHTML from 'escape-html';
|
||||||
|
|
||||||
const createLinkElement = ({ user, renderImgUrl }: { user: UserDto, renderImgUrl: string }) => ({
|
const createLinkElement = ({ user, renderImgUrl }: { user: UserDto, renderImgUrl: string }) => ({
|
||||||
__html: `<a
|
__html: `<a
|
||||||
@ -15,16 +17,6 @@ const createLinkElement = ({ user, renderImgUrl }: { user: UserDto, renderImgUrl
|
|||||||
</a>`
|
</a>`
|
||||||
});
|
});
|
||||||
|
|
||||||
const createButtonElement = () => ({
|
|
||||||
__html: `<button
|
|
||||||
is="paper-icon-button-light"
|
|
||||||
type="button"
|
|
||||||
class="btnUserMenu flex-shrink-zero"
|
|
||||||
>
|
|
||||||
<span class="material-icons more_vert" aria-hidden="true"></span>
|
|
||||||
</button>`
|
|
||||||
});
|
|
||||||
|
|
||||||
type IProps = {
|
type IProps = {
|
||||||
user?: UserDto;
|
user?: UserDto;
|
||||||
}
|
}
|
||||||
@ -81,16 +73,21 @@ const UserCardBox: FunctionComponent<IProps> = ({ user = {} }: IProps) => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className='cardFooter visualCardBox-cardFooter'>
|
<div className='cardFooter visualCardBox-cardFooter'>
|
||||||
<div className='cardText flex align-items-center'>
|
<div
|
||||||
<div className='flex-grow' style={{overflow: 'hidden', textOverflow: 'ellipsis'}}>
|
style={{textAlign: 'right', float: 'right', paddingTop: '5px'}}
|
||||||
{user.Name}
|
>
|
||||||
</div>
|
<IconButtonElement
|
||||||
<div
|
is='paper-icon-button-light'
|
||||||
dangerouslySetInnerHTML={createButtonElement()}
|
type='button'
|
||||||
|
className='btnUserMenu flex-shrink-zero'
|
||||||
|
icon='more_vert'
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div className='cardText'>
|
||||||
|
<span>{escapeHTML(user.Name)}</span>
|
||||||
|
</div>
|
||||||
<div className='cardText cardText-secondary'>
|
<div className='cardText cardText-secondary'>
|
||||||
{lastSeen != '' ? lastSeen : ''}
|
<span>{lastSeen != '' ? lastSeen : ''}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -6,9 +6,9 @@ import LibraryMenu from '../../../scripts/libraryMenu';
|
|||||||
import confirm from '../../confirm/confirm';
|
import confirm from '../../confirm/confirm';
|
||||||
import loading from '../../loading/loading';
|
import loading from '../../loading/loading';
|
||||||
import toast from '../../toast/toast';
|
import toast from '../../toast/toast';
|
||||||
import ButtonElement from './ButtonElement';
|
import ButtonElement from '../elements/ButtonElement';
|
||||||
import CheckBoxElement from './CheckBoxElement';
|
import CheckBoxElement from '../elements/CheckBoxElement';
|
||||||
import InputElement from './InputElement';
|
import InputElement from '../elements/InputElement';
|
||||||
|
|
||||||
type IProps = {
|
type IProps = {
|
||||||
userId: string;
|
userId: string;
|
||||||
@ -206,8 +206,8 @@ const UserPasswordForm: FunctionComponent<IProps> = ({userId}: IProps) => {
|
|||||||
(page.querySelector('.updatePasswordForm') as HTMLFormElement).addEventListener('submit', onSubmit);
|
(page.querySelector('.updatePasswordForm') as HTMLFormElement).addEventListener('submit', onSubmit);
|
||||||
(page.querySelector('.localAccessForm') as HTMLFormElement).addEventListener('submit', onLocalAccessSubmit);
|
(page.querySelector('.localAccessForm') as HTMLFormElement).addEventListener('submit', onLocalAccessSubmit);
|
||||||
|
|
||||||
(page.querySelector('.btnResetEasyPassword') as HTMLButtonElement).addEventListener('click', resetEasyPassword);
|
(page.querySelector('#btnResetEasyPassword') as HTMLButtonElement).addEventListener('click', resetEasyPassword);
|
||||||
(page.querySelector('.btnResetPassword') as HTMLButtonElement).addEventListener('click', resetPassword);
|
(page.querySelector('#btnResetPassword') as HTMLButtonElement).addEventListener('click', resetPassword);
|
||||||
}, [loadUser, userId]);
|
}, [loadUser, userId]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -250,7 +250,8 @@ const UserPasswordForm: FunctionComponent<IProps> = ({userId}: IProps) => {
|
|||||||
/>
|
/>
|
||||||
<ButtonElement
|
<ButtonElement
|
||||||
type='button'
|
type='button'
|
||||||
className='raised btnResetPassword button-cancel block hide'
|
id='btnResetPassword'
|
||||||
|
className='raised button-cancel block hide'
|
||||||
title='ResetPassword'
|
title='ResetPassword'
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -281,7 +282,6 @@ const UserPasswordForm: FunctionComponent<IProps> = ({userId}: IProps) => {
|
|||||||
<br />
|
<br />
|
||||||
<div className='checkboxContainer checkboxContainer-withDescription'>
|
<div className='checkboxContainer checkboxContainer-withDescription'>
|
||||||
<CheckBoxElement
|
<CheckBoxElement
|
||||||
type='checkbox'
|
|
||||||
className='chkEnableLocalEasyPassword'
|
className='chkEnableLocalEasyPassword'
|
||||||
title='LabelInNetworkSignInWithEasyPassword'
|
title='LabelInNetworkSignInWithEasyPassword'
|
||||||
/>
|
/>
|
||||||
@ -297,7 +297,8 @@ const UserPasswordForm: FunctionComponent<IProps> = ({userId}: IProps) => {
|
|||||||
/>
|
/>
|
||||||
<ButtonElement
|
<ButtonElement
|
||||||
type='button'
|
type='button'
|
||||||
className='raised btnResetEasyPassword button-cancel block hide'
|
id='btnResetEasyPassword'
|
||||||
|
className='raised button-cancel block hide'
|
||||||
title='ButtonResetEasyPassword'
|
title='ButtonResetEasyPassword'
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -4,11 +4,11 @@ import Dashboard from '../../utils/dashboard';
|
|||||||
import globalize from '../../scripts/globalize';
|
import globalize from '../../scripts/globalize';
|
||||||
import loading from '../loading/loading';
|
import loading from '../loading/loading';
|
||||||
import toast from '../toast/toast';
|
import toast from '../toast/toast';
|
||||||
import SectionTitleContainer from '../dashboard/users/SectionTitleContainer';
|
import SectionTitleContainer from '../dashboard/elements/SectionTitleContainer';
|
||||||
import InputElement from '../dashboard/users/InputElement';
|
import InputElement from '../dashboard/elements/InputElement';
|
||||||
import CheckBoxListItem from '../dashboard/users/CheckBoxListItem';
|
import ButtonElement from '../dashboard/elements/ButtonElement';
|
||||||
import ButtonElement from '../dashboard/users/ButtonElement';
|
|
||||||
import AccessContainer from '../dashboard/users/AccessContainer';
|
import AccessContainer from '../dashboard/users/AccessContainer';
|
||||||
|
import CheckBoxElement from '../dashboard/elements/CheckBoxElement';
|
||||||
|
|
||||||
type userInput = {
|
type userInput = {
|
||||||
Name?: string;
|
Name?: string;
|
||||||
@ -169,7 +169,7 @@ const NewUserPage: FunctionComponent = () => {
|
|||||||
|
|
||||||
(page.querySelector('.newUserProfileForm') as HTMLFormElement).addEventListener('submit', onSubmit);
|
(page.querySelector('.newUserProfileForm') as HTMLFormElement).addEventListener('submit', onSubmit);
|
||||||
|
|
||||||
(page.querySelector('.button-cancel') as HTMLButtonElement).addEventListener('click', function() {
|
(page.querySelector('#btnCancel') as HTMLButtonElement).addEventListener('click', function() {
|
||||||
window.history.back();
|
window.history.back();
|
||||||
});
|
});
|
||||||
}, [loadUser]);
|
}, [loadUser]);
|
||||||
@ -177,10 +177,13 @@ const NewUserPage: FunctionComponent = () => {
|
|||||||
return (
|
return (
|
||||||
<div ref={element}>
|
<div ref={element}>
|
||||||
<div className='content-primary'>
|
<div className='content-primary'>
|
||||||
<SectionTitleContainer
|
<div className='verticalSection'>
|
||||||
title={globalize.translate('HeaderAddUser')}
|
<SectionTitleContainer
|
||||||
titleLink='https://docs.jellyfin.org/general/server/users/'
|
title={globalize.translate('HeaderAddUser')}
|
||||||
/>
|
url='https://docs.jellyfin.org/general/server/users/'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<form className='newUserProfileForm'>
|
<form className='newUserProfileForm'>
|
||||||
<div className='inputContainer'>
|
<div className='inputContainer'>
|
||||||
<InputElement
|
<InputElement
|
||||||
@ -208,12 +211,11 @@ const NewUserPage: FunctionComponent = () => {
|
|||||||
description='LibraryAccessHelp'
|
description='LibraryAccessHelp'
|
||||||
>
|
>
|
||||||
{mediaFoldersItems.map(Item => (
|
{mediaFoldersItems.map(Item => (
|
||||||
<CheckBoxListItem
|
<CheckBoxElement
|
||||||
key={Item.Id}
|
key={Item.Id}
|
||||||
className='chkFolder'
|
className='chkFolder'
|
||||||
Id={Item.Id}
|
itemId={Item.Id}
|
||||||
Name={Item.Name}
|
itemName={Item.Name}
|
||||||
checkedAttribute=''
|
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</AccessContainer>
|
</AccessContainer>
|
||||||
@ -229,12 +231,11 @@ const NewUserPage: FunctionComponent = () => {
|
|||||||
description='ChannelAccessHelp'
|
description='ChannelAccessHelp'
|
||||||
>
|
>
|
||||||
{channelsItems.map(Item => (
|
{channelsItems.map(Item => (
|
||||||
<CheckBoxListItem
|
<CheckBoxElement
|
||||||
key={Item.Id}
|
key={Item.Id}
|
||||||
className='chkChannel'
|
className='chkChannel'
|
||||||
Id={Item.Id}
|
itemId={Item.Id}
|
||||||
Name={Item.Name}
|
itemName={Item.Name}
|
||||||
checkedAttribute=''
|
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</AccessContainer>
|
</AccessContainer>
|
||||||
@ -246,7 +247,8 @@ const NewUserPage: FunctionComponent = () => {
|
|||||||
/>
|
/>
|
||||||
<ButtonElement
|
<ButtonElement
|
||||||
type='button'
|
type='button'
|
||||||
className='raised button-cancel block btnCancel'
|
id='btnCancel'
|
||||||
|
className='raised button-cancel block'
|
||||||
title='ButtonCancel'
|
title='ButtonCancel'
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -3,18 +3,17 @@ import React, { FunctionComponent, useCallback, useEffect, useState, useRef } fr
|
|||||||
import Dashboard from '../../utils/dashboard';
|
import Dashboard from '../../utils/dashboard';
|
||||||
import globalize from '../../scripts/globalize';
|
import globalize from '../../scripts/globalize';
|
||||||
import LibraryMenu from '../../scripts/libraryMenu';
|
import LibraryMenu from '../../scripts/libraryMenu';
|
||||||
import ButtonElement from '../dashboard/users/ButtonElement';
|
import ButtonElement from '../dashboard/elements/ButtonElement';
|
||||||
import CheckBoxElement from '../dashboard/users/CheckBoxElement';
|
import CheckBoxElement from '../dashboard/elements/CheckBoxElement';
|
||||||
import CheckBoxListItem from '../dashboard/users/CheckBoxListItem';
|
import InputElement from '../dashboard/elements/InputElement';
|
||||||
import InputElement from '../dashboard/users/InputElement';
|
|
||||||
import LinkEditUserPreferences from '../dashboard/users/LinkEditUserPreferences';
|
import LinkEditUserPreferences from '../dashboard/users/LinkEditUserPreferences';
|
||||||
import SectionTitleContainer from '../dashboard/users/SectionTitleContainer';
|
import SectionTitleContainer from '../dashboard/elements/SectionTitleContainer';
|
||||||
import SelectElement from '../dashboard/users/SelectElement';
|
|
||||||
import SelectSyncPlayAccessElement from '../dashboard/users/SelectSyncPlayAccessElement';
|
|
||||||
import SectionTabs from '../dashboard/users/SectionTabs';
|
import SectionTabs from '../dashboard/users/SectionTabs';
|
||||||
import loading from '../loading/loading';
|
import loading from '../loading/loading';
|
||||||
import toast from '../toast/toast';
|
import toast from '../toast/toast';
|
||||||
import { getParameterByName } from '../../utils/url';
|
import { getParameterByName } from '../../utils/url';
|
||||||
|
import escapeHTML from 'escape-html';
|
||||||
|
import SelectElement from '../dashboard/elements/SelectElement';
|
||||||
|
|
||||||
type ItemsArr = {
|
type ItemsArr = {
|
||||||
Name?: string;
|
Name?: string;
|
||||||
@ -22,11 +21,16 @@ type ItemsArr = {
|
|||||||
checkedAttribute: string
|
checkedAttribute: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ProvidersArr = {
|
||||||
|
Name?: string;
|
||||||
|
Id?: string;
|
||||||
|
}
|
||||||
|
|
||||||
const UserEditPage: FunctionComponent = () => {
|
const UserEditPage: FunctionComponent = () => {
|
||||||
const [ userName, setUserName ] = useState('');
|
const [ userName, setUserName ] = useState('');
|
||||||
const [ deleteFoldersAccess, setDeleteFoldersAccess ] = useState<ItemsArr[]>([]);
|
const [ deleteFoldersAccess, setDeleteFoldersAccess ] = useState<ItemsArr[]>([]);
|
||||||
const [ authProviders, setAuthProviders ] = useState([]);
|
const [ authProviders, setAuthProviders ] = useState<ProvidersArr[]>([]);
|
||||||
const [ passwordResetProviders, setPasswordResetProviders ] = useState([]);
|
const [ passwordResetProviders, setPasswordResetProviders ] = useState<ItemsArr[]>([]);
|
||||||
|
|
||||||
const [ authenticationProviderId, setAuthenticationProviderId ] = useState('');
|
const [ authenticationProviderId, setAuthenticationProviderId ] = useState('');
|
||||||
const [ passwordResetProviderId, setPasswordResetProviderId ] = useState('');
|
const [ passwordResetProviderId, setPasswordResetProviderId ] = useState('');
|
||||||
@ -172,7 +176,7 @@ const UserEditPage: FunctionComponent = () => {
|
|||||||
(page.querySelector('#txtLoginAttemptsBeforeLockout') as HTMLInputElement).value = user.Policy.LoginAttemptsBeforeLockout || '0';
|
(page.querySelector('#txtLoginAttemptsBeforeLockout') as HTMLInputElement).value = user.Policy.LoginAttemptsBeforeLockout || '0';
|
||||||
(page.querySelector('#txtMaxActiveSessions') as HTMLInputElement).value = user.Policy.MaxActiveSessions || '0';
|
(page.querySelector('#txtMaxActiveSessions') as HTMLInputElement).value = user.Policy.MaxActiveSessions || '0';
|
||||||
if (window.ApiClient.isMinServerVersion('10.6.0')) {
|
if (window.ApiClient.isMinServerVersion('10.6.0')) {
|
||||||
(page.querySelector('#selectSyncPlayAccess') as HTMLInputElement).value = user.Policy.SyncPlayAccess;
|
(page.querySelector('#selectSyncPlayAccess') as HTMLSelectElement).value = user.Policy.SyncPlayAccess;
|
||||||
}
|
}
|
||||||
loading.hide();
|
loading.hide();
|
||||||
}, [loadAuthProviders, loadPasswordResetProviders, loadDeleteFolders ]);
|
}, [loadAuthProviders, loadPasswordResetProviders, loadDeleteFolders ]);
|
||||||
@ -227,8 +231,8 @@ const UserEditPage: FunctionComponent = () => {
|
|||||||
user.Policy.RemoteClientBitrateLimit = Math.floor(1e6 * parseFloat((page.querySelector('#txtRemoteClientBitrateLimit') as HTMLInputElement).value || '0'));
|
user.Policy.RemoteClientBitrateLimit = Math.floor(1e6 * parseFloat((page.querySelector('#txtRemoteClientBitrateLimit') as HTMLInputElement).value || '0'));
|
||||||
user.Policy.LoginAttemptsBeforeLockout = parseInt((page.querySelector('#txtLoginAttemptsBeforeLockout') as HTMLInputElement).value || '0');
|
user.Policy.LoginAttemptsBeforeLockout = parseInt((page.querySelector('#txtLoginAttemptsBeforeLockout') as HTMLInputElement).value || '0');
|
||||||
user.Policy.MaxActiveSessions = parseInt((page.querySelector('#txtMaxActiveSessions') as HTMLInputElement).value || '0');
|
user.Policy.MaxActiveSessions = parseInt((page.querySelector('#txtMaxActiveSessions') as HTMLInputElement).value || '0');
|
||||||
user.Policy.AuthenticationProviderId = (page.querySelector('.selectLoginProvider') as HTMLInputElement).value;
|
user.Policy.AuthenticationProviderId = (page.querySelector('#selectLoginProvider') as HTMLSelectElement).value;
|
||||||
user.Policy.PasswordResetProviderId = (page.querySelector('.selectPasswordResetProvider') as HTMLInputElement).value;
|
user.Policy.PasswordResetProviderId = (page.querySelector('#selectPasswordResetProvider') as HTMLSelectElement).value;
|
||||||
user.Policy.EnableContentDeletion = (page.querySelector('.chkEnableDeleteAllFolders') as HTMLInputElement).checked;
|
user.Policy.EnableContentDeletion = (page.querySelector('.chkEnableDeleteAllFolders') as HTMLInputElement).checked;
|
||||||
user.Policy.EnableContentDeletionFromFolders = user.Policy.EnableContentDeletion ? [] : Array.prototype.filter.call(page.querySelectorAll('.chkFolder'), function (c) {
|
user.Policy.EnableContentDeletionFromFolders = user.Policy.EnableContentDeletion ? [] : Array.prototype.filter.call(page.querySelectorAll('.chkFolder'), function (c) {
|
||||||
return c.checked;
|
return c.checked;
|
||||||
@ -236,7 +240,7 @@ const UserEditPage: FunctionComponent = () => {
|
|||||||
return c.getAttribute('data-id');
|
return c.getAttribute('data-id');
|
||||||
});
|
});
|
||||||
if (window.ApiClient.isMinServerVersion('10.6.0')) {
|
if (window.ApiClient.isMinServerVersion('10.6.0')) {
|
||||||
user.Policy.SyncPlayAccess = (page.querySelector('#selectSyncPlayAccess') as HTMLInputElement).value as SyncPlayUserAccessType;
|
user.Policy.SyncPlayAccess = (page.querySelector('#selectSyncPlayAccess') as HTMLSelectElement).value as SyncPlayUserAccessType;
|
||||||
}
|
}
|
||||||
window.ApiClient.updateUser(user).then(function () {
|
window.ApiClient.updateUser(user).then(function () {
|
||||||
window.ApiClient.updateUserPolicy(user.Id || '', user.Policy || {}).then(function () {
|
window.ApiClient.updateUserPolicy(user.Id || '', user.Policy || {}).then(function () {
|
||||||
@ -270,18 +274,39 @@ const UserEditPage: FunctionComponent = () => {
|
|||||||
|
|
||||||
(page.querySelector('.editUserProfileForm') as HTMLFormElement).addEventListener('submit', onSubmit);
|
(page.querySelector('.editUserProfileForm') as HTMLFormElement).addEventListener('submit', onSubmit);
|
||||||
|
|
||||||
(page.querySelector('.button-cancel') as HTMLButtonElement).addEventListener('click', function() {
|
(page.querySelector('#btnCancel') as HTMLButtonElement).addEventListener('click', function() {
|
||||||
window.history.back();
|
window.history.back();
|
||||||
});
|
});
|
||||||
}, [loadData]);
|
}, [loadData]);
|
||||||
|
|
||||||
|
const optionLoginProvider = authProviders.map((provider) => {
|
||||||
|
const selected = provider.Id === authenticationProviderId || authProviders.length < 2 ? ' selected' : '';
|
||||||
|
return `<option value="${provider.Id}"${selected}>${escapeHTML(provider.Name)}</option>`;
|
||||||
|
});
|
||||||
|
|
||||||
|
const optionPasswordResetProvider = passwordResetProviders.map((provider) => {
|
||||||
|
const selected = provider.Id === passwordResetProviderId || passwordResetProviders.length < 2 ? ' selected' : '';
|
||||||
|
return `<option value="${provider.Id}"${selected}>${escapeHTML(provider.Name)}</option>`;
|
||||||
|
});
|
||||||
|
|
||||||
|
const optionSyncPlayAccess = () => {
|
||||||
|
let content = '';
|
||||||
|
content += `<option value='CreateAndJoinGroups'>${globalize.translate('LabelSyncPlayAccessCreateAndJoinGroups')}</option>`;
|
||||||
|
content += `<option value='JoinGroups'>${globalize.translate('LabelSyncPlayAccessJoinGroups')}</option>`;
|
||||||
|
content += `<option value='None'>${globalize.translate('LabelSyncPlayAccessNone')}</option>`;
|
||||||
|
return content;
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={element}>
|
<div ref={element}>
|
||||||
<div className='content-primary'>
|
<div className='content-primary'>
|
||||||
<SectionTitleContainer
|
<div className='verticalSection'>
|
||||||
title={userName}
|
<SectionTitleContainer
|
||||||
titleLink='https://docs.jellyfin.org/general/server/users/'
|
title={userName}
|
||||||
/>
|
url='https://docs.jellyfin.org/general/server/users/'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<SectionTabs activeTab='useredit'/>
|
<SectionTabs activeTab='useredit'/>
|
||||||
<div
|
<div
|
||||||
className='lnkEditUserPreferencesContainer'
|
className='lnkEditUserPreferencesContainer'
|
||||||
@ -313,29 +338,29 @@ const UserEditPage: FunctionComponent = () => {
|
|||||||
</div>
|
</div>
|
||||||
<div className='selectContainer fldSelectLoginProvider hide'>
|
<div className='selectContainer fldSelectLoginProvider hide'>
|
||||||
<SelectElement
|
<SelectElement
|
||||||
className= 'selectLoginProvider'
|
id='selectLoginProvider'
|
||||||
label= 'LabelAuthProvider'
|
label='LabelAuthProvider'
|
||||||
currentProviderId={authenticationProviderId}
|
>
|
||||||
providers={authProviders}
|
{optionLoginProvider}
|
||||||
/>
|
</SelectElement>
|
||||||
|
|
||||||
<div className='fieldDescription'>
|
<div className='fieldDescription'>
|
||||||
{globalize.translate('AuthProviderHelp')}
|
{globalize.translate('AuthProviderHelp')}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className='selectContainer fldSelectPasswordResetProvider hide'>
|
<div className='selectContainer fldSelectPasswordResetProvider hide'>
|
||||||
<SelectElement
|
<SelectElement
|
||||||
className= 'selectPasswordResetProvider'
|
id='selectPasswordResetProvider'
|
||||||
label= 'LabelPasswordResetProvider'
|
label='LabelPasswordResetProvider'
|
||||||
currentProviderId={passwordResetProviderId}
|
>
|
||||||
providers={passwordResetProviders}
|
{optionPasswordResetProvider}
|
||||||
/>
|
</SelectElement>
|
||||||
<div className='fieldDescription'>
|
<div className='fieldDescription'>
|
||||||
{globalize.translate('PasswordResetProviderHelp')}
|
{globalize.translate('PasswordResetProviderHelp')}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className='checkboxContainer checkboxContainer-withDescription fldRemoteAccess hide'>
|
<div className='checkboxContainer checkboxContainer-withDescription fldRemoteAccess hide'>
|
||||||
<CheckBoxElement
|
<CheckBoxElement
|
||||||
type='checkbox'
|
|
||||||
className='chkRemoteAccess'
|
className='chkRemoteAccess'
|
||||||
title='AllowRemoteAccess'
|
title='AllowRemoteAccess'
|
||||||
/>
|
/>
|
||||||
@ -345,7 +370,6 @@ const UserEditPage: FunctionComponent = () => {
|
|||||||
</div>
|
</div>
|
||||||
<CheckBoxElement
|
<CheckBoxElement
|
||||||
labelClassName='checkboxContainer'
|
labelClassName='checkboxContainer'
|
||||||
type='checkbox'
|
|
||||||
className='chkIsAdmin'
|
className='chkIsAdmin'
|
||||||
title='OptionAllowUserToManageServer'
|
title='OptionAllowUserToManageServer'
|
||||||
/>
|
/>
|
||||||
@ -355,12 +379,10 @@ const UserEditPage: FunctionComponent = () => {
|
|||||||
</h2>
|
</h2>
|
||||||
<div className='checkboxList paperList' style={{padding: '.5em 1em'}}>
|
<div className='checkboxList paperList' style={{padding: '.5em 1em'}}>
|
||||||
<CheckBoxElement
|
<CheckBoxElement
|
||||||
type='checkbox'
|
|
||||||
className='chkEnableLiveTvAccess'
|
className='chkEnableLiveTvAccess'
|
||||||
title='OptionAllowBrowsingLiveTv'
|
title='OptionAllowBrowsingLiveTv'
|
||||||
/>
|
/>
|
||||||
<CheckBoxElement
|
<CheckBoxElement
|
||||||
type='checkbox'
|
|
||||||
className='chkManageLiveTv'
|
className='chkManageLiveTv'
|
||||||
title='OptionAllowManageLiveTv'
|
title='OptionAllowManageLiveTv'
|
||||||
/>
|
/>
|
||||||
@ -372,27 +394,22 @@ const UserEditPage: FunctionComponent = () => {
|
|||||||
</h2>
|
</h2>
|
||||||
<div className='checkboxList paperList' style={{padding: '.5em 1em'}}>
|
<div className='checkboxList paperList' style={{padding: '.5em 1em'}}>
|
||||||
<CheckBoxElement
|
<CheckBoxElement
|
||||||
type='checkbox'
|
|
||||||
className='chkEnableMediaPlayback'
|
className='chkEnableMediaPlayback'
|
||||||
title='OptionAllowMediaPlayback'
|
title='OptionAllowMediaPlayback'
|
||||||
/>
|
/>
|
||||||
<CheckBoxElement
|
<CheckBoxElement
|
||||||
type='checkbox'
|
|
||||||
className='chkEnableAudioPlaybackTranscoding'
|
className='chkEnableAudioPlaybackTranscoding'
|
||||||
title='OptionAllowAudioPlaybackTranscoding'
|
title='OptionAllowAudioPlaybackTranscoding'
|
||||||
/>
|
/>
|
||||||
<CheckBoxElement
|
<CheckBoxElement
|
||||||
type='checkbox'
|
|
||||||
className='chkEnableVideoPlaybackTranscoding'
|
className='chkEnableVideoPlaybackTranscoding'
|
||||||
title='OptionAllowVideoPlaybackTranscoding'
|
title='OptionAllowVideoPlaybackTranscoding'
|
||||||
/>
|
/>
|
||||||
<CheckBoxElement
|
<CheckBoxElement
|
||||||
type='checkbox'
|
|
||||||
className='chkEnableVideoPlaybackRemuxing'
|
className='chkEnableVideoPlaybackRemuxing'
|
||||||
title='OptionAllowVideoPlaybackRemuxing'
|
title='OptionAllowVideoPlaybackRemuxing'
|
||||||
/>
|
/>
|
||||||
<CheckBoxElement
|
<CheckBoxElement
|
||||||
type='checkbox'
|
|
||||||
className='chkForceRemoteSourceTranscoding'
|
className='chkForceRemoteSourceTranscoding'
|
||||||
title='OptionForceRemoteSourceTranscoding'
|
title='OptionForceRemoteSourceTranscoding'
|
||||||
/>
|
/>
|
||||||
@ -420,11 +437,12 @@ const UserEditPage: FunctionComponent = () => {
|
|||||||
</div>
|
</div>
|
||||||
<div className='verticalSection'>
|
<div className='verticalSection'>
|
||||||
<div className='selectContainer fldSelectSyncPlayAccess'>
|
<div className='selectContainer fldSelectSyncPlayAccess'>
|
||||||
<SelectSyncPlayAccessElement
|
<SelectElement
|
||||||
className='selectSyncPlayAccess'
|
|
||||||
id='selectSyncPlayAccess'
|
id='selectSyncPlayAccess'
|
||||||
label='LabelSyncPlayAccess'
|
label='LabelSyncPlayAccess'
|
||||||
/>
|
>
|
||||||
|
{optionSyncPlayAccess()}
|
||||||
|
</SelectElement>
|
||||||
<div className='fieldDescription'>
|
<div className='fieldDescription'>
|
||||||
{globalize.translate('SyncPlayAccessHelp')}
|
{globalize.translate('SyncPlayAccessHelp')}
|
||||||
</div>
|
</div>
|
||||||
@ -437,18 +455,17 @@ const UserEditPage: FunctionComponent = () => {
|
|||||||
<div className='checkboxList paperList checkboxList-paperList'>
|
<div className='checkboxList paperList checkboxList-paperList'>
|
||||||
<CheckBoxElement
|
<CheckBoxElement
|
||||||
labelClassName='checkboxContainer'
|
labelClassName='checkboxContainer'
|
||||||
type='checkbox'
|
|
||||||
className='chkEnableDeleteAllFolders'
|
className='chkEnableDeleteAllFolders'
|
||||||
title='AllLibraries'
|
title='AllLibraries'
|
||||||
/>
|
/>
|
||||||
<div className='deleteAccess'>
|
<div className='deleteAccess'>
|
||||||
{deleteFoldersAccess.map(Item => (
|
{deleteFoldersAccess.map(Item => (
|
||||||
<CheckBoxListItem
|
<CheckBoxElement
|
||||||
key={Item.Id}
|
key={Item.Id}
|
||||||
className='chkFolder'
|
className='chkFolder'
|
||||||
Id={Item.Id}
|
itemId={Item.Id}
|
||||||
Name={Item.Name}
|
itemName={Item.Name}
|
||||||
checkedAttribute={Item.checkedAttribute}
|
itemCheckedAttribute={Item.checkedAttribute}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
@ -460,12 +477,10 @@ const UserEditPage: FunctionComponent = () => {
|
|||||||
</h2>
|
</h2>
|
||||||
<div className='checkboxList paperList' style={{padding: '.5em 1em'}}>
|
<div className='checkboxList paperList' style={{padding: '.5em 1em'}}>
|
||||||
<CheckBoxElement
|
<CheckBoxElement
|
||||||
type='checkbox'
|
|
||||||
className='chkEnableRemoteControlOtherUsers'
|
className='chkEnableRemoteControlOtherUsers'
|
||||||
title='OptionAllowRemoteControlOthers'
|
title='OptionAllowRemoteControlOthers'
|
||||||
/>
|
/>
|
||||||
<CheckBoxElement
|
<CheckBoxElement
|
||||||
type='checkbox'
|
|
||||||
className='chkRemoteControlSharedDevices'
|
className='chkRemoteControlSharedDevices'
|
||||||
title='OptionAllowRemoteSharedDevices'
|
title='OptionAllowRemoteSharedDevices'
|
||||||
/>
|
/>
|
||||||
@ -479,7 +494,6 @@ const UserEditPage: FunctionComponent = () => {
|
|||||||
</h2>
|
</h2>
|
||||||
<div className='checkboxContainer checkboxContainer-withDescription'>
|
<div className='checkboxContainer checkboxContainer-withDescription'>
|
||||||
<CheckBoxElement
|
<CheckBoxElement
|
||||||
type='checkbox'
|
|
||||||
className='chkEnableDownloading'
|
className='chkEnableDownloading'
|
||||||
title='OptionAllowContentDownload'
|
title='OptionAllowContentDownload'
|
||||||
/>
|
/>
|
||||||
@ -489,7 +503,6 @@ const UserEditPage: FunctionComponent = () => {
|
|||||||
</div>
|
</div>
|
||||||
<div className='checkboxContainer checkboxContainer-withDescription' id='fldIsEnabled'>
|
<div className='checkboxContainer checkboxContainer-withDescription' id='fldIsEnabled'>
|
||||||
<CheckBoxElement
|
<CheckBoxElement
|
||||||
type='checkbox'
|
|
||||||
className='chkDisabled'
|
className='chkDisabled'
|
||||||
title='OptionDisableUser'
|
title='OptionDisableUser'
|
||||||
/>
|
/>
|
||||||
@ -499,7 +512,6 @@ const UserEditPage: FunctionComponent = () => {
|
|||||||
</div>
|
</div>
|
||||||
<div className='checkboxContainer checkboxContainer-withDescription' id='fldIsHidden'>
|
<div className='checkboxContainer checkboxContainer-withDescription' id='fldIsHidden'>
|
||||||
<CheckBoxElement
|
<CheckBoxElement
|
||||||
type='checkbox'
|
|
||||||
className='chkIsHidden'
|
className='chkIsHidden'
|
||||||
title='OptionHideUser'
|
title='OptionHideUser'
|
||||||
/>
|
/>
|
||||||
@ -550,7 +562,8 @@ const UserEditPage: FunctionComponent = () => {
|
|||||||
/>
|
/>
|
||||||
<ButtonElement
|
<ButtonElement
|
||||||
type='button'
|
type='button'
|
||||||
className='raised button-cancel block btnCancel'
|
id='btnCancel'
|
||||||
|
className='raised button-cancel block'
|
||||||
title='ButtonCancel'
|
title='ButtonCancel'
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -6,11 +6,11 @@ import libraryMenu from '../../scripts/libraryMenu';
|
|||||||
import globalize from '../../scripts/globalize';
|
import globalize from '../../scripts/globalize';
|
||||||
import toast from '../toast/toast';
|
import toast from '../toast/toast';
|
||||||
import SectionTabs from '../dashboard/users/SectionTabs';
|
import SectionTabs from '../dashboard/users/SectionTabs';
|
||||||
import CheckBoxListItem from '../dashboard/users/CheckBoxListItem';
|
import ButtonElement from '../dashboard/elements/ButtonElement';
|
||||||
import ButtonElement from '../dashboard/users/ButtonElement';
|
|
||||||
import { getParameterByName } from '../../utils/url';
|
import { getParameterByName } from '../../utils/url';
|
||||||
import SectionTitleContainer from '../dashboard/users/SectionTitleContainer';
|
import SectionTitleContainer from '../dashboard/elements/SectionTitleContainer';
|
||||||
import AccessContainer from '../dashboard/users/AccessContainer';
|
import AccessContainer from '../dashboard/users/AccessContainer';
|
||||||
|
import CheckBoxElement from '../dashboard/elements/CheckBoxElement';
|
||||||
|
|
||||||
type ItemsArr = {
|
type ItemsArr = {
|
||||||
Name?: string;
|
Name?: string;
|
||||||
@ -228,10 +228,12 @@ const UserLibraryAccessPage: FunctionComponent = () => {
|
|||||||
return (
|
return (
|
||||||
<div ref={element}>
|
<div ref={element}>
|
||||||
<div className='content-primary'>
|
<div className='content-primary'>
|
||||||
<SectionTitleContainer
|
<div className='verticalSection'>
|
||||||
title={userName}
|
<SectionTitleContainer
|
||||||
titleLink='https://docs.jellyfin.org/general/server/users/'
|
title={userName}
|
||||||
/>
|
url='https://docs.jellyfin.org/general/server/users/'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<SectionTabs activeTab='userlibraryaccess'/>
|
<SectionTabs activeTab='userlibraryaccess'/>
|
||||||
<form className='userLibraryAccessForm'>
|
<form className='userLibraryAccessForm'>
|
||||||
<AccessContainer
|
<AccessContainer
|
||||||
@ -245,12 +247,12 @@ const UserLibraryAccessPage: FunctionComponent = () => {
|
|||||||
description='LibraryAccessHelp'
|
description='LibraryAccessHelp'
|
||||||
>
|
>
|
||||||
{mediaFoldersItems.map(Item => (
|
{mediaFoldersItems.map(Item => (
|
||||||
<CheckBoxListItem
|
<CheckBoxElement
|
||||||
key={Item.Id}
|
key={Item.Id}
|
||||||
className='chkFolder'
|
className='chkFolder'
|
||||||
Id={Item.Id}
|
itemId={Item.Id}
|
||||||
Name={Item.Name}
|
itemName={Item.Name}
|
||||||
checkedAttribute={Item.checkedAttribute}
|
itemCheckedAttribute={Item.checkedAttribute}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</AccessContainer>
|
</AccessContainer>
|
||||||
@ -266,12 +268,12 @@ const UserLibraryAccessPage: FunctionComponent = () => {
|
|||||||
description='ChannelAccessHelp'
|
description='ChannelAccessHelp'
|
||||||
>
|
>
|
||||||
{channelsItems.map(Item => (
|
{channelsItems.map(Item => (
|
||||||
<CheckBoxListItem
|
<CheckBoxElement
|
||||||
key={Item.Id}
|
key={Item.Id}
|
||||||
className='chkChannel'
|
className='chkChannel'
|
||||||
Id={Item.Id}
|
itemId={Item.Id}
|
||||||
Name={Item.Name}
|
itemName={Item.Name}
|
||||||
checkedAttribute={Item.checkedAttribute}
|
itemCheckedAttribute={Item.checkedAttribute}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</AccessContainer>
|
</AccessContainer>
|
||||||
@ -287,13 +289,13 @@ const UserLibraryAccessPage: FunctionComponent = () => {
|
|||||||
description='DeviceAccessHelp'
|
description='DeviceAccessHelp'
|
||||||
>
|
>
|
||||||
{devicesItems.map(Item => (
|
{devicesItems.map(Item => (
|
||||||
<CheckBoxListItem
|
<CheckBoxElement
|
||||||
key={Item.Id}
|
key={Item.Id}
|
||||||
className='chkDevice'
|
className='chkDevice'
|
||||||
Id={Item.Id}
|
itemId={Item.Id}
|
||||||
Name={Item.Name}
|
itemName={Item.Name}
|
||||||
AppName={Item.AppName}
|
itemAppName={Item.AppName}
|
||||||
checkedAttribute={Item.checkedAttribute}
|
itemCheckedAttribute={Item.checkedAttribute}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</AccessContainer>
|
</AccessContainer>
|
||||||
|
@ -4,15 +4,15 @@ import globalize from '../../scripts/globalize';
|
|||||||
import LibraryMenu from '../../scripts/libraryMenu';
|
import LibraryMenu from '../../scripts/libraryMenu';
|
||||||
import AccessScheduleList from '../dashboard/users/AccessScheduleList';
|
import AccessScheduleList from '../dashboard/users/AccessScheduleList';
|
||||||
import BlockedTagList from '../dashboard/users/BlockedTagList';
|
import BlockedTagList from '../dashboard/users/BlockedTagList';
|
||||||
import ButtonElement from '../dashboard/users/ButtonElement';
|
import ButtonElement from '../dashboard/elements/ButtonElement';
|
||||||
import CheckBoxListItem from '../dashboard/users/CheckBoxListItem';
|
import SectionTitleContainer from '../dashboard/elements/SectionTitleContainer';
|
||||||
import SectionTitleButtonElement from '../dashboard/users/SectionTitleButtonElement';
|
|
||||||
import SectionTitleContainer from '../dashboard/users/SectionTitleContainer';
|
|
||||||
import SelectMaxParentalRating from '../dashboard/users/SelectMaxParentalRating';
|
|
||||||
import SectionTabs from '../dashboard/users/SectionTabs';
|
import SectionTabs from '../dashboard/users/SectionTabs';
|
||||||
import loading from '../loading/loading';
|
import loading from '../loading/loading';
|
||||||
import toast from '../toast/toast';
|
import toast from '../toast/toast';
|
||||||
import { getParameterByName } from '../../utils/url';
|
import { getParameterByName } from '../../utils/url';
|
||||||
|
import CheckBoxElement from '../dashboard/elements/CheckBoxElement';
|
||||||
|
import escapeHTML from 'escape-html';
|
||||||
|
import SelectElement from '../dashboard/elements/SelectElement';
|
||||||
|
|
||||||
type RatingsArr = {
|
type RatingsArr = {
|
||||||
Name: string;
|
Name: string;
|
||||||
@ -181,7 +181,7 @@ const UserParentalControl: FunctionComponent = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(page.querySelector('.selectMaxParentalRating') as HTMLInputElement).value = ratingValue;
|
(page.querySelector('#selectMaxParentalRating') as HTMLSelectElement).value = ratingValue;
|
||||||
|
|
||||||
if (user.Policy.IsAdministrator) {
|
if (user.Policy.IsAdministrator) {
|
||||||
(page.querySelector('.accessScheduleSection') as HTMLDivElement).classList.add('hide');
|
(page.querySelector('.accessScheduleSection') as HTMLDivElement).classList.add('hide');
|
||||||
@ -226,7 +226,7 @@ const UserParentalControl: FunctionComponent = () => {
|
|||||||
throw new Error('Unexpected null user.Policy');
|
throw new Error('Unexpected null user.Policy');
|
||||||
}
|
}
|
||||||
|
|
||||||
user.Policy.MaxParentalRating = parseInt((page.querySelector('.selectMaxParentalRating') as HTMLInputElement).value || '0', 10) || null;
|
user.Policy.MaxParentalRating = parseInt((page.querySelector('#selectMaxParentalRating') as HTMLSelectElement).value || '0', 10) || null;
|
||||||
user.Policy.BlockUnratedItems = Array.prototype.filter.call(page.querySelectorAll('.chkUnratedItem'), function (i) {
|
user.Policy.BlockUnratedItems = Array.prototype.filter.call(page.querySelectorAll('.chkUnratedItem'), function (i) {
|
||||||
return i.checked;
|
return i.checked;
|
||||||
}).map(function (i) {
|
}).map(function (i) {
|
||||||
@ -299,7 +299,7 @@ const UserParentalControl: FunctionComponent = () => {
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
(page.querySelector('.btnAddSchedule') as HTMLButtonElement).addEventListener('click', function () {
|
(page.querySelector('#btnAddSchedule') as HTMLButtonElement).addEventListener('click', function () {
|
||||||
showSchedulePopup({
|
showSchedulePopup({
|
||||||
Id: 0,
|
Id: 0,
|
||||||
UserId: '',
|
UserId: '',
|
||||||
@ -309,28 +309,40 @@ const UserParentalControl: FunctionComponent = () => {
|
|||||||
}, -1);
|
}, -1);
|
||||||
});
|
});
|
||||||
|
|
||||||
(page.querySelector('.btnAddBlockedTag') as HTMLButtonElement).addEventListener('click', function () {
|
(page.querySelector('#btnAddBlockedTag') as HTMLButtonElement).addEventListener('click', function () {
|
||||||
showBlockedTagPopup();
|
showBlockedTagPopup();
|
||||||
});
|
});
|
||||||
|
|
||||||
(page.querySelector('.userParentalControlForm') as HTMLFormElement).addEventListener('submit', onSubmit);
|
(page.querySelector('.userParentalControlForm') as HTMLFormElement).addEventListener('submit', onSubmit);
|
||||||
}, [loadBlockedTags, loadData, renderAccessSchedule]);
|
}, [loadBlockedTags, loadData, renderAccessSchedule]);
|
||||||
|
|
||||||
|
const optionMaxParentalRating = () => {
|
||||||
|
let content = '';
|
||||||
|
content += '<option value=\'\'></option>';
|
||||||
|
for (const rating of parentalRatings) {
|
||||||
|
content += `<option value='${rating.Value}'>${escapeHTML(rating.Name)}</option>`;
|
||||||
|
}
|
||||||
|
return content;
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={element}>
|
<div ref={element}>
|
||||||
<div className='content-primary'>
|
<div className='content-primary'>
|
||||||
<SectionTitleContainer
|
<div className='verticalSection'>
|
||||||
title={userName}
|
<SectionTitleContainer
|
||||||
titleLink='https://docs.jellyfin.org/general/server/users/'
|
title={userName}
|
||||||
/>
|
url='https://docs.jellyfin.org/general/server/users/'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<SectionTabs activeTab='userparentalcontrol'/>
|
<SectionTabs activeTab='userparentalcontrol'/>
|
||||||
<form className='userParentalControlForm'>
|
<form className='userParentalControlForm'>
|
||||||
<div className='selectContainer'>
|
<div className='selectContainer'>
|
||||||
<SelectMaxParentalRating
|
<SelectElement
|
||||||
className= 'selectMaxParentalRating'
|
id='selectMaxParentalRating'
|
||||||
label= 'LabelMaxParentalRating'
|
label='LabelMaxParentalRating'
|
||||||
parentalRatings={parentalRatings}
|
>
|
||||||
/>
|
{optionMaxParentalRating()}
|
||||||
|
</SelectElement>
|
||||||
<div className='fieldDescription'>
|
<div className='fieldDescription'>
|
||||||
{globalize.translate('MaxParentalRatingHelp')}
|
{globalize.translate('MaxParentalRatingHelp')}
|
||||||
</div>
|
</div>
|
||||||
@ -342,12 +354,12 @@ const UserParentalControl: FunctionComponent = () => {
|
|||||||
</h3>
|
</h3>
|
||||||
<div className='checkboxList paperList' style={{ padding: '.5em 1em' }}>
|
<div className='checkboxList paperList' style={{ padding: '.5em 1em' }}>
|
||||||
{unratedItems.map(Item => {
|
{unratedItems.map(Item => {
|
||||||
return <CheckBoxListItem
|
return <CheckBoxElement
|
||||||
key={Item.value}
|
key={Item.value}
|
||||||
className='chkUnratedItem'
|
className='chkUnratedItem'
|
||||||
ItemType={Item.value}
|
itemType={Item.value}
|
||||||
Name={Item.name}
|
itemName={Item.name}
|
||||||
checkedAttribute={Item.checkedAttribute}
|
itemCheckedAttribute={Item.checkedAttribute}
|
||||||
/>;
|
/>;
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
@ -355,19 +367,16 @@ const UserParentalControl: FunctionComponent = () => {
|
|||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
<div className='verticalSection' style={{marginBottom: '2em'}}>
|
<div className='verticalSection' style={{marginBottom: '2em'}}>
|
||||||
<div
|
<SectionTitleContainer
|
||||||
className='detailSectionHeader sectionTitleContainer'
|
SectionClassName='detailSectionHeader'
|
||||||
style={{display: 'flex', alignItems: 'center', paddingBottom: '1em'}}
|
title={globalize.translate('LabelBlockContentWithTags')}
|
||||||
>
|
isBtnVisible={true}
|
||||||
<h2 className='sectionTitle'>
|
btnId='btnAddBlockedTag'
|
||||||
{globalize.translate('LabelBlockContentWithTags')}
|
btnClassName='fab submit sectionTitleButton'
|
||||||
</h2>
|
btnTitle='Add'
|
||||||
<SectionTitleButtonElement
|
btnIcon='add'
|
||||||
className='fab btnAddBlockedTag submit'
|
isLinkVisible={false}
|
||||||
title='Add'
|
/>
|
||||||
icon='add'
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className='blockedTags' style={{marginTop: '.5em'}}>
|
<div className='blockedTags' style={{marginTop: '.5em'}}>
|
||||||
{blockedTags.map((tag, index) => {
|
{blockedTags.map((tag, index) => {
|
||||||
return <BlockedTagList
|
return <BlockedTagList
|
||||||
@ -378,19 +387,15 @@ const UserParentalControl: FunctionComponent = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className='accessScheduleSection verticalSection' style={{marginBottom: '2em'}}>
|
<div className='accessScheduleSection verticalSection' style={{marginBottom: '2em'}}>
|
||||||
<div
|
<SectionTitleContainer
|
||||||
className='sectionTitleContainer'
|
title={globalize.translate('HeaderAccessSchedule')}
|
||||||
style={{display: 'flex', alignItems: 'center', paddingBottom: '1em'}}
|
isBtnVisible={true}
|
||||||
>
|
btnId='btnAddSchedule'
|
||||||
<h2 className='sectionTitle'>
|
btnClassName='fab submit sectionTitleButton'
|
||||||
{globalize.translate('HeaderAccessSchedule')}
|
btnTitle='Add'
|
||||||
</h2>
|
btnIcon='add'
|
||||||
<SectionTitleButtonElement
|
isLinkVisible={false}
|
||||||
className='fab btnAddSchedule submit'
|
/>
|
||||||
title='Add'
|
|
||||||
icon='add'
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<p>{globalize.translate('HeaderAccessScheduleHelp')}</p>
|
<p>{globalize.translate('HeaderAccessScheduleHelp')}</p>
|
||||||
<div className='accessScheduleList paperList'>
|
<div className='accessScheduleList paperList'>
|
||||||
{accessSchedules.map((accessSchedule, index) => {
|
{accessSchedules.map((accessSchedule, index) => {
|
||||||
|
@ -2,7 +2,7 @@ import React, { FunctionComponent, useCallback, useEffect, useState } from 'reac
|
|||||||
import SectionTabs from '../dashboard/users/SectionTabs';
|
import SectionTabs from '../dashboard/users/SectionTabs';
|
||||||
import UserPasswordForm from '../dashboard/users/UserPasswordForm';
|
import UserPasswordForm from '../dashboard/users/UserPasswordForm';
|
||||||
import { getParameterByName } from '../../utils/url';
|
import { getParameterByName } from '../../utils/url';
|
||||||
import SectionTitleContainer from '../dashboard/users/SectionTitleContainer';
|
import SectionTitleContainer from '../dashboard/elements/SectionTitleContainer';
|
||||||
|
|
||||||
const UserPasswordPage: FunctionComponent = () => {
|
const UserPasswordPage: FunctionComponent = () => {
|
||||||
const userId = getParameterByName('userId');
|
const userId = getParameterByName('userId');
|
||||||
@ -23,10 +23,12 @@ const UserPasswordPage: FunctionComponent = () => {
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className='content-primary'>
|
<div className='content-primary'>
|
||||||
<SectionTitleContainer
|
<div className='verticalSection'>
|
||||||
title={userName}
|
<SectionTitleContainer
|
||||||
titleLink='https://docs.jellyfin.org/general/server/users/'
|
title={userName}
|
||||||
/>
|
url='https://docs.jellyfin.org/general/server/users/'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<SectionTabs activeTab='userpassword'/>
|
<SectionTabs activeTab='userpassword'/>
|
||||||
<div className='readOnlyContent'>
|
<div className='readOnlyContent'>
|
||||||
<UserPasswordForm
|
<UserPasswordForm
|
||||||
|
@ -6,7 +6,7 @@ import globalize from '../../scripts/globalize';
|
|||||||
import LibraryMenu from '../../scripts/libraryMenu';
|
import LibraryMenu from '../../scripts/libraryMenu';
|
||||||
import { appHost } from '../apphost';
|
import { appHost } from '../apphost';
|
||||||
import confirm from '../confirm/confirm';
|
import confirm from '../confirm/confirm';
|
||||||
import ButtonElement from '../dashboard/users/ButtonElement';
|
import ButtonElement from '../dashboard/elements/ButtonElement';
|
||||||
import UserPasswordForm from '../dashboard/users/UserPasswordForm';
|
import UserPasswordForm from '../dashboard/users/UserPasswordForm';
|
||||||
import loading from '../loading/loading';
|
import loading from '../loading/loading';
|
||||||
import toast from '../toast/toast';
|
import toast from '../toast/toast';
|
||||||
@ -57,11 +57,11 @@ const UserProfilePage: FunctionComponent<IProps> = ({userId}: IProps) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (user.PrimaryImageTag) {
|
if (user.PrimaryImageTag) {
|
||||||
(page.querySelector('.btnAddImage') as HTMLButtonElement).classList.add('hide');
|
(page.querySelector('#btnAddImage') as HTMLButtonElement).classList.add('hide');
|
||||||
(page.querySelector('.btnDeleteImage') as HTMLButtonElement).classList.remove('hide');
|
(page.querySelector('#btnDeleteImage') as HTMLButtonElement).classList.remove('hide');
|
||||||
} else if (appHost.supports('fileinput') && (loggedInUser?.Policy?.IsAdministrator || user.Policy.EnableUserPreferenceAccess)) {
|
} else if (appHost.supports('fileinput') && (loggedInUser?.Policy?.IsAdministrator || user.Policy.EnableUserPreferenceAccess)) {
|
||||||
(page.querySelector('.btnDeleteImage') as HTMLButtonElement).classList.add('hide');
|
(page.querySelector('#btnDeleteImage') as HTMLButtonElement).classList.add('hide');
|
||||||
(page.querySelector('.btnAddImage') as HTMLButtonElement).classList.remove('hide');
|
(page.querySelector('#btnAddImage') as HTMLButtonElement).classList.remove('hide');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
loading.hide();
|
loading.hide();
|
||||||
@ -120,7 +120,7 @@ const UserProfilePage: FunctionComponent<IProps> = ({userId}: IProps) => {
|
|||||||
reader.readAsDataURL(file);
|
reader.readAsDataURL(file);
|
||||||
};
|
};
|
||||||
|
|
||||||
(page.querySelector('.btnDeleteImage') as HTMLButtonElement).addEventListener('click', function () {
|
(page.querySelector('#btnDeleteImage') as HTMLButtonElement).addEventListener('click', function () {
|
||||||
confirm(
|
confirm(
|
||||||
globalize.translate('DeleteImageConfirmation'),
|
globalize.translate('DeleteImageConfirmation'),
|
||||||
globalize.translate('DeleteImage')
|
globalize.translate('DeleteImage')
|
||||||
@ -133,7 +133,7 @@ const UserProfilePage: FunctionComponent<IProps> = ({userId}: IProps) => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
(page.querySelector('.btnAddImage') as HTMLButtonElement).addEventListener('click', function () {
|
(page.querySelector('#btnAddImage') as HTMLButtonElement).addEventListener('click', function () {
|
||||||
const uploadImage = page.querySelector('#uploadImage') as HTMLInputElement;
|
const uploadImage = page.querySelector('#uploadImage') as HTMLInputElement;
|
||||||
uploadImage.value = '';
|
uploadImage.value = '';
|
||||||
uploadImage.click();
|
uploadImage.click();
|
||||||
@ -172,12 +172,14 @@ const UserProfilePage: FunctionComponent<IProps> = ({userId}: IProps) => {
|
|||||||
<br />
|
<br />
|
||||||
<ButtonElement
|
<ButtonElement
|
||||||
type='button'
|
type='button'
|
||||||
className='raised btnAddImage hide'
|
id='btnAddImage'
|
||||||
|
className='raised button-submit hide'
|
||||||
title='ButtonAddImage'
|
title='ButtonAddImage'
|
||||||
/>
|
/>
|
||||||
<ButtonElement
|
<ButtonElement
|
||||||
type='button'
|
type='button'
|
||||||
className='raised btnDeleteImage hide'
|
id='btnDeleteImage'
|
||||||
|
className='raised button-delete hide'
|
||||||
title='DeleteImage'
|
title='DeleteImage'
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -6,7 +6,7 @@ import loading from '../loading/loading';
|
|||||||
import dom from '../../scripts/dom';
|
import dom from '../../scripts/dom';
|
||||||
import confirm from '../../components/confirm/confirm';
|
import confirm from '../../components/confirm/confirm';
|
||||||
import UserCardBox from '../dashboard/users/UserCardBox';
|
import UserCardBox from '../dashboard/users/UserCardBox';
|
||||||
import SectionTitleContainer from '../dashboard/users/SectionTitleContainer';
|
import SectionTitleContainer from '../dashboard/elements/SectionTitleContainer';
|
||||||
import '../../elements/emby-button/emby-button';
|
import '../../elements/emby-button/emby-button';
|
||||||
import '../../elements/emby-button/paper-icon-button-light';
|
import '../../elements/emby-button/paper-icon-button-light';
|
||||||
import '../../components/cardbuilder/card.scss';
|
import '../../components/cardbuilder/card.scss';
|
||||||
@ -124,7 +124,7 @@ const UserProfilesPage: FunctionComponent = () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
(page.querySelector('.btnAddUser') as HTMLButtonElement).addEventListener('click', function() {
|
(page.querySelector('#btnAddUser') as HTMLButtonElement).addEventListener('click', function() {
|
||||||
Dashboard.navigate('usernew.html');
|
Dashboard.navigate('usernew.html');
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
@ -132,11 +132,17 @@ const UserProfilesPage: FunctionComponent = () => {
|
|||||||
return (
|
return (
|
||||||
<div ref={element}>
|
<div ref={element}>
|
||||||
<div className='content-primary'>
|
<div className='content-primary'>
|
||||||
<SectionTitleContainer
|
<div className='verticalSection'>
|
||||||
title={globalize.translate('HeaderUsers')}
|
<SectionTitleContainer
|
||||||
isBtnVisible={true}
|
title={globalize.translate('HeaderUsers')}
|
||||||
titleLink='https://docs.jellyfin.org/general/server/users/adding-managing-users.html'
|
isBtnVisible={true}
|
||||||
/>
|
btnId='btnAddUser'
|
||||||
|
btnClassName='fab submit sectionTitleButton'
|
||||||
|
btnTitle='ButtonAddUser'
|
||||||
|
btnIcon='add'
|
||||||
|
url='https://docs.jellyfin.org/general/server/users/adding-managing-users.html'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className='localUsers itemsContainer vertical-wrap'>
|
<div className='localUsers itemsContainer vertical-wrap'>
|
||||||
{users.map(user => {
|
{users.map(user => {
|
||||||
|
Loading…
Reference in New Issue
Block a user