feat: add Source filter to library filtering system (#1131)
* feat: add Source filter to library filtering system Add a new Source filter section to the library options panel that allows users to filter their library manga by source (e.g. MangaDex, MangaSee). - Add hasSource to LibraryOptions type and category metadata - Add source filtering logic in useGetVisibleLibraryMangas - Add Source section with three-state checkboxes in filter UI - Show loading spinner while source list loads - Include source filter in active filter indicator Closes #1057 * refactor: address review feedback for source filter - Remove skip option, let query always run - Use uniqBy from lodash/fp for deduplication - Remove loading spinner (data available quickly) - Wrap source section in length check * docs: add source filter to changelog --------- Co-authored-by: Copilot <noreply@github.com>
This commit is contained in:
@@ -11,6 +11,8 @@ import FormLabel from '@mui/material/FormLabel';
|
||||
import RadioGroup from '@mui/material/RadioGroup';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import { useMemo } from 'react';
|
||||
import uniqBy from 'lodash/fp/uniqBy';
|
||||
import { CheckboxInput } from '@/base/components/inputs/CheckboxInput.tsx';
|
||||
import { RadioInput } from '@/base/components/inputs/RadioInput.tsx';
|
||||
import { SortRadioInput } from '@/base/components/inputs/SortRadioInput.tsx';
|
||||
@@ -65,6 +67,16 @@ export const LibraryOptionsPanel = ({
|
||||
const trackerList = requestManager.useGetTrackerList<GetTrackersSettingsQuery>(GET_TRACKERS_SETTINGS);
|
||||
const loggedInTrackers = Trackers.getLoggedIn(trackerList.data?.trackers.nodes ?? STABLE_EMPTY_ARRAY);
|
||||
|
||||
const migratableSourcesResult = requestManager.useGetMigratableSources();
|
||||
const librarySources = useMemo(() => {
|
||||
const sources = migratableSourcesResult.data?.mangas.nodes
|
||||
.map(({ source }) => source)
|
||||
.filter((source) => source != null);
|
||||
const uniqueSources = uniqBy('id', sources);
|
||||
|
||||
return uniqueSources.toSorted((a, b) => a.displayName.localeCompare(b.displayName));
|
||||
}, [migratableSourcesResult.data?.mangas.nodes]);
|
||||
|
||||
const categoryLibraryOptions = useGetCategoryMetadata(category);
|
||||
const updateCategoryLibraryOptions = createUpdateCategoryMetadata(category, (e) =>
|
||||
makeToast(t`Failed to save changes`, 'error', getErrorMessage(e)),
|
||||
@@ -140,6 +152,24 @@ export const LibraryOptionsPanel = ({
|
||||
}
|
||||
/>
|
||||
))}
|
||||
{librarySources.length > 0 && (
|
||||
<>
|
||||
<FormLabel sx={{ mt: 2 }}>{t`Source`}</FormLabel>
|
||||
{librarySources.map((source) => (
|
||||
<ThreeStateCheckboxInput
|
||||
key={source.id}
|
||||
label={source.displayName}
|
||||
checked={categoryLibraryOptions.hasSource[source.id]}
|
||||
onChange={(checked) =>
|
||||
updateCategoryLibraryOptions('hasSource', {
|
||||
...categoryLibraryOptions.hasSource,
|
||||
[source.id]: checked,
|
||||
})
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user