mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
Update to React 18
This commit is contained in:
parent
b5d6e37fb3
commit
be891c3a98
36 changed files with 339 additions and 311 deletions
|
@ -147,7 +147,7 @@ const Activity = () => {
|
|||
}
|
||||
];
|
||||
|
||||
const onViewChange = useCallback((_e, newView: ActivityView | null) => {
|
||||
const onViewChange = useCallback((_e: React.MouseEvent<HTMLElement, MouseEvent>, newView: ActivityView | null) => {
|
||||
if (newView !== null) {
|
||||
setActivityView(newView);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import type { ProcessPriorityClass, ServerConfiguration, TrickplayScanBehavior } from '@jellyfin/sdk/lib/generated-client';
|
||||
import React, { type FunctionComponent, useCallback, useEffect, useRef } from 'react';
|
||||
import type { ServerConfiguration } from '@jellyfin/sdk/lib/generated-client/models/server-configuration';
|
||||
import { TrickplayScanBehavior } from '@jellyfin/sdk/lib/generated-client/models/trickplay-scan-behavior';
|
||||
import { ProcessPriorityClass } from '@jellyfin/sdk/lib/generated-client/models/process-priority-class';
|
||||
import React, { type FC, useCallback, useEffect, useRef } from 'react';
|
||||
|
||||
import globalize from '../../../../scripts/globalize';
|
||||
import Page from '../../../../components/Page';
|
||||
|
@ -17,10 +19,10 @@ function onSaveComplete() {
|
|||
toast(globalize.translate('SettingsSaved'));
|
||||
}
|
||||
|
||||
const PlaybackTrickplay: FunctionComponent = () => {
|
||||
const PlaybackTrickplay: FC = () => {
|
||||
const element = useRef<HTMLDivElement>(null);
|
||||
|
||||
const loadConfig = useCallback((config) => {
|
||||
const loadConfig = useCallback((config: ServerConfiguration) => {
|
||||
const page = element.current;
|
||||
const options = config.TrickplayOptions;
|
||||
|
||||
|
@ -29,17 +31,17 @@ const PlaybackTrickplay: FunctionComponent = () => {
|
|||
return;
|
||||
}
|
||||
|
||||
(page.querySelector('.chkEnableHwAcceleration') as HTMLInputElement).checked = options.EnableHwAcceleration;
|
||||
(page.querySelector('.chkEnableHwEncoding') as HTMLInputElement).checked = options.EnableHwEncoding;
|
||||
(page.querySelector('#selectScanBehavior') as HTMLSelectElement).value = options.ScanBehavior;
|
||||
(page.querySelector('#selectProcessPriority') as HTMLSelectElement).value = options.ProcessPriority;
|
||||
(page.querySelector('#txtInterval') as HTMLInputElement).value = options.Interval;
|
||||
(page.querySelector('#txtWidthResolutions') as HTMLInputElement).value = options.WidthResolutions.join(',');
|
||||
(page.querySelector('#txtTileWidth') as HTMLInputElement).value = options.TileWidth;
|
||||
(page.querySelector('#txtTileHeight') as HTMLInputElement).value = options.TileHeight;
|
||||
(page.querySelector('#txtQscale') as HTMLInputElement).value = options.Qscale;
|
||||
(page.querySelector('#txtJpegQuality') as HTMLInputElement).value = options.JpegQuality;
|
||||
(page.querySelector('#txtProcessThreads') as HTMLInputElement).value = options.ProcessThreads;
|
||||
(page.querySelector('.chkEnableHwAcceleration') as HTMLInputElement).checked = options?.EnableHwAcceleration || false;
|
||||
(page.querySelector('.chkEnableHwEncoding') as HTMLInputElement).checked = options?.EnableHwEncoding || false;
|
||||
(page.querySelector('#selectScanBehavior') as HTMLSelectElement).value = (options?.ScanBehavior || TrickplayScanBehavior.NonBlocking);
|
||||
(page.querySelector('#selectProcessPriority') as HTMLSelectElement).value = (options?.ProcessPriority || ProcessPriorityClass.Normal);
|
||||
(page.querySelector('#txtInterval') as HTMLInputElement).value = String(options?.Interval);
|
||||
(page.querySelector('#txtWidthResolutions') as HTMLInputElement).value = options?.WidthResolutions?.join(',') || '';
|
||||
(page.querySelector('#txtTileWidth') as HTMLInputElement).value = String(options?.TileWidth);
|
||||
(page.querySelector('#txtTileHeight') as HTMLInputElement).value = String(options?.TileHeight);
|
||||
(page.querySelector('#txtQscale') as HTMLInputElement).value = String(options?.Qscale);
|
||||
(page.querySelector('#txtJpegQuality') as HTMLInputElement).value = String(options?.JpegQuality);
|
||||
(page.querySelector('#txtProcessThreads') as HTMLInputElement).value = String(options?.ProcessThreads);
|
||||
|
||||
loading.hide();
|
||||
}, []);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import type { UserDto } from '@jellyfin/sdk/lib/generated-client';
|
||||
import React, { FunctionComponent, useCallback, useEffect, useState, useRef } from 'react';
|
||||
import type { BaseItemDto, DeviceInfo, UserDto } from '@jellyfin/sdk/lib/generated-client';
|
||||
import React, { useCallback, useEffect, useState, useRef } from 'react';
|
||||
|
||||
import loading from '../../../../components/loading/loading';
|
||||
import libraryMenu from '../../../../scripts/libraryMenu';
|
||||
|
@ -14,13 +14,13 @@ import CheckBoxElement from '../../../../elements/CheckBoxElement';
|
|||
import Page from '../../../../components/Page';
|
||||
|
||||
type ItemsArr = {
|
||||
Name?: string;
|
||||
Id?: string;
|
||||
AppName?: string;
|
||||
Name?: string | null;
|
||||
Id?: string | null;
|
||||
AppName?: string | null;
|
||||
checkedAttribute?: string
|
||||
};
|
||||
|
||||
const UserLibraryAccess: FunctionComponent = () => {
|
||||
const UserLibraryAccess = () => {
|
||||
const [ userName, setUserName ] = useState('');
|
||||
const [channelsItems, setChannelsItems] = useState<ItemsArr[]>([]);
|
||||
const [mediaFoldersItems, setMediaFoldersItems] = useState<ItemsArr[]>([]);
|
||||
|
@ -33,7 +33,7 @@ const UserLibraryAccess: FunctionComponent = () => {
|
|||
select.dispatchEvent(evt);
|
||||
};
|
||||
|
||||
const loadMediaFolders = useCallback((user, mediaFolders) => {
|
||||
const loadMediaFolders = useCallback((user: UserDto, mediaFolders: BaseItemDto[]) => {
|
||||
const page = element.current;
|
||||
|
||||
if (!page) {
|
||||
|
@ -44,7 +44,7 @@ const UserLibraryAccess: FunctionComponent = () => {
|
|||
const itemsArr: ItemsArr[] = [];
|
||||
|
||||
for (const folder of mediaFolders) {
|
||||
const isChecked = user.Policy.EnableAllFolders || user.Policy.EnabledFolders.indexOf(folder.Id) != -1;
|
||||
const isChecked = user.Policy?.EnableAllFolders || user.Policy?.EnabledFolders?.indexOf(folder.Id || '') != -1;
|
||||
const checkedAttribute = isChecked ? ' checked="checked"' : '';
|
||||
itemsArr.push({
|
||||
Id: folder.Id,
|
||||
|
@ -56,11 +56,11 @@ const UserLibraryAccess: FunctionComponent = () => {
|
|||
setMediaFoldersItems(itemsArr);
|
||||
|
||||
const chkEnableAllFolders = page.querySelector('.chkEnableAllFolders') as HTMLInputElement;
|
||||
chkEnableAllFolders.checked = user.Policy.EnableAllFolders;
|
||||
chkEnableAllFolders.checked = Boolean(user.Policy?.EnableAllFolders);
|
||||
triggerChange(chkEnableAllFolders);
|
||||
}, []);
|
||||
|
||||
const loadChannels = useCallback((user, channels) => {
|
||||
const loadChannels = useCallback((user: UserDto, channels: BaseItemDto[]) => {
|
||||
const page = element.current;
|
||||
|
||||
if (!page) {
|
||||
|
@ -71,7 +71,7 @@ const UserLibraryAccess: FunctionComponent = () => {
|
|||
const itemsArr: ItemsArr[] = [];
|
||||
|
||||
for (const folder of channels) {
|
||||
const isChecked = user.Policy.EnableAllChannels || user.Policy.EnabledChannels.indexOf(folder.Id) != -1;
|
||||
const isChecked = user.Policy?.EnableAllChannels || user.Policy?.EnabledChannels?.indexOf(folder.Id || '') != -1;
|
||||
const checkedAttribute = isChecked ? ' checked="checked"' : '';
|
||||
itemsArr.push({
|
||||
Id: folder.Id,
|
||||
|
@ -89,11 +89,11 @@ const UserLibraryAccess: FunctionComponent = () => {
|
|||
}
|
||||
|
||||
const chkEnableAllChannels = page.querySelector('.chkEnableAllChannels') as HTMLInputElement;
|
||||
chkEnableAllChannels.checked = user.Policy.EnableAllChannels;
|
||||
chkEnableAllChannels.checked = Boolean(user.Policy?.EnableAllChannels);
|
||||
triggerChange(chkEnableAllChannels);
|
||||
}, []);
|
||||
|
||||
const loadDevices = useCallback((user, devices) => {
|
||||
const loadDevices = useCallback((user: UserDto, devices: DeviceInfo[]) => {
|
||||
const page = element.current;
|
||||
|
||||
if (!page) {
|
||||
|
@ -104,7 +104,7 @@ const UserLibraryAccess: FunctionComponent = () => {
|
|||
const itemsArr: ItemsArr[] = [];
|
||||
|
||||
for (const device of devices) {
|
||||
const isChecked = user.Policy.EnableAllDevices || user.Policy.EnabledDevices.indexOf(device.Id) != -1;
|
||||
const isChecked = user.Policy?.EnableAllDevices || user.Policy?.EnabledDevices?.indexOf(device.Id || '') != -1;
|
||||
const checkedAttribute = isChecked ? ' checked="checked"' : '';
|
||||
itemsArr.push({
|
||||
Id: device.Id,
|
||||
|
@ -117,18 +117,18 @@ const UserLibraryAccess: FunctionComponent = () => {
|
|||
setDevicesItems(itemsArr);
|
||||
|
||||
const chkEnableAllDevices = page.querySelector('.chkEnableAllDevices') as HTMLInputElement;
|
||||
chkEnableAllDevices.checked = user.Policy.EnableAllDevices;
|
||||
chkEnableAllDevices.checked = Boolean(user.Policy?.EnableAllDevices);
|
||||
triggerChange(chkEnableAllDevices);
|
||||
|
||||
if (user.Policy.IsAdministrator) {
|
||||
if (user.Policy?.IsAdministrator) {
|
||||
(page.querySelector('.deviceAccessContainer') as HTMLDivElement).classList.add('hide');
|
||||
} else {
|
||||
(page.querySelector('.deviceAccessContainer') as HTMLDivElement).classList.remove('hide');
|
||||
}
|
||||
}, []);
|
||||
|
||||
const loadUser = useCallback((user, mediaFolders, channels, devices) => {
|
||||
setUserName(user.Name);
|
||||
const loadUser = useCallback((user: UserDto, mediaFolders: BaseItemDto[], channels: BaseItemDto[], devices: DeviceInfo[]) => {
|
||||
setUserName(user.Name || '');
|
||||
libraryMenu.setTitle(user.Name);
|
||||
loadChannels(user, channels);
|
||||
loadMediaFolders(user, mediaFolders);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React, { FunctionComponent, useCallback, useEffect, useState, useRef } from 'react';
|
||||
import type { BaseItemDto } from '@jellyfin/sdk/lib/generated-client';
|
||||
import React, { useCallback, useEffect, useState, useRef } from 'react';
|
||||
|
||||
import Dashboard from '../../../../utils/dashboard';
|
||||
import globalize from '../../../../scripts/globalize';
|
||||
|
@ -17,16 +18,16 @@ type userInput = {
|
|||
};
|
||||
|
||||
type ItemsArr = {
|
||||
Name?: string;
|
||||
Name?: string | null;
|
||||
Id?: string;
|
||||
};
|
||||
|
||||
const UserNew: FunctionComponent = () => {
|
||||
const UserNew = () => {
|
||||
const [ channelsItems, setChannelsItems ] = useState<ItemsArr[]>([]);
|
||||
const [ mediaFoldersItems, setMediaFoldersItems ] = useState<ItemsArr[]>([]);
|
||||
const element = useRef<HTMLDivElement>(null);
|
||||
|
||||
const getItemsResult = (items: ItemsArr[]) => {
|
||||
const getItemsResult = (items: BaseItemDto[]) => {
|
||||
return items.map(item =>
|
||||
({
|
||||
Id: item.Id,
|
||||
|
@ -35,7 +36,7 @@ const UserNew: FunctionComponent = () => {
|
|||
);
|
||||
};
|
||||
|
||||
const loadMediaFolders = useCallback((result) => {
|
||||
const loadMediaFolders = useCallback((result: BaseItemDto[]) => {
|
||||
const page = element.current;
|
||||
|
||||
if (!page) {
|
||||
|
@ -53,7 +54,7 @@ const UserNew: FunctionComponent = () => {
|
|||
(page.querySelector('.chkEnableAllFolders') as HTMLInputElement).checked = false;
|
||||
}, []);
|
||||
|
||||
const loadChannels = useCallback((result) => {
|
||||
const loadChannels = useCallback((result: BaseItemDto[]) => {
|
||||
const page = element.current;
|
||||
|
||||
if (!page) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import type { UserDto } from '@jellyfin/sdk/lib/generated-client';
|
||||
import React, { FunctionComponent, useEffect, useState, useRef } from 'react';
|
||||
import React, { useEffect, useState, useRef } from 'react';
|
||||
|
||||
import Dashboard from '../../../../utils/dashboard';
|
||||
import globalize from '../../../../scripts/globalize';
|
||||
|
@ -21,7 +21,7 @@ type MenuEntry = {
|
|||
icon?: string;
|
||||
};
|
||||
|
||||
const UserProfiles: FunctionComponent = () => {
|
||||
const UserProfiles = () => {
|
||||
const [ users, setUsers ] = useState<UserDto[]>([]);
|
||||
|
||||
const element = useRef<HTMLDivElement>(null);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import type { AccessSchedule, ParentalRating, UserDto } from '@jellyfin/sdk/lib/generated-client';
|
||||
import { UnratedItem, type AccessSchedule, type ParentalRating, type UserDto } from '@jellyfin/sdk/lib/generated-client';
|
||||
import { DynamicDayOfWeek } from '@jellyfin/sdk/lib/generated-client/models/dynamic-day-of-week';
|
||||
import React, { FunctionComponent, useCallback, useEffect, useState, useRef } from 'react';
|
||||
import React, { useCallback, useEffect, useState, useRef } from 'react';
|
||||
import escapeHTML from 'escape-html';
|
||||
|
||||
import globalize from '../../../../scripts/globalize';
|
||||
|
@ -19,9 +19,12 @@ import Page from '../../../../components/Page';
|
|||
import prompt from '../../../../components/prompt/prompt';
|
||||
import ServerConnections from 'components/ServerConnections';
|
||||
|
||||
type UnratedItem = {
|
||||
type ItemArr = {
|
||||
name: string;
|
||||
value: string;
|
||||
value: UnratedItem;
|
||||
};
|
||||
|
||||
type UnratedItemArr = ItemArr & {
|
||||
checkedAttribute: string
|
||||
};
|
||||
|
||||
|
@ -56,17 +59,17 @@ function handleSaveUser(
|
|||
};
|
||||
}
|
||||
|
||||
const UserParentalControl: FunctionComponent = () => {
|
||||
const UserParentalControl = () => {
|
||||
const [ userName, setUserName ] = useState('');
|
||||
const [ parentalRatings, setParentalRatings ] = useState<ParentalRating[]>([]);
|
||||
const [ unratedItems, setUnratedItems ] = useState<UnratedItem[]>([]);
|
||||
const [ unratedItems, setUnratedItems ] = useState<UnratedItemArr[]>([]);
|
||||
const [ accessSchedules, setAccessSchedules ] = useState<AccessSchedule[]>([]);
|
||||
const [ allowedTags, setAllowedTags ] = useState<string[]>([]);
|
||||
const [ blockedTags, setBlockedTags ] = useState<string[]>([]);
|
||||
|
||||
const element = useRef<HTMLDivElement>(null);
|
||||
|
||||
const populateRatings = useCallback((allParentalRatings) => {
|
||||
const populateRatings = useCallback((allParentalRatings: ParentalRating[]) => {
|
||||
let rating;
|
||||
const ratings: ParentalRating[] = [];
|
||||
|
||||
|
@ -91,7 +94,7 @@ const UserParentalControl: FunctionComponent = () => {
|
|||
setParentalRatings(ratings);
|
||||
}, []);
|
||||
|
||||
const loadUnratedItems = useCallback((user) => {
|
||||
const loadUnratedItems = useCallback((user: UserDto) => {
|
||||
const page = element.current;
|
||||
|
||||
if (!page) {
|
||||
|
@ -99,33 +102,33 @@ const UserParentalControl: FunctionComponent = () => {
|
|||
return;
|
||||
}
|
||||
|
||||
const items = [{
|
||||
const items: ItemArr[] = [{
|
||||
name: globalize.translate('Books'),
|
||||
value: 'Book'
|
||||
value: UnratedItem.Book
|
||||
}, {
|
||||
name: globalize.translate('Channels'),
|
||||
value: 'ChannelContent'
|
||||
value: UnratedItem.ChannelContent
|
||||
}, {
|
||||
name: globalize.translate('LiveTV'),
|
||||
value: 'LiveTvChannel'
|
||||
value: UnratedItem.LiveTvChannel
|
||||
}, {
|
||||
name: globalize.translate('Movies'),
|
||||
value: 'Movie'
|
||||
value: UnratedItem.Movie
|
||||
}, {
|
||||
name: globalize.translate('Music'),
|
||||
value: 'Music'
|
||||
value: UnratedItem.Music
|
||||
}, {
|
||||
name: globalize.translate('Trailers'),
|
||||
value: 'Trailer'
|
||||
value: UnratedItem.Trailer
|
||||
}, {
|
||||
name: globalize.translate('Shows'),
|
||||
value: 'Series'
|
||||
value: UnratedItem.Series
|
||||
}];
|
||||
|
||||
const itemsArr: UnratedItem[] = [];
|
||||
const itemsArr: UnratedItemArr[] = [];
|
||||
|
||||
for (const item of items) {
|
||||
const isChecked = user.Policy.BlockUnratedItems.indexOf(item.value) != -1;
|
||||
const isChecked = user.Policy?.BlockUnratedItems?.indexOf(item.value) != -1;
|
||||
const checkedAttribute = isChecked ? ' checked="checked"' : '';
|
||||
itemsArr.push({
|
||||
value: item.value,
|
||||
|
@ -182,7 +185,7 @@ const UserParentalControl: FunctionComponent = () => {
|
|||
}
|
||||
}, []);
|
||||
|
||||
const renderAccessSchedule = useCallback((schedules) => {
|
||||
const renderAccessSchedule = useCallback((schedules: AccessSchedule[]) => {
|
||||
const page = element.current;
|
||||
|
||||
if (!page) {
|
||||
|
@ -198,7 +201,7 @@ const UserParentalControl: FunctionComponent = () => {
|
|||
btnDelete.addEventListener('click', function () {
|
||||
const index = parseInt(btnDelete.getAttribute('data-index') ?? '0', 10);
|
||||
schedules.splice(index, 1);
|
||||
const newindex = schedules.filter((i: number) => i != index);
|
||||
const newindex = schedules.filter((_, i) => i != index);
|
||||
renderAccessSchedule(newindex);
|
||||
});
|
||||
}
|
||||
|
@ -229,7 +232,7 @@ const UserParentalControl: FunctionComponent = () => {
|
|||
});
|
||||
}
|
||||
|
||||
(page.querySelector('#selectMaxParentalRating') as HTMLSelectElement).value = ratingValue;
|
||||
(page.querySelector('#selectMaxParentalRating') as HTMLSelectElement).value = String(ratingValue);
|
||||
|
||||
if (user.Policy?.IsAdministrator) {
|
||||
(page.querySelector('.accessScheduleSection') as HTMLDivElement).classList.add('hide');
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import React, { FunctionComponent, useCallback, useEffect, useState } from 'react';
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
|
||||
import SectionTabs from '../../../../components/dashboard/users/SectionTabs';
|
||||
import UserPasswordForm from '../../../../components/dashboard/users/UserPasswordForm';
|
||||
|
@ -7,7 +7,7 @@ import SectionTitleContainer from '../../../../elements/SectionTitleContainer';
|
|||
import Page from '../../../../components/Page';
|
||||
import loading from '../../../../components/loading/loading';
|
||||
|
||||
const UserPassword: FunctionComponent = () => {
|
||||
const UserPassword = () => {
|
||||
const userId = getParameterByName('userId');
|
||||
const [ userName, setUserName ] = useState('');
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import type { SyncPlayUserAccessType, UserDto } from '@jellyfin/sdk/lib/generated-client';
|
||||
import React, { FunctionComponent, useCallback, useEffect, useState, useRef } from 'react';
|
||||
import type { BaseItemDto, NameIdPair, SyncPlayUserAccessType, UserDto } from '@jellyfin/sdk/lib/generated-client';
|
||||
import React, { useCallback, useEffect, useState, useRef } from 'react';
|
||||
import escapeHTML from 'escape-html';
|
||||
|
||||
import Dashboard from '../../../../utils/dashboard';
|
||||
|
@ -17,15 +17,10 @@ import { getParameterByName } from '../../../../utils/url';
|
|||
import SelectElement from '../../../../elements/SelectElement';
|
||||
import Page from '../../../../components/Page';
|
||||
|
||||
type ResetProvider = AuthProvider & {
|
||||
type ResetProvider = BaseItemDto & {
|
||||
checkedAttribute: string
|
||||
};
|
||||
|
||||
type AuthProvider = {
|
||||
Name?: string;
|
||||
Id?: string;
|
||||
};
|
||||
|
||||
const getCheckedElementDataIds = (elements: NodeListOf<Element>) => (
|
||||
Array.prototype.filter.call(elements, e => e.checked)
|
||||
.map(e => e.getAttribute('data-id'))
|
||||
|
@ -40,11 +35,11 @@ function onSaveComplete() {
|
|||
toast(globalize.translate('SettingsSaved'));
|
||||
}
|
||||
|
||||
const UserEdit: FunctionComponent = () => {
|
||||
const UserEdit = () => {
|
||||
const [ userName, setUserName ] = useState('');
|
||||
const [ deleteFoldersAccess, setDeleteFoldersAccess ] = useState<ResetProvider[]>([]);
|
||||
const [ authProviders, setAuthProviders ] = useState<AuthProvider[]>([]);
|
||||
const [ passwordResetProviders, setPasswordResetProviders ] = useState<ResetProvider[]>([]);
|
||||
const [ authProviders, setAuthProviders ] = useState<NameIdPair[]>([]);
|
||||
const [ passwordResetProviders, setPasswordResetProviders ] = useState<NameIdPair[]>([]);
|
||||
|
||||
const [ authenticationProviderId, setAuthenticationProviderId ] = useState('');
|
||||
const [ passwordResetProviderId, setPasswordResetProviderId ] = useState('');
|
||||
|
@ -61,48 +56,27 @@ const UserEdit: FunctionComponent = () => {
|
|||
return window.ApiClient.getUser(userId);
|
||||
};
|
||||
|
||||
const loadAuthProviders = useCallback((user, providers) => {
|
||||
const page = element.current;
|
||||
|
||||
if (!page) {
|
||||
console.error('Unexpected null reference');
|
||||
return;
|
||||
}
|
||||
|
||||
const loadAuthProviders = useCallback((page: HTMLDivElement, user: UserDto, providers: NameIdPair[]) => {
|
||||
const fldSelectLoginProvider = page.querySelector('.fldSelectLoginProvider') as HTMLDivElement;
|
||||
fldSelectLoginProvider.classList.toggle('hide', providers.length <= 1);
|
||||
|
||||
setAuthProviders(providers);
|
||||
|
||||
const currentProviderId = user.Policy.AuthenticationProviderId;
|
||||
const currentProviderId = user.Policy?.AuthenticationProviderId || '';
|
||||
setAuthenticationProviderId(currentProviderId);
|
||||
}, []);
|
||||
|
||||
const loadPasswordResetProviders = useCallback((user, providers) => {
|
||||
const page = element.current;
|
||||
|
||||
if (!page) {
|
||||
console.error('Unexpected null reference');
|
||||
return;
|
||||
}
|
||||
|
||||
const loadPasswordResetProviders = useCallback((page: HTMLDivElement, user: UserDto, providers: NameIdPair[]) => {
|
||||
const fldSelectPasswordResetProvider = page.querySelector('.fldSelectPasswordResetProvider') as HTMLDivElement;
|
||||
fldSelectPasswordResetProvider.classList.toggle('hide', providers.length <= 1);
|
||||
|
||||
setPasswordResetProviders(providers);
|
||||
|
||||
const currentProviderId = user.Policy.PasswordResetProviderId;
|
||||
const currentProviderId = user.Policy?.PasswordResetProviderId || '';
|
||||
setPasswordResetProviderId(currentProviderId);
|
||||
}, []);
|
||||
|
||||
const loadDeleteFolders = useCallback((user, mediaFolders) => {
|
||||
const page = element.current;
|
||||
|
||||
if (!page) {
|
||||
console.error('Unexpected null reference');
|
||||
return;
|
||||
}
|
||||
|
||||
const loadDeleteFolders = useCallback((page: HTMLDivElement, user: UserDto, mediaFolders: BaseItemDto[]) => {
|
||||
window.ApiClient.getJSON(window.ApiClient.getUrl('Channels', {
|
||||
SupportsMediaDeletion: true
|
||||
})).then(function (channelsResult) {
|
||||
|
@ -110,22 +84,20 @@ const UserEdit: FunctionComponent = () => {
|
|||
let checkedAttribute;
|
||||
const itemsArr: ResetProvider[] = [];
|
||||
|
||||
for (const folder of mediaFolders) {
|
||||
isChecked = user.Policy.EnableContentDeletion || user.Policy.EnableContentDeletionFromFolders.indexOf(folder.Id) != -1;
|
||||
for (const mediaFolder of mediaFolders) {
|
||||
isChecked = user.Policy?.EnableContentDeletion || user.Policy?.EnableContentDeletionFromFolders?.indexOf(mediaFolder.Id || '') != -1;
|
||||
checkedAttribute = isChecked ? ' checked="checked"' : '';
|
||||
itemsArr.push({
|
||||
Id: folder.Id,
|
||||
Name: folder.Name,
|
||||
...mediaFolder,
|
||||
checkedAttribute: checkedAttribute
|
||||
});
|
||||
}
|
||||
|
||||
for (const folder of channelsResult.Items) {
|
||||
isChecked = user.Policy.EnableContentDeletion || user.Policy.EnableContentDeletionFromFolders.indexOf(folder.Id) != -1;
|
||||
for (const channel of channelsResult.Items) {
|
||||
isChecked = user.Policy?.EnableContentDeletion || user.Policy?.EnableContentDeletionFromFolders?.indexOf(channel.Id || '') != -1;
|
||||
checkedAttribute = isChecked ? ' checked="checked"' : '';
|
||||
itemsArr.push({
|
||||
Id: folder.Id,
|
||||
Name: folder.Name,
|
||||
...channel,
|
||||
checkedAttribute: checkedAttribute
|
||||
});
|
||||
}
|
||||
|
@ -133,14 +105,14 @@ const UserEdit: FunctionComponent = () => {
|
|||
setDeleteFoldersAccess(itemsArr);
|
||||
|
||||
const chkEnableDeleteAllFolders = page.querySelector('.chkEnableDeleteAllFolders') as HTMLInputElement;
|
||||
chkEnableDeleteAllFolders.checked = user.Policy.EnableContentDeletion;
|
||||
chkEnableDeleteAllFolders.checked = user.Policy?.EnableContentDeletion || false;
|
||||
triggerChange(chkEnableDeleteAllFolders);
|
||||
}).catch(err => {
|
||||
console.error('[useredit] failed to fetch channels', err);
|
||||
});
|
||||
}, []);
|
||||
|
||||
const loadUser = useCallback((user) => {
|
||||
const loadUser = useCallback((user: UserDto) => {
|
||||
const page = element.current;
|
||||
|
||||
if (!page) {
|
||||
|
@ -149,25 +121,25 @@ const UserEdit: FunctionComponent = () => {
|
|||
}
|
||||
|
||||
window.ApiClient.getJSON(window.ApiClient.getUrl('Auth/Providers')).then(function (providers) {
|
||||
loadAuthProviders(user, providers);
|
||||
loadAuthProviders(page, user, providers);
|
||||
}).catch(err => {
|
||||
console.error('[useredit] failed to fetch auth providers', err);
|
||||
});
|
||||
window.ApiClient.getJSON(window.ApiClient.getUrl('Auth/PasswordResetProviders')).then(function (providers) {
|
||||
loadPasswordResetProviders(user, providers);
|
||||
loadPasswordResetProviders(page, user, providers);
|
||||
}).catch(err => {
|
||||
console.error('[useredit] failed to fetch password reset providers', err);
|
||||
});
|
||||
window.ApiClient.getJSON(window.ApiClient.getUrl('Library/MediaFolders', {
|
||||
IsHidden: false
|
||||
})).then(function (folders) {
|
||||
loadDeleteFolders(user, folders.Items);
|
||||
loadDeleteFolders(page, user, folders.Items);
|
||||
}).catch(err => {
|
||||
console.error('[useredit] failed to fetch media folders', err);
|
||||
});
|
||||
|
||||
const disabledUserBanner = page.querySelector('.disabledUserBanner') as HTMLDivElement;
|
||||
disabledUserBanner.classList.toggle('hide', !user.Policy.IsDisabled);
|
||||
disabledUserBanner.classList.toggle('hide', !user.Policy?.IsDisabled);
|
||||
|
||||
const txtUserName = page.querySelector('#txtUserName') as HTMLInputElement;
|
||||
txtUserName.disabled = false;
|
||||
|
@ -176,30 +148,30 @@ const UserEdit: FunctionComponent = () => {
|
|||
const lnkEditUserPreferences = page.querySelector('.lnkEditUserPreferences') as HTMLDivElement;
|
||||
lnkEditUserPreferences.setAttribute('href', 'mypreferencesmenu.html?userId=' + user.Id);
|
||||
LibraryMenu.setTitle(user.Name);
|
||||
setUserName(user.Name);
|
||||
(page.querySelector('#txtUserName') as HTMLInputElement).value = user.Name;
|
||||
(page.querySelector('.chkIsAdmin') as HTMLInputElement).checked = user.Policy.IsAdministrator;
|
||||
(page.querySelector('.chkDisabled') as HTMLInputElement).checked = user.Policy.IsDisabled;
|
||||
(page.querySelector('.chkIsHidden') as HTMLInputElement).checked = user.Policy.IsHidden;
|
||||
(page.querySelector('.chkEnableCollectionManagement') as HTMLInputElement).checked = user.Policy.EnableCollectionManagement;
|
||||
(page.querySelector('.chkEnableSubtitleManagement') as HTMLInputElement).checked = user.Policy.EnableSubtitleManagement;
|
||||
(page.querySelector('.chkRemoteControlSharedDevices') as HTMLInputElement).checked = user.Policy.EnableSharedDeviceControl;
|
||||
(page.querySelector('.chkEnableRemoteControlOtherUsers') as HTMLInputElement).checked = user.Policy.EnableRemoteControlOfOtherUsers;
|
||||
(page.querySelector('.chkEnableDownloading') as HTMLInputElement).checked = user.Policy.EnableContentDownloading;
|
||||
(page.querySelector('.chkManageLiveTv') as HTMLInputElement).checked = user.Policy.EnableLiveTvManagement;
|
||||
(page.querySelector('.chkEnableLiveTvAccess') as HTMLInputElement).checked = user.Policy.EnableLiveTvAccess;
|
||||
(page.querySelector('.chkEnableMediaPlayback') as HTMLInputElement).checked = user.Policy.EnableMediaPlayback;
|
||||
(page.querySelector('.chkEnableAudioPlaybackTranscoding') as HTMLInputElement).checked = user.Policy.EnableAudioPlaybackTranscoding;
|
||||
(page.querySelector('.chkEnableVideoPlaybackTranscoding') as HTMLInputElement).checked = user.Policy.EnableVideoPlaybackTranscoding;
|
||||
(page.querySelector('.chkEnableVideoPlaybackRemuxing') as HTMLInputElement).checked = user.Policy.EnablePlaybackRemuxing;
|
||||
(page.querySelector('.chkForceRemoteSourceTranscoding') as HTMLInputElement).checked = user.Policy.ForceRemoteSourceTranscoding;
|
||||
(page.querySelector('.chkRemoteAccess') as HTMLInputElement).checked = user.Policy.EnableRemoteAccess == null || user.Policy.EnableRemoteAccess;
|
||||
(page.querySelector('#txtRemoteClientBitrateLimit') as HTMLInputElement).value = user.Policy.RemoteClientBitrateLimit > 0 ?
|
||||
(user.Policy.RemoteClientBitrateLimit / 1e6).toLocaleString(undefined, { maximumFractionDigits: 6 }) : '';
|
||||
(page.querySelector('#txtLoginAttemptsBeforeLockout') as HTMLInputElement).value = user.Policy.LoginAttemptsBeforeLockout || '0';
|
||||
(page.querySelector('#txtMaxActiveSessions') as HTMLInputElement).value = user.Policy.MaxActiveSessions || '0';
|
||||
setUserName(user.Name || '');
|
||||
(page.querySelector('#txtUserName') as HTMLInputElement).value = user.Name || '';
|
||||
(page.querySelector('.chkIsAdmin') as HTMLInputElement).checked = !!user.Policy?.IsAdministrator;
|
||||
(page.querySelector('.chkDisabled') as HTMLInputElement).checked = !!user.Policy?.IsDisabled;
|
||||
(page.querySelector('.chkIsHidden') as HTMLInputElement).checked = !!user.Policy?.IsHidden;
|
||||
(page.querySelector('.chkEnableCollectionManagement') as HTMLInputElement).checked = !!user.Policy?.EnableCollectionManagement;
|
||||
(page.querySelector('.chkEnableSubtitleManagement') as HTMLInputElement).checked = !!user.Policy?.EnableSubtitleManagement;
|
||||
(page.querySelector('.chkRemoteControlSharedDevices') as HTMLInputElement).checked = !!user.Policy?.EnableSharedDeviceControl;
|
||||
(page.querySelector('.chkEnableRemoteControlOtherUsers') as HTMLInputElement).checked = !!user.Policy?.EnableRemoteControlOfOtherUsers;
|
||||
(page.querySelector('.chkEnableDownloading') as HTMLInputElement).checked = !!user.Policy?.EnableContentDownloading;
|
||||
(page.querySelector('.chkManageLiveTv') as HTMLInputElement).checked = !!user.Policy?.EnableLiveTvManagement;
|
||||
(page.querySelector('.chkEnableLiveTvAccess') as HTMLInputElement).checked = !!user.Policy?.EnableLiveTvAccess;
|
||||
(page.querySelector('.chkEnableMediaPlayback') as HTMLInputElement).checked = !!user.Policy?.EnableMediaPlayback;
|
||||
(page.querySelector('.chkEnableAudioPlaybackTranscoding') as HTMLInputElement).checked = !!user.Policy?.EnableAudioPlaybackTranscoding;
|
||||
(page.querySelector('.chkEnableVideoPlaybackTranscoding') as HTMLInputElement).checked = !!user.Policy?.EnableVideoPlaybackTranscoding;
|
||||
(page.querySelector('.chkEnableVideoPlaybackRemuxing') as HTMLInputElement).checked = !!user.Policy?.EnablePlaybackRemuxing;
|
||||
(page.querySelector('.chkForceRemoteSourceTranscoding') as HTMLInputElement).checked = !!user.Policy?.ForceRemoteSourceTranscoding;
|
||||
(page.querySelector('.chkRemoteAccess') as HTMLInputElement).checked = user.Policy?.EnableRemoteAccess == null || user.Policy?.EnableRemoteAccess;
|
||||
(page.querySelector('#txtRemoteClientBitrateLimit') as HTMLInputElement).value = user.Policy?.RemoteClientBitrateLimit && user.Policy?.RemoteClientBitrateLimit > 0 ?
|
||||
(user.Policy?.RemoteClientBitrateLimit / 1e6).toLocaleString(undefined, { maximumFractionDigits: 6 }) : '';
|
||||
(page.querySelector('#txtLoginAttemptsBeforeLockout') as HTMLInputElement).value = String(user.Policy?.MaxActiveSessions) || '0';
|
||||
(page.querySelector('#txtMaxActiveSessions') as HTMLInputElement).value = String(user.Policy?.SyncPlayAccess) || '0';
|
||||
if (window.ApiClient.isMinServerVersion('10.6.0')) {
|
||||
(page.querySelector('#selectSyncPlayAccess') as HTMLSelectElement).value = user.Policy.SyncPlayAccess;
|
||||
(page.querySelector('#selectSyncPlayAccess') as HTMLSelectElement).value = String(user.Policy?.SyncPlayAccess);
|
||||
}
|
||||
loading.hide();
|
||||
}, [loadAuthProviders, loadPasswordResetProviders, loadDeleteFolders ]);
|
||||
|
|
|
@ -33,7 +33,7 @@ const RemotePlayButton = () => {
|
|||
const [ remotePlayMenuAnchorEl, setRemotePlayMenuAnchorEl ] = useState<null | HTMLElement>(null);
|
||||
const isRemotePlayMenuOpen = Boolean(remotePlayMenuAnchorEl);
|
||||
|
||||
const onRemotePlayButtonClick = useCallback((event) => {
|
||||
const onRemotePlayButtonClick = useCallback((event: React.MouseEvent<HTMLElement>) => {
|
||||
setRemotePlayMenuAnchorEl(event.currentTarget);
|
||||
}, [ setRemotePlayMenuAnchorEl ]);
|
||||
|
||||
|
@ -44,7 +44,7 @@ const RemotePlayButton = () => {
|
|||
const [ remotePlayActiveMenuAnchorEl, setRemotePlayActiveMenuAnchorEl ] = useState<null | HTMLElement>(null);
|
||||
const isRemotePlayActiveMenuOpen = Boolean(remotePlayActiveMenuAnchorEl);
|
||||
|
||||
const onRemotePlayActiveButtonClick = useCallback((event) => {
|
||||
const onRemotePlayActiveButtonClick = useCallback((event: React.MouseEvent<HTMLElement>) => {
|
||||
setRemotePlayActiveMenuAnchorEl(event.currentTarget);
|
||||
}, [ setRemotePlayActiveMenuAnchorEl ]);
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ const SyncPlayButton = () => {
|
|||
const [ syncPlayMenuAnchorEl, setSyncPlayMenuAnchorEl ] = useState<null | HTMLElement>(null);
|
||||
const isSyncPlayMenuOpen = Boolean(syncPlayMenuAnchorEl);
|
||||
|
||||
const onSyncPlayButtonClick = useCallback((event) => {
|
||||
const onSyncPlayButtonClick = useCallback((event: React.MouseEvent<HTMLElement>) => {
|
||||
setSyncPlayMenuAnchorEl(event.currentTarget);
|
||||
}, [ setSyncPlayMenuAnchorEl ]);
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ import { useApi } from 'hooks/useApi';
|
|||
import { useSyncPlayGroups } from 'hooks/useSyncPlayGroups';
|
||||
import globalize from 'scripts/globalize';
|
||||
import { PluginType } from 'types/plugin';
|
||||
import Events from 'utils/events';
|
||||
import Events, { Event } from 'utils/events';
|
||||
|
||||
export const ID = 'app-sync-play-menu';
|
||||
|
||||
|
@ -136,7 +136,7 @@ const SyncPlayMenu: FC<SyncPlayMenuProps> = ({
|
|||
}
|
||||
}, [ __legacyApiClient__, onMenuClose, syncPlay ]);
|
||||
|
||||
const updateSyncPlayGroup = useCallback((_e, enabled) => {
|
||||
const updateSyncPlayGroup = useCallback((_e: Event, enabled: boolean) => {
|
||||
if (syncPlay && enabled) {
|
||||
setCurrentGroup(syncPlay.Manager.getGroupInfo() ?? undefined);
|
||||
} else {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import React, { FunctionComponent, useCallback, useEffect, useMemo, useRef } from 'react';
|
||||
import React, { useCallback, useEffect, useMemo, useRef } from 'react';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
|
||||
import globalize from '../../../scripts/globalize';
|
||||
|
@ -25,7 +25,7 @@ type ControllerProps = {
|
|||
destroy: () => void;
|
||||
};
|
||||
|
||||
const Home: FunctionComponent = () => {
|
||||
const Home = () => {
|
||||
const [ searchParams ] = useSearchParams();
|
||||
const initialTabIndex = parseInt(searchParams.get('tab') ?? '0', 10);
|
||||
|
||||
|
|
|
@ -6,6 +6,11 @@ import globalize from 'scripts/globalize';
|
|||
import { DisplaySettingsValues } from '../types';
|
||||
import { useDisplaySettings } from './useDisplaySettings';
|
||||
|
||||
type UpdateField = {
|
||||
name: keyof DisplaySettingsValues;
|
||||
value: string | boolean;
|
||||
};
|
||||
|
||||
export function useDisplaySettingForm() {
|
||||
const [urlParams] = useSearchParams();
|
||||
const {
|
||||
|
@ -21,7 +26,7 @@ export function useDisplaySettingForm() {
|
|||
}
|
||||
}, [formValues, loading, displaySettings]);
|
||||
|
||||
const updateField = useCallback(({ name, value }) => {
|
||||
const updateField = useCallback(({ name, value }: UpdateField) => {
|
||||
if (formValues) {
|
||||
setFormValues({
|
||||
...formValues,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue