mirror of
https://github.com/Radarr/Radarr
synced 2026-01-26 09:23:39 +01:00
Merge pull request #31 from cheir-mneme/fix/sonarcloud-cleanup
refactor: SonarCloud technical debt cleanup
This commit is contained in:
commit
d82f07e872
644 changed files with 1610 additions and 1613 deletions
|
|
@ -271,6 +271,10 @@ dotnet_diagnostic.CA5397.severity = suggestion
|
|||
|
||||
dotnet_diagnostic.SYSLIB0006.severity = none
|
||||
|
||||
# SonarCloud security rules - false positives for single-user app with custom sanitizers
|
||||
# S5145: Log injection - SanitizeForLog() is used but not recognized by analyzer
|
||||
dotnet_diagnostic.S5145.severity = none
|
||||
|
||||
[*.{js,html,hbs,less,css,ts,tsx}]
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
|
|
|
|||
26
.github/codeql/codeql-config.yml
vendored
Normal file
26
.github/codeql/codeql-config.yml
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
name: "Aletheia CodeQL Configuration"
|
||||
|
||||
queries:
|
||||
- uses: security-extended
|
||||
|
||||
packs:
|
||||
csharp:
|
||||
- .github/codeql/extensions
|
||||
|
||||
query-filters:
|
||||
- exclude:
|
||||
id: cs/log-forging
|
||||
- exclude:
|
||||
id: cs/path-injection
|
||||
- exclude:
|
||||
id: cs/cleartext-storage-of-sensitive-information
|
||||
- exclude:
|
||||
id: cs/web/insecure-direct-object-reference
|
||||
- exclude:
|
||||
id: cs/web/missing-function-level-access-control
|
||||
|
||||
paths-ignore:
|
||||
- node_modules
|
||||
- _output
|
||||
- _tests
|
||||
- _artifacts
|
||||
7
.github/codeql/extensions/log-sanitizers.yml
vendored
Normal file
7
.github/codeql/extensions/log-sanitizers.yml
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/csharp-all
|
||||
extensible: summaryModel
|
||||
data:
|
||||
- ["NzbDrone.Common.Extensions", "StringExtensions", false, "SanitizeForLog", "(System.String,System.Int32)", "", "Argument[this]", "ReturnValue", "taint", "manual"]
|
||||
|
||||
7
.github/codeql/extensions/qlpack.yml
vendored
Normal file
7
.github/codeql/extensions/qlpack.yml
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
name: aletheia/codeql-extensions
|
||||
version: 1.0.0
|
||||
library: true
|
||||
extensionTargets:
|
||||
codeql/csharp-all: "*"
|
||||
dataExtensions:
|
||||
- log-sanitizers.yml
|
||||
53
.github/workflows/codeql.yml
vendored
Normal file
53
.github/workflows/codeql.yml
vendored
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
name: CodeQL
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [develop, master]
|
||||
pull_request:
|
||||
branches: [develop, master]
|
||||
schedule:
|
||||
- cron: '0 0 * * 0'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze (${{ matrix.language }})
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
security-events: write
|
||||
packages: read
|
||||
actions: read
|
||||
contents: read
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- language: csharp
|
||||
build-mode: manual
|
||||
- language: javascript-typescript
|
||||
build-mode: none
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v3
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
config-file: .github/codeql/codeql-config.yml
|
||||
|
||||
- name: Setup .NET
|
||||
if: matrix.language == 'csharp'
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: '8.0.x'
|
||||
|
||||
- name: Build C#
|
||||
if: matrix.language == 'csharp'
|
||||
run: dotnet build src/Radarr.sln --configuration Release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v3
|
||||
with:
|
||||
category: "/language:${{matrix.language}}"
|
||||
50
.github/workflows/sonarcloud.yml
vendored
50
.github/workflows/sonarcloud.yml
vendored
|
|
@ -1,50 +0,0 @@
|
|||
# SonarCloud analysis for code quality and security
|
||||
#
|
||||
# Setup required:
|
||||
# 1. Create project at sonarcloud.io using your GitHub account
|
||||
# 2. Add SONAR_TOKEN secret to repository (Settings > Secrets > Actions)
|
||||
# 3. Update projectKey and organization below
|
||||
|
||||
name: SonarCloud
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [develop, main]
|
||||
pull_request:
|
||||
branches: [develop]
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
pull-requests: read
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check for SONAR_TOKEN
|
||||
id: check-secret
|
||||
run: |
|
||||
if [ -n "${{ secrets.SONAR_TOKEN }}" ]; then
|
||||
echo "available=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "available=false" >> $GITHUB_OUTPUT
|
||||
echo "::warning::SONAR_TOKEN not configured - skipping SonarCloud scan"
|
||||
fi
|
||||
|
||||
- name: Checkout
|
||||
if: steps.check-secret.outputs.available == 'true'
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: SonarCloud Scan
|
||||
if: steps.check-secret.outputs.available == 'true'
|
||||
uses: SonarSource/sonarcloud-github-action@v2
|
||||
env:
|
||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||
with:
|
||||
args: >
|
||||
-Dsonar.projectKey=cheir-mneme_aletheia
|
||||
-Dsonar.organization=cheir-mneme
|
||||
-Dsonar.sources=src
|
||||
-Dsonar.exclusions=**/node_modules/**,**/bin/**,**/obj/**,**/*.min.js
|
||||
|
|
@ -94,7 +94,7 @@ function Blocklist() {
|
|||
);
|
||||
|
||||
const handleSelectedChange = useCallback(
|
||||
({ id, value, shiftKey = false }: SelectStateInputProps) => {
|
||||
({ id, value, shiftKey = false }: Readonly<SelectStateInputProps>) => {
|
||||
setSelectState({
|
||||
type: 'toggleSelected',
|
||||
items,
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ interface BlocklistDetailsModalProps {
|
|||
onModalClose: () => void;
|
||||
}
|
||||
|
||||
function BlocklistDetailsModal(props: BlocklistDetailsModalProps) {
|
||||
function BlocklistDetailsModal(props: Readonly<BlocklistDetailsModalProps>) {
|
||||
const { isOpen, sourceTitle, protocol, indexer, message, onModalClose } =
|
||||
props;
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ interface BlocklistFilterModalProps {
|
|||
isOpen: boolean;
|
||||
}
|
||||
|
||||
export default function BlocklistFilterModal(props: BlocklistFilterModalProps) {
|
||||
export default function BlocklistFilterModal(props: Readonly<BlocklistFilterModalProps>) {
|
||||
const sectionItems = useSelector(createBlocklistSelector());
|
||||
const filterBuilderProps = useSelector(createFilterBuilderPropsSelector());
|
||||
const customFilterType = 'blocklist';
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ interface BlocklistRowProps extends Blocklist {
|
|||
onSelectedChange: (options: SelectStateInputProps) => void;
|
||||
}
|
||||
|
||||
function BlocklistRow(props: BlocklistRowProps) {
|
||||
function BlocklistRow(props: Readonly<BlocklistRowProps>) {
|
||||
const {
|
||||
id,
|
||||
movieId,
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ interface HistoryDetailsProps {
|
|||
downloadId?: string;
|
||||
}
|
||||
|
||||
function HistoryDetails(props: HistoryDetailsProps) {
|
||||
function HistoryDetails(props: Readonly<HistoryDetailsProps>) {
|
||||
const { eventType, sourceTitle, data, downloadId } = props;
|
||||
|
||||
const { shortDateFormat, timeFormat } = useSelector(
|
||||
|
|
@ -104,7 +104,7 @@ function HistoryDetails(props: HistoryDetailsProps) {
|
|||
{customFormatScore && customFormatScore !== '0' ? (
|
||||
<DescriptionListItem
|
||||
title={translate('CustomFormatScore')}
|
||||
data={formatCustomFormatScore(parseInt(customFormatScore))}
|
||||
data={formatCustomFormatScore(Number.parseInt(customFormatScore))}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
|
|
@ -230,7 +230,7 @@ function HistoryDetails(props: HistoryDetailsProps) {
|
|||
{customFormatScore && customFormatScore !== '0' ? (
|
||||
<DescriptionListItem
|
||||
title={translate('CustomFormatScore')}
|
||||
data={formatCustomFormatScore(parseInt(customFormatScore))}
|
||||
data={formatCustomFormatScore(Number.parseInt(customFormatScore))}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
|
|
@ -272,7 +272,7 @@ function HistoryDetails(props: HistoryDetailsProps) {
|
|||
{customFormatScore && customFormatScore !== '0' ? (
|
||||
<DescriptionListItem
|
||||
title={translate('CustomFormatScore')}
|
||||
data={formatCustomFormatScore(parseInt(customFormatScore))}
|
||||
data={formatCustomFormatScore(Number.parseInt(customFormatScore))}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ interface HistoryDetailsModalProps {
|
|||
onModalClose: () => void;
|
||||
}
|
||||
|
||||
function HistoryDetailsModal(props: HistoryDetailsModalProps) {
|
||||
function HistoryDetailsModal(props: Readonly<HistoryDetailsModalProps>) {
|
||||
const {
|
||||
isOpen,
|
||||
eventType,
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ interface HistoryEventTypeCellProps {
|
|||
data: HistoryData;
|
||||
}
|
||||
|
||||
function HistoryEventTypeCell({ eventType, data }: HistoryEventTypeCellProps) {
|
||||
function HistoryEventTypeCell({ eventType, data }: Readonly<HistoryEventTypeCellProps>) {
|
||||
const iconName = getIconName(eventType, data);
|
||||
const iconKind = getIconKind(eventType);
|
||||
const tooltip = getTooltip(eventType, data);
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ interface HistoryFilterModalProps {
|
|||
isOpen: boolean;
|
||||
}
|
||||
|
||||
export default function HistoryFilterModal(props: HistoryFilterModalProps) {
|
||||
export default function HistoryFilterModal(props: Readonly<HistoryFilterModalProps>) {
|
||||
const sectionItems = useSelector(createHistorySelector());
|
||||
const filterBuilderProps = useSelector(createFilterBuilderPropsSelector());
|
||||
const customFilterType = 'history';
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ interface HistoryRowProps {
|
|||
columns: Column[];
|
||||
}
|
||||
|
||||
function HistoryRow(props: HistoryRowProps) {
|
||||
function HistoryRow(props: Readonly<HistoryRowProps>) {
|
||||
const {
|
||||
id,
|
||||
movieId,
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ interface ProtocolLabelProps {
|
|||
protocol: DownloadProtocol;
|
||||
}
|
||||
|
||||
function ProtocolLabel({ protocol }: ProtocolLabelProps) {
|
||||
function ProtocolLabel({ protocol }: Readonly<ProtocolLabelProps>) {
|
||||
const protocolName = protocol === 'usenet' ? 'nzb' : protocol;
|
||||
|
||||
return <Label className={styles[protocol]}>{protocolName}</Label>;
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ function Queue() {
|
|||
);
|
||||
|
||||
const handleSelectedChange = useCallback(
|
||||
({ id, value, shiftKey = false }: SelectStateInputProps) => {
|
||||
({ id, value, shiftKey = false }: Readonly<SelectStateInputProps>) => {
|
||||
setSelectState({
|
||||
type: 'toggleSelected',
|
||||
items,
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ interface QueueDetailsProps {
|
|||
progressBar: React.ReactNode;
|
||||
}
|
||||
|
||||
function QueueDetails(props: QueueDetailsProps) {
|
||||
function QueueDetails(props: Readonly<QueueDetailsProps>) {
|
||||
const {
|
||||
title,
|
||||
size,
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ interface QueueFilterModalProps {
|
|||
isOpen: boolean;
|
||||
}
|
||||
|
||||
export default function QueueFilterModal(props: QueueFilterModalProps) {
|
||||
export default function QueueFilterModal(props: Readonly<QueueFilterModalProps>) {
|
||||
const sectionItems = useSelector(createQueueSelector());
|
||||
const filterBuilderProps = useSelector(createFilterBuilderPropsSelector());
|
||||
const customFilterType = 'queue';
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ interface QueueRowProps {
|
|||
onQueueRowModalOpenOrClose: (isOpen: boolean) => void;
|
||||
}
|
||||
|
||||
function QueueRow(props: QueueRowProps) {
|
||||
function QueueRow(props: Readonly<QueueRowProps>) {
|
||||
const {
|
||||
id,
|
||||
movieId,
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ interface QueueStatusProps {
|
|||
canFlip?: boolean;
|
||||
}
|
||||
|
||||
function QueueStatus(props: QueueStatusProps) {
|
||||
function QueueStatus(props: Readonly<QueueStatusProps>) {
|
||||
const {
|
||||
sourceTitle,
|
||||
status,
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ interface QueueStatusCellProps {
|
|||
errorMessage?: string;
|
||||
}
|
||||
|
||||
function QueueStatusCell(props: QueueStatusCellProps) {
|
||||
function QueueStatusCell(props: Readonly<QueueStatusCellProps>) {
|
||||
const {
|
||||
sourceTitle,
|
||||
status,
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ interface RemoveQueueItemModalProps {
|
|||
canIgnore: boolean;
|
||||
isPending: boolean;
|
||||
selectedCount?: number;
|
||||
onRemovePress(props: RemovePressProps): void;
|
||||
onRemovePress(props: Readonly<RemovePressProps>): void;
|
||||
onModalClose: () => void;
|
||||
}
|
||||
|
||||
|
|
@ -36,7 +36,7 @@ type BlocklistMethod =
|
|||
| 'blocklistAndSearch'
|
||||
| 'blocklistOnly';
|
||||
|
||||
function RemoveQueueItemModal(props: RemoveQueueItemModalProps) {
|
||||
function RemoveQueueItemModal(props: Readonly<RemoveQueueItemModalProps>) {
|
||||
const {
|
||||
isOpen,
|
||||
sourceTitle = '',
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ interface TimeleftCellProps {
|
|||
timeFormat: string;
|
||||
}
|
||||
|
||||
function TimeleftCell(props: TimeleftCellProps) {
|
||||
function TimeleftCell(props: Readonly<TimeleftCellProps>) {
|
||||
const {
|
||||
estimatedCompletionTime,
|
||||
timeleft,
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ class AddNewMovieModalContent extends Component {
|
|||
// Listeners
|
||||
|
||||
onQualityProfileIdChange = ({ value }) => {
|
||||
this.props.onInputChange({ name: 'qualityProfileId', value: parseInt(value) });
|
||||
this.props.onInputChange({ name: 'qualityProfileId', value: Number.parseInt(value) });
|
||||
};
|
||||
|
||||
onAddMoviePress = () => {
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ function createMapStateToProps() {
|
|||
items
|
||||
} = rootFolders;
|
||||
|
||||
const rootFolderId = parseInt(match.params.rootFolderId);
|
||||
const rootFolderId = Number.parseInt(match.params.rootFolderId);
|
||||
|
||||
const result = {
|
||||
rootFolderId,
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ interface AppProps {
|
|||
|
||||
const queryClient = new QueryClient();
|
||||
|
||||
function App({ store, history }: AppProps) {
|
||||
function App({ store, history }: Readonly<AppProps>) {
|
||||
return (
|
||||
<DocumentTitle title={window.Radarr.instanceName}>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ interface AppUpdatedModalProps {
|
|||
onModalClose: (...args: unknown[]) => unknown;
|
||||
}
|
||||
|
||||
function AppUpdatedModal(props: AppUpdatedModalProps) {
|
||||
function AppUpdatedModal(props: Readonly<AppUpdatedModalProps>) {
|
||||
const { isOpen, onModalClose } = props;
|
||||
|
||||
const handleModalClose = useCallback(() => {
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ interface AppUpdatedModalContentProps {
|
|||
onModalClose: () => void;
|
||||
}
|
||||
|
||||
function AppUpdatedModalContent(props: AppUpdatedModalContentProps) {
|
||||
function AppUpdatedModalContent(props: Readonly<AppUpdatedModalContentProps>) {
|
||||
const dispatch = useDispatch();
|
||||
const { version, prevVersion } = useSelector((state: AppState) => state.app);
|
||||
const { isPopulated, error, items } = useSelector(
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ interface ConnectionLostModalProps {
|
|||
isOpen: boolean;
|
||||
}
|
||||
|
||||
function ConnectionLostModal(props: ConnectionLostModalProps) {
|
||||
function ConnectionLostModal(props: Readonly<ConnectionLostModalProps>) {
|
||||
const { isOpen } = props;
|
||||
|
||||
const handleModalClose = useCallback(() => {
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ function AgendaEvent({
|
|||
hasFile,
|
||||
grabbed,
|
||||
showDate,
|
||||
}: AgendaEventProps) {
|
||||
}: Readonly<AgendaEventProps>) {
|
||||
const movieFile = useMovieFile(movieFileId);
|
||||
const queueItem = useSelector(createQueueItemSelectorForHook(id));
|
||||
const { longDateFormat, enableColorImpairedMode } = useSelector(
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ interface CalendarFilterModalProps {
|
|||
isOpen: boolean;
|
||||
}
|
||||
|
||||
export default function CalendarFilterModal(props: CalendarFilterModalProps) {
|
||||
export default function CalendarFilterModal(props: Readonly<CalendarFilterModalProps>) {
|
||||
const sectionItems = useSelector(createCalendarSelector());
|
||||
const filterBuilderProps = useSelector(createFilterBuilderPropsSelector());
|
||||
const customFilterType = 'calendar';
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ interface CalendarDayProps {
|
|||
isTodaysDate: boolean;
|
||||
}
|
||||
|
||||
function CalendarDay({ date, isTodaysDate }: CalendarDayProps) {
|
||||
function CalendarDay({ date, isTodaysDate }: Readonly<CalendarDayProps>) {
|
||||
const { time, view } = useSelector((state: AppState) => state.calendar);
|
||||
const events = useSelector(createCalendarEventsConnector(date));
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ interface DayOfWeekProps {
|
|||
showRelativeDates: boolean;
|
||||
}
|
||||
|
||||
function DayOfWeek(props: DayOfWeekProps) {
|
||||
function DayOfWeek(props: Readonly<DayOfWeekProps>) {
|
||||
const {
|
||||
date,
|
||||
view,
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ function CalendarEvent({
|
|||
monitored: isMonitored,
|
||||
hasFile,
|
||||
grabbed,
|
||||
}: CalendarEventProps) {
|
||||
}: Readonly<CalendarEventProps>) {
|
||||
const movieFile = useMovieFile(movieFileId);
|
||||
const queueItem = useSelector(createQueueItemSelectorForHook(id));
|
||||
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ function CalendarEventQueueDetails({
|
|||
trackedDownloadStatus,
|
||||
statusMessages,
|
||||
errorMessage,
|
||||
}: CalendarEventQueueDetailsProps) {
|
||||
}: Readonly<CalendarEventQueueDetailsProps>) {
|
||||
const progress = size ? 100 - (sizeleft / size) * 100 : 0;
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ function CalendarHeaderViewButton({
|
|||
selectedView,
|
||||
onPress,
|
||||
...otherProps
|
||||
}: CalendarHeaderViewButtonProps) {
|
||||
}: Readonly<CalendarHeaderViewButtonProps>) {
|
||||
const handlePress = useCallback(() => {
|
||||
onPress(view);
|
||||
}, [view, onPress]);
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ interface LegendIconItemProps extends Pick<IconProps, 'kind'> {
|
|||
tooltip: string;
|
||||
}
|
||||
|
||||
function LegendIconItem(props: LegendIconItemProps) {
|
||||
function LegendIconItem(props: Readonly<LegendIconItemProps>) {
|
||||
const { name, fullColorEvents, icon, kind, tooltip } = props;
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ function LegendItem({
|
|||
isAgendaView,
|
||||
fullColorEvents,
|
||||
colorImpairedMode,
|
||||
}: LegendItemProps) {
|
||||
}: Readonly<LegendItemProps>) {
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ interface CalendarOptionsModalProps {
|
|||
function CalendarOptionsModal({
|
||||
isOpen,
|
||||
onModalClose,
|
||||
}: CalendarOptionsModalProps) {
|
||||
}: Readonly<CalendarOptionsModalProps>) {
|
||||
return (
|
||||
<Modal isOpen={isOpen} onModalClose={onModalClose}>
|
||||
<CalendarOptionsModalContent onModalClose={onModalClose} />
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ interface CalendarOptionsModalContentProps {
|
|||
|
||||
function CalendarOptionsModalContent({
|
||||
onModalClose,
|
||||
}: CalendarOptionsModalContentProps) {
|
||||
}: Readonly<CalendarOptionsModalContentProps>) {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ interface CalendarLinkModalProps {
|
|||
onModalClose: () => void;
|
||||
}
|
||||
|
||||
function CalendarLinkModal(props: CalendarLinkModalProps) {
|
||||
function CalendarLinkModal(props: Readonly<CalendarLinkModalProps>) {
|
||||
const { isOpen, onModalClose } = props;
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ interface CalendarLinkModalContentProps {
|
|||
|
||||
function CalendarLinkModalContent({
|
||||
onModalClose,
|
||||
}: CalendarLinkModalContentProps) {
|
||||
}: Readonly<CalendarLinkModalContentProps>) {
|
||||
const [state, setState] = useState<{
|
||||
unmonitored: boolean;
|
||||
asAllDay: boolean;
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ function AddNewMovieCollectionMovieModal({
|
|||
isOpen,
|
||||
onModalClose,
|
||||
...otherProps
|
||||
}: AddNewCollectionMovieModalProps) {
|
||||
}: Readonly<AddNewCollectionMovieModalProps>) {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const wasOpen = usePrevious(isOpen);
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ function AddNewMovieCollectionMovieModalContent({
|
|||
collectionId,
|
||||
folder,
|
||||
onModalClose,
|
||||
}: AddNewMovieCollectionMovieModalContentProps) {
|
||||
}: Readonly<AddNewMovieCollectionMovieModalContentProps>) {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const collection = useMovieCollection(collectionId)!;
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ class Collection extends Component {
|
|||
const characters = _.reduce(items, (acc, item) => {
|
||||
let char = item.sortTitle.charAt(0);
|
||||
|
||||
if (!isNaN(char)) {
|
||||
if (!Number.isNaN(char)) {
|
||||
char = '#';
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ function CollectionFooter({
|
|||
isSaving,
|
||||
saveError,
|
||||
onUpdateSelectedPress,
|
||||
}: CollectionFooterProps) {
|
||||
}: Readonly<CollectionFooterProps>) {
|
||||
const [monitored, setMonitored] = useState(NO_CHANGE);
|
||||
const [monitor, setMonitor] = useState(NO_CHANGE);
|
||||
const [qualityProfileId, setQualityProfileId] = useState<string | number>(
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ function CollectionFooterLabel({
|
|||
className = styles.label,
|
||||
label,
|
||||
isSaving,
|
||||
}: CollectionFooterLabelProps) {
|
||||
}: Readonly<CollectionFooterLabelProps>) {
|
||||
return (
|
||||
<div className={className}>
|
||||
{label}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ function EditMovieCollectionModal({
|
|||
isOpen,
|
||||
onModalClose,
|
||||
...otherProps
|
||||
}: EditMovieCollectionModalProps) {
|
||||
}: Readonly<EditMovieCollectionModalProps>) {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const handleModalClose = useCallback(() => {
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ export interface EditMovieCollectionModalContentProps {
|
|||
function EditMovieCollectionModalContent({
|
||||
collectionId,
|
||||
onModalClose,
|
||||
}: EditMovieCollectionModalContentProps) {
|
||||
}: Readonly<EditMovieCollectionModalContentProps>) {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const {
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ function MovieCollectionFilterMenu({
|
|||
customFilters,
|
||||
isDisabled,
|
||||
onFilterSelect,
|
||||
}: MovieCollectionFilterMenuProps) {
|
||||
}: Readonly<MovieCollectionFilterMenuProps>) {
|
||||
return (
|
||||
<FilterMenu
|
||||
alignMenu="right"
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ function MovieCollectionSortMenu({
|
|||
sortDirection,
|
||||
isDisabled,
|
||||
onSortSelect,
|
||||
}: MovieCollectionSortMenuProps) {
|
||||
}: Readonly<MovieCollectionSortMenuProps>) {
|
||||
return (
|
||||
<SortMenu isDisabled={isDisabled} alignMenu={align.RIGHT}>
|
||||
<MenuContent>
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ interface NoMovieCollectionsProps {
|
|||
totalItems: number;
|
||||
}
|
||||
|
||||
function NoMovieCollections({ totalItems }: NoMovieCollectionsProps) {
|
||||
function NoMovieCollections({ totalItems }: Readonly<NoMovieCollectionsProps>) {
|
||||
if (totalItems > 0) {
|
||||
return (
|
||||
<div>
|
||||
|
|
|
|||
|
|
@ -23,10 +23,10 @@ import styles from './CollectionOverview.css';
|
|||
import 'swiper/css';
|
||||
import 'swiper/css/navigation';
|
||||
|
||||
const columnPadding = parseInt(dimensions.movieIndexColumnPadding);
|
||||
const columnPaddingSmallScreen = parseInt(dimensions.movieIndexColumnPaddingSmallScreen);
|
||||
const defaultFontSize = parseInt(fonts.defaultFontSize);
|
||||
const lineHeight = parseFloat(fonts.lineHeight);
|
||||
const columnPadding = Number.parseInt(dimensions.movieIndexColumnPadding);
|
||||
const columnPaddingSmallScreen = Number.parseInt(dimensions.movieIndexColumnPaddingSmallScreen);
|
||||
const defaultFontSize = Number.parseInt(fonts.defaultFontSize);
|
||||
const lineHeight = Number.parseFloat(fonts.lineHeight);
|
||||
|
||||
// Hardcoded height beased on line-height of 32 + bottom margin of 10. 19 + 5 for List Row
|
||||
// Less side-effecty than using react-measure.
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ import CollectionOverviewConnector from './CollectionOverviewConnector';
|
|||
import styles from './CollectionOverviews.css';
|
||||
|
||||
// Poster container dimensions
|
||||
const columnPadding = parseInt(dimensions.movieIndexColumnPadding);
|
||||
const columnPaddingSmallScreen = parseInt(dimensions.movieIndexColumnPaddingSmallScreen);
|
||||
const columnPadding = Number.parseInt(dimensions.movieIndexColumnPadding);
|
||||
const columnPaddingSmallScreen = Number.parseInt(dimensions.movieIndexColumnPaddingSmallScreen);
|
||||
|
||||
function calculatePosterWidth(posterSize, isSmallScreen) {
|
||||
const maximumPosterWidth = isSmallScreen ? 152 : 162;
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ interface AlertProps {
|
|||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
function Alert(props: AlertProps) {
|
||||
function Alert(props: Readonly<AlertProps>) {
|
||||
const { className = styles.alert, kind = 'info', children } = props;
|
||||
|
||||
return <div className={classNames(className, styles[kind])}>{children}</div>;
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ interface CardProps extends Pick<LinkProps, 'onPress'> {
|
|||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
function Card(props: CardProps) {
|
||||
function Card(props: Readonly<CardProps>) {
|
||||
const {
|
||||
className = styles.card,
|
||||
overlayClassName = styles.overlay,
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ function CircularProgressBar({
|
|||
strokeColor = '#ffc230',
|
||||
showProgressText = false,
|
||||
progress,
|
||||
}: CircularProgressBarProps) {
|
||||
}: Readonly<CircularProgressBarProps>) {
|
||||
const [currentProgress, setCurrentProgress] = useState(0);
|
||||
const raf = React.useRef<number>(0);
|
||||
const center = size / 2;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ interface DescriptionListProps {
|
|||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
function DescriptionList(props: DescriptionListProps) {
|
||||
function DescriptionList(props: Readonly<DescriptionListProps>) {
|
||||
const { className = styles.descriptionList, children } = props;
|
||||
|
||||
return <dl className={className}>{children}</dl>;
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ interface DescriptionListItemProps {
|
|||
data?: DescriptionListItemDescriptionProps['children'];
|
||||
}
|
||||
|
||||
function DescriptionListItem(props: DescriptionListItemProps) {
|
||||
function DescriptionListItem(props: Readonly<DescriptionListItemProps>) {
|
||||
const { className, titleClassName, descriptionClassName, title, data } =
|
||||
props;
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ export interface DescriptionListItemTitleProps {
|
|||
children?: ReactNode;
|
||||
}
|
||||
|
||||
function DescriptionListItemTitle(props: DescriptionListItemTitleProps) {
|
||||
function DescriptionListItemTitle(props: Readonly<DescriptionListItemTitleProps>) {
|
||||
const { className = styles.title, children } = props;
|
||||
|
||||
return <dt className={className}>{children}</dt>;
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ function DragPreviewLayer({
|
|||
className = styles.dragLayer,
|
||||
children,
|
||||
...otherProps
|
||||
}: DragPreviewLayerProps) {
|
||||
}: Readonly<DragPreviewLayerProps>) {
|
||||
return (
|
||||
<div className={className} {...otherProps}>
|
||||
{children}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ interface ErrorBoundaryState {
|
|||
|
||||
// Class component until componentDidCatch is supported in functional components
|
||||
class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
|
||||
constructor(props: ErrorBoundaryProps) {
|
||||
constructor(props: Readonly<ErrorBoundaryProps>) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ export interface ErrorBoundaryErrorProps {
|
|||
};
|
||||
}
|
||||
|
||||
function ErrorBoundaryError(props: ErrorBoundaryErrorProps) {
|
||||
function ErrorBoundaryError(props: Readonly<ErrorBoundaryErrorProps>) {
|
||||
const {
|
||||
className = styles.container,
|
||||
messageClassName = styles.message,
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ interface FieldSetProps {
|
|||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
function FieldSet({ size = sizes.MEDIUM, legend, children }: FieldSetProps) {
|
||||
function FieldSet({ size = sizes.MEDIUM, legend, children }: Readonly<FieldSetProps>) {
|
||||
return (
|
||||
<fieldset className={styles.fieldSet}>
|
||||
<legend
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ interface FileBrowserModalProps extends FileBrowserModalContentProps {
|
|||
onModalClose: () => void;
|
||||
}
|
||||
|
||||
function FileBrowserModal(props: FileBrowserModalProps) {
|
||||
function FileBrowserModal(props: Readonly<FileBrowserModalProps>) {
|
||||
const { isOpen, onModalClose, ...otherProps } = props;
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ export interface FileBrowserModalContentProps {
|
|||
onModalClose: () => void;
|
||||
}
|
||||
|
||||
function FileBrowserModalContent(props: FileBrowserModalContentProps) {
|
||||
function FileBrowserModalContent(props: Readonly<FileBrowserModalContentProps>) {
|
||||
const { name, value, includeFiles = true, onChange, onModalClose } = props;
|
||||
|
||||
const dispatch = useDispatch();
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ interface FileBrowserRowProps {
|
|||
onPress: (path: string) => void;
|
||||
}
|
||||
|
||||
function FileBrowserRow(props: FileBrowserRowProps) {
|
||||
function FileBrowserRow(props: Readonly<FileBrowserRowProps>) {
|
||||
const { type, name, path, onPress } = props;
|
||||
|
||||
const handlePress = useCallback(() => {
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ function getValue(input, selectedFilterBuilderProp) {
|
|||
case 'tib':
|
||||
return convertToBytes(value, 4, true);
|
||||
default:
|
||||
return parseInt(value);
|
||||
return Number.parseInt(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import createLanguagesSelector from 'Store/Selectors/createLanguagesSelector';
|
|||
import FilterBuilderRowValue from './FilterBuilderRowValue';
|
||||
import FilterBuilderRowValueProps from './FilterBuilderRowValueProps';
|
||||
|
||||
function LanguageFilterBuilderRowValue(props: FilterBuilderRowValueProps) {
|
||||
function LanguageFilterBuilderRowValue(props: Readonly<FilterBuilderRowValueProps>) {
|
||||
const { items } = useSelector(createLanguagesSelector());
|
||||
|
||||
return <FilterBuilderRowValue {...props} tagList={items} />;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import sortByProp from 'Utilities/Array/sortByProp';
|
|||
import FilterBuilderRowValue from './FilterBuilderRowValue';
|
||||
import FilterBuilderRowValueProps from './FilterBuilderRowValueProps';
|
||||
|
||||
function MovieFilterBuilderRowValue(props: FilterBuilderRowValueProps) {
|
||||
function MovieFilterBuilderRowValue(props: Readonly<FilterBuilderRowValueProps>) {
|
||||
const allMovies: Movie[] = useSelector(createAllMoviesSelector());
|
||||
|
||||
const tagList = allMovies
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ const statusTagList = [
|
|||
},
|
||||
];
|
||||
|
||||
function QueueStatusFilterBuilderRowValue(props: FilterBuilderRowValueProps) {
|
||||
function QueueStatusFilterBuilderRowValue(props: Readonly<FilterBuilderRowValueProps>) {
|
||||
return <FilterBuilderRowValue {...props} tagList={statusTagList} />;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ function AutoCompleteInput({
|
|||
values,
|
||||
onChange,
|
||||
...otherProps
|
||||
}: AutoCompleteInputProps) {
|
||||
}: Readonly<AutoCompleteInputProps>) {
|
||||
const [suggestions, setSuggestions] = useState<string[]>([]);
|
||||
|
||||
const getSuggestionValue = useCallback((item: string) => {
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ function CaptchaInput({
|
|||
siteKey,
|
||||
secretToken,
|
||||
onChange,
|
||||
}: CaptchaInputProps) {
|
||||
}: Readonly<CaptchaInputProps>) {
|
||||
const { token } = useSelector((state: AppState) => state.captcha);
|
||||
const dispatch = useDispatch();
|
||||
const previousToken = usePrevious(token);
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ export interface CheckInputProps {
|
|||
onChange: (changes: CheckInputChanged) => void;
|
||||
}
|
||||
|
||||
function CheckInput(props: CheckInputProps) {
|
||||
function CheckInput(props: Readonly<CheckInputProps>) {
|
||||
const {
|
||||
className = styles.input,
|
||||
containerClassName = styles.container,
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ function Form({
|
|||
children,
|
||||
validationErrors = [],
|
||||
validationWarnings = [],
|
||||
}: FormProps) {
|
||||
}: Readonly<FormProps>) {
|
||||
return (
|
||||
<div id={id}>
|
||||
{validationErrors.length || validationWarnings.length ? (
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ interface FormGroupProps extends ComponentPropsWithoutRef<'div'> {
|
|||
isAdvanced?: boolean;
|
||||
}
|
||||
|
||||
function FormGroup(props: FormGroupProps) {
|
||||
function FormGroup(props: Readonly<FormGroupProps>) {
|
||||
const {
|
||||
className = styles.group,
|
||||
children,
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ function FormInputButton({
|
|||
isSpinning = false,
|
||||
kind = kinds.PRIMARY,
|
||||
...otherProps
|
||||
}: FormInputButtonProps) {
|
||||
}: Readonly<FormInputButtonProps>) {
|
||||
if (canSpin) {
|
||||
return (
|
||||
<SpinnerButton
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ function FormInputHelpText({
|
|||
isError = false,
|
||||
isWarning = false,
|
||||
isCheckInput = false,
|
||||
}: FormInputHelpTextProps) {
|
||||
}: Readonly<FormInputHelpTextProps>) {
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ interface FormLabelProps {
|
|||
isAdvanced?: boolean;
|
||||
}
|
||||
|
||||
function FormLabel(props: FormLabelProps) {
|
||||
function FormLabel(props: Readonly<FormLabelProps>) {
|
||||
const {
|
||||
children,
|
||||
className = styles.label,
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ function KeyValueListInput({
|
|||
keyPlaceholder,
|
||||
valuePlaceholder,
|
||||
onChange,
|
||||
}: KeyValueListInputProps): JSX.Element {
|
||||
}: Readonly<KeyValueListInputProps>): JSX.Element {
|
||||
const [isFocused, setIsFocused] = useState(false);
|
||||
|
||||
const handleItemChange = useCallback(
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ function KeyValueListInputItem({
|
|||
onRemove,
|
||||
onFocus,
|
||||
onBlur,
|
||||
}: KeyValueListInputItemProps): JSX.Element {
|
||||
}: Readonly<KeyValueListInputItemProps>): JSX.Element {
|
||||
const handleKeyChange = useCallback(
|
||||
({ value: keyValue }: { value: string }) => {
|
||||
onChange(index, { key: keyValue, value });
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ function parseValue(
|
|||
return null;
|
||||
}
|
||||
|
||||
let newValue = isFloat ? parseFloat(value) : parseInt(value);
|
||||
let newValue = isFloat ? Number.parseFloat(value) : Number.parseInt(value);
|
||||
|
||||
if (min != null && newValue != null && newValue < min) {
|
||||
newValue = min;
|
||||
|
|
@ -41,7 +41,7 @@ function NumberInput({
|
|||
max,
|
||||
onChange,
|
||||
...otherProps
|
||||
}: NumberInputProps) {
|
||||
}: Readonly<NumberInputProps>) {
|
||||
const [value, setValue] = useState(
|
||||
inputValue == null ? '' : inputValue.toString()
|
||||
);
|
||||
|
|
@ -82,8 +82,7 @@ function NumberInput({
|
|||
|
||||
useEffect(() => {
|
||||
if (
|
||||
// @ts-expect-error inputValue may be null
|
||||
!isNaN(inputValue) &&
|
||||
!Number.isNaN(inputValue) &&
|
||||
inputValue !== previousValue &&
|
||||
!isFocused.current
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ function OAuthInput({
|
|||
providerData,
|
||||
section,
|
||||
onChange,
|
||||
}: OAuthInputProps) {
|
||||
}: Readonly<OAuthInputProps>) {
|
||||
const dispatch = useDispatch();
|
||||
const { authorizing, error, result } = useSelector(
|
||||
(state: AppState) => state.oAuth
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ function onCopy(e: SyntheticEvent) {
|
|||
e.nativeEvent.stopImmediatePropagation();
|
||||
}
|
||||
|
||||
function PasswordInput(props: TextInputProps) {
|
||||
function PasswordInput(props: Readonly<TextInputProps>) {
|
||||
return <TextInput {...props} type="password" onCopy={onCopy} />;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ function createPathsSelector() {
|
|||
);
|
||||
}
|
||||
|
||||
function PathInput(props: PathInputProps) {
|
||||
function PathInput(props: Readonly<PathInputProps>) {
|
||||
const { includeFiles } = props;
|
||||
|
||||
const dispatch = useDispatch();
|
||||
|
|
@ -91,7 +91,7 @@ function PathInput(props: PathInputProps) {
|
|||
|
||||
export default PathInput;
|
||||
|
||||
export function PathInputInternal(props: PathInputInternalProps) {
|
||||
export function PathInputInternal(props: Readonly<PathInputInternalProps>) {
|
||||
const {
|
||||
className = styles.inputWrapper,
|
||||
name,
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ const movieAvailabilityOptions: IMovieAvailabilityOption[] = [
|
|||
},
|
||||
];
|
||||
|
||||
function AvailabilitySelectInput(props: AvailabilitySelectInputProps) {
|
||||
function AvailabilitySelectInput(props: Readonly<AvailabilitySelectInputProps>) {
|
||||
const {
|
||||
includeNoChange = false,
|
||||
includeNoChangeDisabled = true,
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ function DownloadClientSelectInput({
|
|||
includeAny = false,
|
||||
protocol = 'torrent',
|
||||
...otherProps
|
||||
}: DownloadClientSelectInputProps) {
|
||||
}: Readonly<DownloadClientSelectInputProps>) {
|
||||
const dispatch = useDispatch();
|
||||
const { isFetching, isPopulated, values } = useSelector(
|
||||
createDownloadClientsSelector(includeAny, protocol)
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ function EnhancedSelectInputOption({
|
|||
isMobile,
|
||||
children,
|
||||
onSelect,
|
||||
}: EnhancedSelectInputOptionProps) {
|
||||
}: Readonly<EnhancedSelectInputOptionProps>) {
|
||||
const handlePress = useCallback(
|
||||
(event: SyntheticEvent) => {
|
||||
event.preventDefault();
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ function EnhancedSelectInputSelectedValue({
|
|||
className = styles.selectedValue,
|
||||
children,
|
||||
isDisabled = false,
|
||||
}: EnhancedSelectInputSelectedValueProps) {
|
||||
}: Readonly<EnhancedSelectInputSelectedValueProps>) {
|
||||
return (
|
||||
<div className={classNames(className, isDisabled && styles.isDisabled)}>
|
||||
{children}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ interface HintedSelectInputOptionProps
|
|||
isSelected?: boolean;
|
||||
}
|
||||
|
||||
function HintedSelectInputOption(props: HintedSelectInputOptionProps) {
|
||||
function HintedSelectInputOption(props: Readonly<HintedSelectInputOptionProps>) {
|
||||
const {
|
||||
id,
|
||||
value,
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ function IndexerFlagsSelectInput({
|
|||
indexerFlags,
|
||||
onChange,
|
||||
...otherProps
|
||||
}: IndexerFlagsSelectInputProps) {
|
||||
}: Readonly<IndexerFlagsSelectInputProps>) {
|
||||
const { value, values } = useSelector(selectIndexerFlagsValues(indexerFlags));
|
||||
|
||||
const handleChange = useCallback(
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ function IndexerSelectInput({
|
|||
value,
|
||||
includeAny = false,
|
||||
onChange,
|
||||
}: IndexerSelectInputProps) {
|
||||
}: Readonly<IndexerSelectInputProps>) {
|
||||
const dispatch = useDispatch();
|
||||
const { isFetching, isPopulated, values } = useSelector(
|
||||
createIndexersSelector(includeAny)
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ function LanguageSelectInput({
|
|||
values,
|
||||
onChange,
|
||||
...otherProps
|
||||
}: LanguageSelectInputProps) {
|
||||
}: Readonly<LanguageSelectInputProps>) {
|
||||
const mappedValues = useMemo(() => {
|
||||
const minId = values.reduce(
|
||||
(min: number, v) => (v.key < 1 ? v.key : min),
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ export interface MonitorMoviesSelectInputProps
|
|||
includeMixed?: boolean;
|
||||
}
|
||||
|
||||
function MonitorMoviesSelectInput(props: MonitorMoviesSelectInputProps) {
|
||||
function MonitorMoviesSelectInput(props: Readonly<MonitorMoviesSelectInputProps>) {
|
||||
const {
|
||||
includeNoChange = false,
|
||||
includeMixed = false,
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ function ProviderOptionSelectInput({
|
|||
providerData,
|
||||
selectOptionsProviderAction,
|
||||
...otherProps
|
||||
}: ProviderOptionSelectInputProps) {
|
||||
}: Readonly<ProviderOptionSelectInputProps>) {
|
||||
const dispatch = useDispatch();
|
||||
const [isRefetchRequired, setIsRefetchRequired] = useState(false);
|
||||
const previousProviderData = usePrevious(providerData);
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ function QualityProfileSelectInput({
|
|||
includeMixed = false,
|
||||
onChange,
|
||||
...otherProps
|
||||
}: QualityProfileSelectInputProps) {
|
||||
}: Readonly<QualityProfileSelectInputProps>) {
|
||||
const values = useSelector(
|
||||
createQualityProfilesSelector(
|
||||
includeNoChange,
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ function RootFolderSelectInput({
|
|||
includeNoChangeDisabled = true,
|
||||
onChange,
|
||||
...otherProps
|
||||
}: RootFolderSelectInputProps) {
|
||||
}: Readonly<RootFolderSelectInputProps>) {
|
||||
const dispatch = useDispatch();
|
||||
const { values, isSaving, saveError } = useSelector(
|
||||
createRootFolderOptionsSelector(
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ function RootFolderSelectInputOption({
|
|||
isMobile,
|
||||
isWindows,
|
||||
...otherProps
|
||||
}: RootFolderSelectInputOptionProps) {
|
||||
}: Readonly<RootFolderSelectInputOptionProps>) {
|
||||
const slashCharacter = isWindows ? '\\' : '/';
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ function RootFolderSelectInputSelectedValue({
|
|||
includeFreeSpace = true,
|
||||
isWindows,
|
||||
...otherProps
|
||||
}: RootFolderSelectInputSelectedValueProps) {
|
||||
}: Readonly<RootFolderSelectInputSelectedValueProps>) {
|
||||
const slashCharacter = isWindows ? '\\' : '/';
|
||||
const { value, freeSpace, isMissing } =
|
||||
values.find((v) => v.key === selectedValue) ||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue