mirror of
https://github.com/antebudimir/feishin.git
synced 2025-12-31 18:13:31 +00:00
warn if a value in select no longer exists
This commit is contained in:
parent
f068d6e4b8
commit
cf74625bfc
6 changed files with 93 additions and 11 deletions
|
|
@ -160,6 +160,7 @@
|
|||
"audioDeviceFetchError": "an error occurred when trying to get audio devices",
|
||||
"authenticationFailed": "authentication failed",
|
||||
"badAlbum": "you are seeing this page because this song is not part of an album. you are most likely seeing this issue if you have a song at the top level of your music folder. jellyfin only groups tracks if they are in a folder.",
|
||||
"badValue": "invalid option \"{{value}}\". this value no longer exists",
|
||||
"credentialsRequired": "credentials required",
|
||||
"endpointNotImplementedError": "endpoint {{endpoint}} is not implemented for {{serverType}}",
|
||||
"genericError": "an error occurred",
|
||||
|
|
|
|||
78
src/renderer/components/select-with-invalid-data/index.tsx
Normal file
78
src/renderer/components/select-with-invalid-data/index.tsx
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
import { MultiSelect, MultiSelectProps, Select, SelectProps } from '/@/renderer/components/select';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const SelectWithInvalidData = ({ data, defaultValue, ...props }: SelectProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [fullData, hasError] = useMemo(() => {
|
||||
if (typeof defaultValue === 'string') {
|
||||
const missingField =
|
||||
data.find((item) =>
|
||||
typeof item === 'string' ? item === defaultValue : item.value === defaultValue,
|
||||
) === undefined;
|
||||
|
||||
if (missingField) {
|
||||
return [data.concat(defaultValue), true];
|
||||
}
|
||||
}
|
||||
|
||||
return [data, false];
|
||||
}, [data, defaultValue]);
|
||||
|
||||
return (
|
||||
<Select
|
||||
data={fullData}
|
||||
defaultValue={defaultValue}
|
||||
error={
|
||||
hasError
|
||||
? t('error.badValue', { postProcess: 'sentenceCase', value: defaultValue })
|
||||
: undefined
|
||||
}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const MultiSelectWithInvalidData = ({ data, defaultValue, ...props }: MultiSelectProps) => {
|
||||
const { t } = useTranslation();
|
||||
const [fullData, missing] = useMemo(() => {
|
||||
if (defaultValue?.length) {
|
||||
const validValues = new Set<string>();
|
||||
for (const item of data) {
|
||||
if (typeof item === 'string') {
|
||||
validValues.add(item);
|
||||
} else {
|
||||
validValues.add(item.value);
|
||||
}
|
||||
}
|
||||
|
||||
const missingFields: string[] = [];
|
||||
|
||||
for (const value of defaultValue) {
|
||||
if (!validValues.has(value)) {
|
||||
missingFields.push(value);
|
||||
}
|
||||
}
|
||||
|
||||
if (missingFields.length > 0) {
|
||||
return [data.concat(missingFields), missingFields];
|
||||
}
|
||||
}
|
||||
|
||||
return [data, []];
|
||||
}, [data, defaultValue]);
|
||||
|
||||
return (
|
||||
<MultiSelect
|
||||
data={fullData}
|
||||
defaultValue={defaultValue}
|
||||
error={
|
||||
missing.length
|
||||
? t('error.badValue', { postProcess: 'sentenceCase', value: missing })
|
||||
: undefined
|
||||
}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
@ -5,7 +5,7 @@ import type {
|
|||
import { Select as MantineSelect, MultiSelect as MantineMultiSelect } from '@mantine/core';
|
||||
import styled from 'styled-components';
|
||||
|
||||
interface SelectProps extends MantineSelectProps {
|
||||
export interface SelectProps extends MantineSelectProps {
|
||||
maxWidth?: number | string;
|
||||
width?: number | string;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { ChangeEvent, useMemo, useState } from 'react';
|
||||
import { Divider, Group, Stack } from '@mantine/core';
|
||||
import { NumberInput, Switch, Text, Select, SpinnerIcon } from '/@/renderer/components';
|
||||
import { NumberInput, Switch, Text, SpinnerIcon } from '/@/renderer/components';
|
||||
import { AlbumListFilter, useListStoreActions, useListStoreByKey } from '/@/renderer/store';
|
||||
import debounce from 'lodash/debounce';
|
||||
import { useGenreList } from '/@/renderer/features/genres';
|
||||
|
|
@ -14,6 +14,7 @@ import {
|
|||
} from '/@/renderer/api/types';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTagList } from '/@/renderer/features/tag/queries/use-tag-list';
|
||||
import { SelectWithInvalidData } from '/@/renderer/components/select-with-invalid-data';
|
||||
|
||||
interface NavidromeAlbumFiltersProps {
|
||||
customFilters?: Partial<AlbumListFilter>;
|
||||
|
|
@ -251,7 +252,7 @@ export const NavidromeAlbumFilters = ({
|
|||
min={0}
|
||||
onChange={(e) => handleYearFilter(e)}
|
||||
/>
|
||||
<Select
|
||||
<SelectWithInvalidData
|
||||
clearable
|
||||
searchable
|
||||
data={genreList}
|
||||
|
|
@ -261,7 +262,7 @@ export const NavidromeAlbumFilters = ({
|
|||
/>
|
||||
</Group>
|
||||
<Group grow>
|
||||
<Select
|
||||
<SelectWithInvalidData
|
||||
clearable
|
||||
searchable
|
||||
data={selectableAlbumArtists}
|
||||
|
|
@ -281,7 +282,7 @@ export const NavidromeAlbumFilters = ({
|
|||
key={tag.name}
|
||||
grow
|
||||
>
|
||||
<Select
|
||||
<SelectWithInvalidData
|
||||
clearable
|
||||
searchable
|
||||
data={tag.options}
|
||||
|
|
|
|||
|
|
@ -2,11 +2,12 @@ import { ChangeEvent, useMemo } from 'react';
|
|||
import { Divider, Group, Stack } from '@mantine/core';
|
||||
import debounce from 'lodash/debounce';
|
||||
import { GenreListSort, LibraryItem, SongListQuery, SortOrder } from '/@/renderer/api/types';
|
||||
import { MultiSelect, NumberInput, Switch, Text } from '/@/renderer/components';
|
||||
import { NumberInput, Switch, Text } from '/@/renderer/components';
|
||||
import { SongListFilter, useListFilterByKey, useListStoreActions } from '/@/renderer/store';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTagList } from '/@/renderer/features/tag/queries/use-tag-list';
|
||||
import { useGenreList } from '/@/renderer/features/genres';
|
||||
import { MultiSelectWithInvalidData } from '/@/renderer/components/select-with-invalid-data';
|
||||
|
||||
interface JellyfinSongFiltersProps {
|
||||
customFilters?: Partial<SongListFilter>;
|
||||
|
|
@ -201,7 +202,7 @@ export const JellyfinSongFilters = ({
|
|||
</Group>
|
||||
{!isGenrePage && (
|
||||
<Group grow>
|
||||
<MultiSelect
|
||||
<MultiSelectWithInvalidData
|
||||
clearable
|
||||
searchable
|
||||
data={genreList}
|
||||
|
|
@ -214,7 +215,7 @@ export const JellyfinSongFilters = ({
|
|||
)}
|
||||
{tagsQuery.data?.boolTags?.length && (
|
||||
<Group grow>
|
||||
<MultiSelect
|
||||
<MultiSelectWithInvalidData
|
||||
clearable
|
||||
searchable
|
||||
data={tagsQuery.data.boolTags}
|
||||
|
|
|
|||
|
|
@ -2,11 +2,12 @@ import { ChangeEvent, useMemo } from 'react';
|
|||
import { Divider, Group, Stack } from '@mantine/core';
|
||||
import debounce from 'lodash/debounce';
|
||||
import { GenreListSort, LibraryItem, SongListQuery, SortOrder } from '/@/renderer/api/types';
|
||||
import { NumberInput, Select, Switch, Text } from '/@/renderer/components';
|
||||
import { NumberInput, Switch, Text } from '/@/renderer/components';
|
||||
import { useGenreList } from '/@/renderer/features/genres';
|
||||
import { SongListFilter, useListFilterByKey, useListStoreActions } from '/@/renderer/store';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTagList } from '/@/renderer/features/tag/queries/use-tag-list';
|
||||
import { SelectWithInvalidData } from '/@/renderer/components/select-with-invalid-data';
|
||||
|
||||
interface NavidromeSongFiltersProps {
|
||||
customFilters?: Partial<SongListFilter>;
|
||||
|
|
@ -149,7 +150,7 @@ export const NavidromeSongFilters = ({
|
|||
onChange={(e) => handleYearFilter(e)}
|
||||
/>
|
||||
{!isGenrePage && (
|
||||
<Select
|
||||
<SelectWithInvalidData
|
||||
clearable
|
||||
searchable
|
||||
data={genreList}
|
||||
|
|
@ -166,7 +167,7 @@ export const NavidromeSongFilters = ({
|
|||
key={tag.name}
|
||||
grow
|
||||
>
|
||||
<Select
|
||||
<SelectWithInvalidData
|
||||
clearable
|
||||
searchable
|
||||
data={tag.options}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue