1
0
Fork 0
mirror of https://github.com/jellyfin/jellyfin-web synced 2025-03-30 19:56:21 +00:00

Add eslint rules for sonar issues

This commit is contained in:
Bill Thornton 2022-12-16 16:02:11 -05:00
parent 2690b90d84
commit 19f416580c
12 changed files with 45 additions and 30 deletions

View file

@ -56,6 +56,7 @@ module.exports = {
'no-return-assign': ['error'],
'no-return-await': ['error'],
'no-sequences': ['error', { 'allowInParentheses': false }],
'no-shadow': ['error'],
'no-trailing-spaces': ['error'],
'@babel/no-unused-expressions': ['error', { 'allowShortCircuit': true, 'allowTernary': true, 'allowTaggedTemplates': true }],
'no-useless-constructor': ['error'],
@ -70,12 +71,15 @@ module.exports = {
'space-before-blocks': ['error'],
'space-infix-ops': 'error',
'yoda': 'error',
'@typescript-eslint/no-shadow': 'error',
'react/jsx-filename-extension': ['error', { 'extensions': ['.jsx', '.tsx'] }],
'react/jsx-no-bind': ['error'],
'react/jsx-no-constructed-context-values': ['error'],
'react/no-array-index-key': ['error'],
'sonarjs/cognitive-complexity': ['warn'],
'sonarjs/no-inverted-boolean-check': ['error'],
// TODO: Enable the following rules and fix issues
'sonarjs/cognitive-complexity': ['off'],
'sonarjs/no-duplicate-string': ['off']
},
settings: {
@ -255,8 +259,14 @@ module.exports = {
'plugin:jsx-a11y/recommended'
],
rules: {
// Use TypeScript equivalent rules when required
'no-shadow': ['off'],
'@typescript-eslint/no-shadow': ['error'],
'no-useless-constructor': ['off'],
'@typescript-eslint/no-useless-constructor': ['error']
'@typescript-eslint/no-useless-constructor': ['error'],
'max-params': ['error', 7],
'sonarjs/cognitive-complexity': ['warn']
}
}
]

View file

@ -90,8 +90,8 @@ const GenresItemsContainer: FC<GenresItemsContainerProps> = ({
<h1>{globalize.translate('MessageNothingHere')}</h1>
<p>{globalize.translate('MessageNoGenresAvailable')}</p>
</div>
) : items.map((item, index) => (
<div key={index} className='verticalSection'>
) : items.map(item => (
<div key={item.Id} className='verticalSection'>
<div
className='sectionTitleContainer sectionTitleContainer-cards padded-left'
dangerouslySetInnerHTML={createLinkElement({

View file

@ -610,7 +610,7 @@ export default function () {
function onTimeUpdate() {
const now = new Date().getTime();
if (!(now - lastUpdateTime < 700)) {
if (now - lastUpdateTime >= 700) {
lastUpdateTime = now;
const player = this;
currentRuntimeTicks = playbackManager.duration(player);

View file

@ -125,7 +125,7 @@ const LiveTVSearchResults: FunctionComponent<LiveTVSearchResultsProps> = ({ serv
'searchResults',
'padded-bottom-page',
'padded-top',
{ 'hide': !query || !(collectionType === 'livetv') }
{ 'hide': !query || collectionType !== 'livetv' }
)}
>
<SearchResultsRow

View file

@ -1,5 +1,5 @@
import debounce from 'lodash-es/debounce';
import React, { FunctionComponent, useEffect, useMemo, useRef } from 'react';
import React, { FunctionComponent, useCallback, useEffect, useMemo, useRef } from 'react';
import AlphaPicker from '../alphaPicker/AlphaPickerComponent';
import globalize from '../../scripts/globalize';
@ -53,7 +53,7 @@ const SearchFields: FunctionComponent<SearchFieldsProps> = ({ onSearch = () => {
};
}, [debouncedOnSearch]);
const onAlphaPicked = (e: Event) => {
const onAlphaPicked = useCallback((e: Event) => {
const value = (e as CustomEvent).detail.value;
const searchInput = getSearchInput();
@ -70,7 +70,7 @@ const SearchFields: FunctionComponent<SearchFieldsProps> = ({ onSearch = () => {
}
searchInput.dispatchEvent(new CustomEvent('input', { bubbles: true }));
};
}, []);
return (
<div

View file

@ -1106,7 +1106,7 @@ class ItemsView {
const filters = [];
const params = this.params;
if (!(params.type === 'nextup')) {
if (params.type !== 'nextup') {
if (params.type === 'Programs') {
filters.push('Genres');
} else {

View file

@ -585,7 +585,7 @@ import { setBackdropTransparency, TRANSPARENCY_LEVEL } from '../../../components
if (isEnabled && currentItem) {
const now = new Date().getTime();
if (!(now - lastUpdateTime < 700)) {
if (now - lastUpdateTime >= 700) {
lastUpdateTime = now;
const player = this;
currentRuntimeTicks = playbackManager.duration(player);

View file

@ -1,4 +1,4 @@
import React, { AnchorHTMLAttributes, DetailedHTMLProps, MouseEvent } from 'react';
import React, { AnchorHTMLAttributes, DetailedHTMLProps, MouseEvent, useCallback } from 'react';
import classNames from 'classnames';
import layoutManager from '../../components/layoutManager';
import shell from '../../scripts/shell';
@ -23,7 +23,7 @@ const LinkButton: React.FC<LinkButtonProps> = ({
children,
...rest
}) => {
const onAnchorClick = (e: MouseEvent<HTMLAnchorElement>) => {
const onAnchorClick = useCallback((e: MouseEvent<HTMLAnchorElement>) => {
const url = href || '';
if (url !== '#') {
if (target) {
@ -38,7 +38,7 @@ const LinkButton: React.FC<LinkButtonProps> = ({
} else {
e.preventDefault();
}
};
}, [ href, target ]);
if (isAutoHideEnabled === true && !appHost.supports('externallinks')) {
return null;

View file

@ -29,7 +29,7 @@ const ScrollButtons: FC<ScrollButtonsProps> = ({ scrollerFactoryRef, scrollState
}
}, [scrollerFactoryRef]);
const onScrollButtonClick = (direction: Direction) => {
const onScrollButtonClick = useCallback((direction: Direction) => {
let newPos;
if (direction === Direction.LEFT) {
newPos = Math.max(0, scrollState.scrollPos - scrollState.scrollSize);
@ -44,7 +44,10 @@ const ScrollButtons: FC<ScrollButtonsProps> = ({ scrollerFactoryRef, scrollState
}
scrollToPosition(newPos, false);
};
}, [ scrollState.scrollPos, scrollState.scrollSize, scrollToPosition ]);
const triggerScrollLeft = useCallback(() => onScrollButtonClick(Direction.LEFT), [ onScrollButtonClick ]);
const triggerScrollRight = useCallback(() => onScrollButtonClick(Direction.RIGHT), [ onScrollButtonClick ]);
useEffect(() => {
const parent = scrollButtonsRef.current?.parentNode as HTMLDivElement;
@ -63,7 +66,7 @@ const ScrollButtons: FC<ScrollButtonsProps> = ({ scrollerFactoryRef, scrollState
<IconButton
type='button'
className='emby-scrollbuttons-button btnPrev'
onClick={() => onScrollButtonClick(Direction.LEFT)}
onClick={triggerScrollLeft}
icon='chevron_left'
disabled={localeScrollPos > 0 ? false : true}
/>
@ -71,7 +74,7 @@ const ScrollButtons: FC<ScrollButtonsProps> = ({ scrollerFactoryRef, scrollState
<IconButton
type='button'
className='emby-scrollbuttons-button btnNext'
onClick={() => onScrollButtonClick(Direction.RIGHT)}
onClick={triggerScrollRight}
icon='chevron_right'
disabled={scrollState.scrollWidth > 0 && localeScrollPos + scrollState.scrollSize >= scrollState.scrollWidth ? true : false}
/>

View file

@ -1,7 +1,7 @@
import type { Api } from '@jellyfin/sdk';
import type { UserDto } from '@jellyfin/sdk/lib/generated-client';
import type { ApiClient, Event } from 'jellyfin-apiclient';
import React, { createContext, FC, useContext, useEffect, useState } from 'react';
import React, { createContext, FC, useContext, useEffect, useMemo, useState } from 'react';
import ServerConnections from '../components/ServerConnections';
import events from '../utils/events';
@ -21,6 +21,12 @@ export const ApiProvider: FC = ({ children }) => {
const [ api, setApi ] = useState<Api>();
const [ user, setUser ] = useState<UserDto>();
const context = useMemo(() => ({
__legacyApiClient__: legacyApiClient,
api,
user
}), [ api, legacyApiClient, user ]);
useEffect(() => {
ServerConnections.currentApiClient()
?.getCurrentUser()
@ -56,11 +62,7 @@ export const ApiProvider: FC = ({ children }) => {
}, [ legacyApiClient, setApi ]);
return (
<ApiContext.Provider value={{
__legacyApiClient__: legacyApiClient,
api,
user
}}>
<ApiContext.Provider value={context}>
{children}
</ApiContext.Provider>
);

View file

@ -143,8 +143,8 @@ const SuggestionsView: FC<LibraryViewProps> = ({topParentId}) => {
{!recommendations.length ? <div className='noItemsMessage centerMessage'>
<h1>{globalize.translate('MessageNothingHere')}</h1>
<p>{globalize.translate('MessageNoMovieSuggestionsAvailable')}</p>
</div> : recommendations.map((recommendation, index) => {
return <RecommendationContainer key={index} getPortraitShape={getPortraitShape} enableScrollX={enableScrollX} recommendation={recommendation} />;
</div> : recommendations.map(recommendation => {
return <RecommendationContainer key={recommendation.CategoryId} getPortraitShape={getPortraitShape} enableScrollX={enableScrollX} recommendation={recommendation} />;
})}
</div>
);

View file

@ -379,9 +379,9 @@ const UserParentalControl: FunctionComponent = () => {
isLinkVisible={false}
/>
<div className='blockedTags' style={{marginTop: '.5em'}}>
{blockedTags.map((tag, index) => {
{blockedTags.map(tag => {
return <BlockedTagList
key={index}
key={tag}
tag={tag}
/>;
})}
@ -401,7 +401,7 @@ const UserParentalControl: FunctionComponent = () => {
<div className='accessScheduleList paperList'>
{accessSchedules.map((accessSchedule, index) => {
return <AccessScheduleList
key={index}
key={accessSchedule.Id}
index={index}
Id={accessSchedule.Id}
DayOfWeek={accessSchedule.DayOfWeek}