diff --git a/package-lock.json b/package-lock.json index 68d5a3804d..bf88087474 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2513,6 +2513,17 @@ "string.prototype.matchall": "^4.0.6" } }, + "@thornbill/jellyfin-sdk": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@thornbill/jellyfin-sdk/-/jellyfin-sdk-0.4.1.tgz", + "integrity": "sha512-DuUeSiIvk1qcEYp9oxnKc/e4T0zj3LujXhITQ6L6TqGOo8miNiBgU8OjmidAUwPc2ibCLAK2rM5BcNVAEwaFmw==", + "dev": true, + "requires": { + "axios": "^0.26.0", + "compare-versions": "^4.0.0", + "normalize-url": "^6.1.0" + } + }, "@trysound/sax": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", @@ -2651,6 +2662,21 @@ "localforage": "*" } }, + "@types/lodash": { + "version": "4.14.178", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.178.tgz", + "integrity": "sha512-0d5Wd09ItQWH1qFbEyQ7oTQ3GZrMfth5JkbN3EvTKLXcHLRDSXeLnlvlOn0wvxVIwK5o2M8JzP/OWz7T3NRsbw==", + "dev": true + }, + "@types/lodash-es": { + "version": "4.17.6", + "resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.6.tgz", + "integrity": "sha512-R+zTeVUKDdfoRxpAryaQNRKk3105Rrgx2CFRClIgRGaqDTdjsm8h6IYA8ir584W3ePzkZfst5xIgDwYrlh9HLg==", + "dev": true, + "requires": { + "@types/lodash": "*" + } + }, "@types/mime": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", @@ -2687,6 +2713,12 @@ "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", "dev": true }, + "@types/prop-types": { + "version": "15.7.4", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz", + "integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==", + "dev": true + }, "@types/qs": { "version": "6.9.7", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", @@ -2699,6 +2731,26 @@ "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", "dev": true }, + "@types/react": { + "version": "17.0.39", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.39.tgz", + "integrity": "sha512-UVavlfAxDd/AgAacMa60Azl7ygyQNRwC/DsHZmKgNvPmRR5p70AJ5Q9EAmL2NWOJmeV+vVUI4IAP7GZrN8h8Ug==", + "dev": true, + "requires": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "@types/react-dom": { + "version": "17.0.11", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.11.tgz", + "integrity": "sha512-f96K3k+24RaLGVu/Y2Ng3e1EbZ8/cVJvypZWd7cy0ofCBaf2lcM46xNhycMZ2xGwbBjRql7hOlZ+e2WlJ5MH3Q==", + "dev": true, + "requires": { + "@types/react": "*" + } + }, "@types/resolve": { "version": "1.17.1", "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", @@ -2714,6 +2766,12 @@ "integrity": "sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g==", "dev": true }, + "@types/scheduler": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==", + "dev": true + }, "@types/serve-index": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz", @@ -3540,6 +3598,15 @@ "integrity": "sha512-WKTW1+xAzhMS5dJsxWkliixlO/PqC4VhmO9T4juNYcaTg9jzWiJsou6m5pxWYGfigWbwzJWeFY6z47a+4neRXA==", "dev": true }, + "axios": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.0.tgz", + "integrity": "sha512-lKoGLMYtHvFrPVt3r+RBMp9nh34N0M8zEfCWqdWZx6phynIEhQqAdydpyBAAG211zlhX9Rgu08cOamy6XjE5Og==", + "dev": true, + "requires": { + "follow-redirects": "^1.14.8" + } + }, "axobject-query": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", @@ -4152,6 +4219,12 @@ "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", "dev": true }, + "compare-versions": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-4.1.3.tgz", + "integrity": "sha512-WQfnbDcrYnGr55UwbxKiQKASnTtNnaAWVi8jZyy8NTpVAXWACSne8lMD1iaIo9AiU6mnuLvSVshCzewVuWxHUg==", + "dev": true + }, "component-emitter": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", @@ -4686,6 +4759,12 @@ "css-tree": "^1.1.2" } }, + "csstype": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz", + "integrity": "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==", + "dev": true + }, "currently-unhandled": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", diff --git a/package.json b/package.json index b37e61f0df..d27e43887d 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,10 @@ "@babel/preset-env": "7.16.11", "@babel/preset-react": "7.16.7", "@babel/preset-typescript": "7.16.7", + "@thornbill/jellyfin-sdk": "0.4.1", + "@types/lodash-es": "4.17.6", + "@types/react": "17.0.39", + "@types/react-dom": "17.0.11", "@typescript-eslint/eslint-plugin": "5.12.0", "@typescript-eslint/parser": "5.12.0", "@uupaa/dynamic-import-polyfill": "1.0.2", diff --git a/src/apiclient.d.ts b/src/apiclient.d.ts new file mode 100644 index 0000000000..565ac35a83 --- /dev/null +++ b/src/apiclient.d.ts @@ -0,0 +1,350 @@ +// TODO: Move to jellyfin-apiclient +declare module 'jellyfin-apiclient' { + import { + AllThemeMediaResult, + AuthenticationResult, + BaseItemDto, + BaseItemDtoQueryResult, + BufferRequestDto, + ClientCapabilities, + CountryInfo, + CultureDto, + DeviceOptions, + DisplayPreferencesDto, + EndPointInfo, + FileSystemEntryInfo, + GeneralCommand, + GroupInfoDto, + GuideInfo, + IgnoreWaitRequestDto, + ImageInfo, + ImageProviderInfo, + ImageType, + ItemCounts, + LiveTvInfo, + MovePlaylistItemRequestDto, + NewGroupRequestDto, + NextItemRequestDto, + NotificationResultDto, + NotificationsSummaryDto, + ParentalRating, + PingRequestDto, + PlaybackInfoResponse, + PlaybackProgressInfo, + PlaybackStartInfo, + PlaybackStopInfo, + PlayCommand, + PlaystateCommand, + PluginInfo, + PluginSecurityInfo, + PreviousItemRequestDto, + QueryFiltersLegacy, + QueueRequestDto, + QuickConnectResult, + QuickConnectState, + ReadyRequestDto, + RecommendationDto, + RemoteImageResult, + RemoveFromPlaylistRequestDto, + SearchHintResult, + SeekRequestDto, + SeriesTimerInfoDto, + SeriesTimerInfoDtoQueryResult, + ServerConfiguration, + SessionInfo, + SetPlaylistItemRequestDto, + SetRepeatModeRequestDto, + SetShuffleModeRequestDto, + SystemInfo, + TaskInfo, + TaskTriggerInfo, + TimerInfoDto, + TimerInfoDtoQueryResult, + UserConfiguration, + UserDto, + UserItemDataDto, + UserPolicy, + UtcTimeResponse, + VirtualFolderInfo + } from '@thornbill/jellyfin-sdk/dist/generated-client'; + + class ApiClient { + constructor(serverAddress: string, appName: string, appVersion: string, deviceName: string, deviceId: string); + + accessToken(): string; + addMediaPath(virtualFolderName: string, mediaPath: string, networkSharePath: string, refreshLibrary?: boolean): Promise; + addVirtualFolder(name: string, type?: string, refreshLibrary?: boolean, libraryOptions?: any): Promise; + appName(): string; + appVersion(): string; + authenticateUserByName(name: string, password: string): Promise; + cancelLiveTvSeriesTimer(id: string): Promise; + cancelLiveTvTimer(id: string): Promise; + cancelSyncItems(itemIds: string[], targetId?: string): Promise; + clearAuthenticationInfo(): void; + clearUserItemRating(userId: string, itemId: string): Promise; + closeWebSocket(): void; + createLiveTvSeriesTimer(item: string): Promise; + createLiveTvTimer(item: string): Promise; + createPackageReview(review: any): Promise; + createSyncPlayGroup(options?: NewGroupRequestDto): Promise; + createUser(user: UserDto): Promise; + deleteDevice(deviceId: string): Promise; + deleteItemImage(itemId: string, imageType: ImageType, imageIndex?: number): Promise; + deleteItem(itemId: string): Promise; + deleteLiveTvRecording(id: string): Promise; + deleteUserImage(userId: string, imageType: ImageType, imageIndex?: number): Promise; + deleteUser(userId: string): Promise; + detectBitrate(force: boolean): Promise; + deviceId(): string; + deviceName(): string; + disablePlugin(id: string, version: string): Promise; + downloadRemoteImage(options: any): Promise; + enablePlugin(id: string, version: string): Promise; + encodeName(name: string): string; + ensureWebSocket(): void; + fetch(request: any, includeAuthorization?: boolean): Promise; + fetchWithFailover(request: any, enableReconnection?: boolean): Promise; + getAdditionalVideoParts(userId?: string, itemId: string): Promise; + getAlbumArtists(userId: string, options?: any): Promise; + getAncestorItems(itemId: string, userId?: string): Promise; + getArtist(name: string, userId?: string): Promise; + getArtists(userId: string, options?: any): Promise; + getAvailablePlugins(options?: any): Promise; + getAvailableRemoteImages(options: any): Promise; + getContentUploadHistory(): Promise; + getCountries(): Promise; + getCriticReviews(itemId: string, options?: any): Promise; + getCultures(): Promise; + getCurrentUserId(): string; + getDateParamValue(date: Date): string; + getDefaultImageQuality(imageType: ImageType): number; + getDevicesOptions(): Promise; + getDirectoryContents(path: string, options?: any): Promise; + getDisplayPreferences(id: string, userId: string, app: string): Promise; + getDownloadSpeed(byteSize: number): Promise; + getDrives(): Promise; + getEndpointInfo(): Promise; + getEpisodes(itemId: string, options?: any): Promise; + getFilters(options?: any): Promise; + getGenre(name: string, userId?: string): Promise; + getGenres(userId: string, options?: any): Promise; + getImageUrl(itemId: string, options?: any): string; + getInstalledPlugins(): Promise; + getInstantMixFromItem(itemId: string, options?: any): Promise; + getIntros(itemId: string): Promise; + getItemCounts(userId?: string): Promise; + getItemDownloadUrl(itemId: string): string; + getItemImageInfos(itemId: string): Promise; + getItems(userId: string, options?: any): Promise; + getItem(userId: string, itemId: string): Promise; + getJSON(url: string, includeAuthorization?: boolean): Promise; + getLatestItems(options?: any): Promise; + getLiveStreamMediaInfo(liveStreamId: string): Promise; + getLiveTvChannel(id: string, userId?: string): Promise; + getLiveTvChannels(options?: any): Promise; + getLiveTvGuideInfo(userId: string): Promise; + getLiveTvInfo(userId: string): Promise; + getLiveTvProgram(id: string, userId?: string): Promise; + getLiveTvPrograms(options?: any): Promise; + getLiveTvRecommendedPrograms(options?: any): Promise; + getLiveTvRecordingGroup(id: string): Promise; + getLiveTvRecordingGroups(options?: any): Promise; + getLiveTvRecording(id: string, userId?: string): Promise; + getLiveTvRecordingSeries(options?: any): Promise; + getLiveTvRecordings(options?: any): Promise; + getLiveTvSeriesTimer(id: string): Promise; + getLiveTvSeriesTimers(options?: any): Promise; + getLiveTvTimer(id: string): Promise; + getLiveTvTimers(options?: any): Promise; + getLocalTrailers(userId: string, itemId: string): Promise; + getMovieRecommendations(options?: any): Promise; + getMusicGenre(name: string, userId?: string): Promise; + getMusicGenres(userId: string, options?: any): Promise; + getNamedConfiguration(name: string): Promise; + getNetworkDevices(): Promise; + getNetworkShares(path: string): Promise; + getNewLiveTvTimerDefaults(options?: any): Promise; + getNextUpEpisodes(options?: any): Promise; + getNotificationSummary(userId: string): Promise; + getNotifications(userId: string, options?: any): Promise; + getPackageInfo(name: string, guid: string): Promise; + getPackageReviews(packageId: string, minRating?: string, maxRating?: string, limit?: string): Promise; + getParentalRatings(): Promise; + getParentPath(path: string): Promise; + getPeople(userId: string, options?: any): Promise; + getPerson(name: string, userId?: string): Promise; + getPhysicalPaths(): Promise; + getPlaybackInfo(itemId: string, options: any, deviceProfile: any): Promise; + getPluginConfiguration(id: string): Promise; + getPublicSystemInfo(): Promise; + getPublicUsers(): Promise; + getQuickConnect(verb: string): Promise; + getReadySyncItems(deviceId: string): Promise; + getRecordingFolders(userId: string): Promise; + getRegistrationInfo(feature: string): Promise; + getRemoteImageProviders(options: any): Promise; + getResumableItems(userId: string, options?: any): Promise; + getRootFolder(userId: string): Promise; + getSavedEndpointInfo(): EndPointInfo; + getScaledImageUrl(itemId: string, options?: any): string; + getScheduledTask(id: string): Promise; + getScheduledTasks(options?: any): Promise; + getSearchHints(options?: any): Promise; + getSeasons(itemId: string, options?: any): Promise; + getServerConfiguration(): Promise; + getServerTime(): Promise; + getSessions(options?: any): Promise; + getSimilarItems(itemId: string, options?: any): Promise; + getSpecialFeatures(userId: string, itemId: string): Promise; + getStudio(name: string, userId?: string): Promise; + getStudios(userId: string, options?: any): Promise; + getSyncPlayGroups(): Promise; + getSyncStatus(itemId: string): Promise; + getSystemInfo(): Promise; + getThemeMedia(userId?: string, itemId: string, inherit?: boolean): Promise; + getThumbImageUrl(item: BaseItemDto, options?: any): string; + getUpcomingEpisodes(options?: any): Promise; + getUrl(name: string, params?: any, serverAddress?: string): string; + get(url: string): Promise; + getUserImageUrl(userId: string, options?: any): string; + getUsers(options?: any): Promise; + getUser(userId: string): Promise; + getUserViews(options?: any, userId: string): Promise; + getVirtualFolders(): Promise; + handleMessageReceived(msg: any): void; + installPlugin(name: string, guid: string, version?: string): Promise; + isLoggedIn(): boolean; + isMessageChannelOpen(): boolean; + isMinServerVersion(version: string): boolean; + isWebSocketOpen(): boolean; + isWebSocketOpenOrConnecting(): boolean; + isWebSocketSupported(): boolean; + joinSyncPlayGroup(options?: any): Promise; + leaveSyncPlayGroup(): Promise; + logout(): Promise; + markNotificationsRead(userId: string, idList: string[], isRead: boolean): Promise; + markPlayed(userId: string, itemId: string, date: Date): Promise; + markUnplayed(userId: string, itemId: string, date: Date): Promise; + openWebSocket(): void; + quickConnect(secret: string): Promise; + refreshItem(itemId: string, options?: any): Promise; + removeMediaPath(virtualFolderName: string, mediaPath: string, refreshLibrary?: boolean): Promise; + removeVirtualFolder(name: string, refreshLibrary?: boolean): Promise; + renameVirtualFolder(name: string, newName: string, refreshLibrary?: boolean): Promise; + reportCapabilities(capabilities: ClientCapabilities): Promise; + reportOfflineActions(actions: any): Promise; + reportPlaybackProgress(options: PlaybackProgressInfo): Promise; + reportPlaybackStart(options: PlaybackStartInfo): Promise; + reportPlaybackStopped(options: PlaybackStopInfo): Promise; + reportSyncJobItemTransferred(syncJobItemId: string): Promise; + requestSyncPlayBuffering(options?: BufferRequestDto): Promise; + requestSyncPlayMovePlaylistItem(options?: MovePlaylistItemRequestDto): Promise; + requestSyncPlayNextItem(options?: NextItemRequestDto): Promise; + requestSyncPlayPause(): Promise; + requestSyncPlayPreviousItem(options?: PreviousItemRequestDto): Promise; + requestSyncPlayQueue(options?: QueueRequestDto): Promise; + requestSyncPlayReady(options?: ReadyRequestDto): Promise; + requestSyncPlayRemoveFromPlaylist(options?: RemoveFromPlaylistRequestDto): Promise; + requestSyncPlaySeek(options?: SeekRequestDto): Promise; + requestSyncPlaySetIgnoreWait(options?: IgnoreWaitRequestDto): Promise; + requestSyncPlaySetNewQueue(options?: NewGroupRequestDto): Promise; + requestSyncPlaySetPlaylistItem(options?: SetPlaylistItemRequestDto): Promise; + requestSyncPlaySetRepeatMode(options?: SetRepeatModeRequestDto): Promise; + requestSyncPlaySetShuffleMode(options?: SetShuffleModeRequestDto): Promise; + requestSyncPlayUnpause(): Promise; + resetEasyPassword(userId: string): Promise; + resetLiveTvTuner(id: string): Promise; + resetUserPassword(userId: string): Promise; + restartServer(): Promise; + sendCommand(sessionId: string, command: any): Promise; + sendMessageCommand(sessionId: string, options: GeneralCommand): Promise; + sendMessage(name: string, data: any): void; + sendPlayCommand(sessionId: string, options: PlayCommand): Promise; + sendPlayStateCommand(sessionId: string, command: PlaystateCommand, options?: any): Promise; + sendSyncPlayPing(options?: PingRequestDto): Promise; + sendWebSocketMessage(name: string, data: any): void; + serverAddress(val?: string): string; + serverId(): string; + serverVersion(): string + setAuthenticationInfo(accessKey?: string, userId?: string): void; + setRequestHeaders(headers: any): void; + setSystemInfo(info: SystemInfo): void; + shutdownServer(): Promise; + startScheduledTask(id: string): Promise; + stopActiveEncodings(playSessionId: string): Promise; + stopScheduledTask(id: string): Promise; + syncData(data: any): Promise; + uninstallPluginByVersion(id: string, version: string): Promise; + uninstallPlugin(id: string): Promise; + updateDisplayPreferences(id: string, obj: DisplayPreferencesDto, userId: string, app: string): Promise; + updateEasyPassword(userId: string, newPassword: string): Promise; + updateFavoriteStatus(userId: string, itemId: string, isFavorite: boolean): Promise; + updateItemImageIndex(itemId: string, imageType: ImageType, imageIndex: number, newIndex: number): Promise; + updateItem(item: BaseItemDto): Promise; + updateLiveTvSeriesTimer(item: SeriesTimerInfoDto): Promise; + updateLiveTvTimer(item: TimerInfoDto): Promise; + updateMediaPath(virtualFolderName: string, pathInfo: any): Promise; + updateNamedConfiguration(name: string, configuration: any): Promise; + updatePluginConfiguration(id: string, configuration: any): Promise; + updatePluginSecurityInfo(info: PluginSecurityInfo): Promise; + updateScheduledTaskTriggers(id: string, triggers: TaskTriggerInfo[]): Promise; + updateServerConfiguration(configuration: ServerConfiguration): Promise; + updateServerInfo(server: any, serverUrl: string): void; + updateUserConfiguration(userId: string, configuration: UserConfiguration): Promise; + updateUserItemRating(userId: string, itemId: string, likes: boolean): Promise; + updateUserPassword(userId: string, currentPassword: string, newPassword: string): Promise; + updateUserPolicy(userId: string, policy: UserPolicy): Promise; + updateUser(user: UserDto): Promise; + updateVirtualFolderOptions(id: string, libraryOptions?: any): Promise; + uploadItemImage(itemId: string, imageType: ImageType, file: File): Promise; + uploadItemSubtitle(itemId: string, language: string, isForced: boolean, file: File): Promise; + uploadUserImage(userId: string, imageType: ImageType, file: File): Promise; + } + + class AppStore { + constructor(); + + getItem(name: string): string|null; + removeItem(name: string): void; + setItem(name: string, value: string): void; + } + + class ConnectionManager { + constructor(credentialProvider: Credentials, appName: string, appVersion: string, deviceName: string, deviceId: string, capabilities: ClientCapabilities); + + addApiClient(apiClient: ApiClient): void; + clearData(): void; + connect(options?: any): Promise; + connectToAddress(address: string, options?: any): Promise; + connectToServer(server: any, options?: any): Promise; + connectToServers(servers: any[], options?: any): Promise; + deleteServer(serverId: string): Promise; + getApiClient(item: BaseItemDto|string): ApiClient; + getApiClients(): ApiClient[]; + getAvailableServers(): any[]; + getOrCreateApiClient(serverId: string): ApiClient; + getSavedServers(): any[]; + handleMessageReceived(msg: any): void; + logout(): Promise; + minServerVersion(val?: string): string; + user(apiClient: ApiClient): Promise; + } + + class Credentials { + constructor(key?: string); + + addOrUpdateServer(list: any[], server: any): any; + clear(): void; + credentials(data?: any): any; + } + + interface Event { + type: string; + } + + const Events: { + off(obj: any, eventName: string, fn: (e: Event, ...args: any[]) => void): void; + on(obj: any, eventName: string, fn: (e: Event, ...args: any[]) => void): void; + trigger(obj: any, eventName: string, ...args: any[]): void; + }; +} diff --git a/src/components/alphaPicker/AlphaPickerComponent.tsx b/src/components/alphaPicker/AlphaPickerComponent.tsx index 0ea33cd212..3c476bb13a 100644 --- a/src/components/alphaPicker/AlphaPickerComponent.tsx +++ b/src/components/alphaPicker/AlphaPickerComponent.tsx @@ -3,14 +3,14 @@ import React, { FunctionComponent, useEffect, useRef, useState } from 'react'; import AlphaPicker from './alphaPicker'; type AlphaPickerProps = { - onAlphaPicked?: () => void + onAlphaPicked?: (e: Event) => void }; // React compatibility wrapper component for alphaPicker.js // eslint-disable-next-line @typescript-eslint/no-empty-function const AlphaPickerComponent: FunctionComponent = ({ onAlphaPicked = () => {} }: AlphaPickerProps) => { - const [ alphaPicker, setAlphaPicker ] = useState(null); - const element = useRef(null); + const [ alphaPicker, setAlphaPicker ] = useState(); + const element = useRef(null); useEffect(() => { setAlphaPicker(new AlphaPicker({ diff --git a/src/components/cardbuilder/cardBuilder.js b/src/components/cardbuilder/cardBuilder.js index ff224044b8..197e0efcae 100644 --- a/src/components/cardbuilder/cardBuilder.js +++ b/src/components/cardbuilder/cardBuilder.js @@ -481,12 +481,20 @@ import ServerConnections from '../ServerConnections'; return null; } + /** + * @typedef {Object} CardImageUrl + * @property {string} imgUrl - Image URL. + * @property {string} blurhash - Image blurhash. + * @property {boolean} forceName - Force name. + * @property {boolean} coverImage - Use cover style. + */ + /** Get the URL of the card's image. * @param {Object} item - Item for which to generate a card. * @param {Object} apiClient - API client object. * @param {Object} options - Options of the card. * @param {string} shape - Shape of the desired image. - * @returns {Object} Object representing the URL of the card's image. + * @returns {CardImageUrl} Object representing the URL of the card's image. */ function getCardImageUrl(item, apiClient, options, shape) { item = item.ProgramInfo || item; @@ -639,7 +647,7 @@ import ServerConnections from '../ServerConnections'; /** * Generates an index used to select the default color of a card based on a string. - * @param {string} str - String to use for generating the index. + * @param {?string} [str] - String to use for generating the index. * @returns {number} Index of the color. */ function getDefaultColorIndex(str) { @@ -726,8 +734,8 @@ import ServerConnections from '../ServerConnections'; /** * Returns the air time text for the item based on the given times. * @param {object} item - Item used to generate the air time text. - * @param {string} showAirDateTime - ISO8601 date for the start of the show. - * @param {string} showAirEndTime - ISO8601 date for the end of the show. + * @param {boolean} showAirDateTime - ISO8601 date for the start of the show. + * @param {boolean} showAirEndTime - ISO8601 date for the end of the show. * @returns {string} The air time text for the item based on the given dates. */ function getAirTimeText(item, showAirDateTime, showAirEndTime) { @@ -1129,7 +1137,7 @@ import ServerConnections from '../ServerConnections'; /** * Returns the default background class for a card based on a string. - * @param {string} str - Text used to generate the background class. + * @param {?string} [str] - Text used to generate the background class. * @returns {string} CSS classes for default card backgrounds. */ export function getDefaultBackgroundClass(str) { diff --git a/src/components/dashboard/users/AccessScheduleList.tsx b/src/components/dashboard/users/AccessScheduleList.tsx index 0a2aceaa55..1e788d796f 100644 --- a/src/components/dashboard/users/AccessScheduleList.tsx +++ b/src/components/dashboard/users/AccessScheduleList.tsx @@ -2,7 +2,7 @@ import React, { FunctionComponent } from 'react'; import datetime from '../../../scripts/datetime'; import globalize from '../../../scripts/globalize'; -const createButtonElement = ({index}) => ({ +const createButtonElement = (index: number) => ({ __html: `