Feature/manga migration (#536)

* Add "migration" tab to "Browse" screen

* Add missing useEffect cleanup for navbar title and actions

* Make "SourceGridLayout" reusable

* Add migration tab to "Browse"

* Add migration logic
This commit is contained in:
schroda
2024-01-26 20:50:51 +01:00
committed by GitHub
parent 5224ad1391
commit e0c5e0521d
39 changed files with 1329 additions and 365 deletions

69
src/screens/Migration.tsx Normal file
View File

@@ -0,0 +1,69 @@
/*
* Copyright (C) Contributors to the Suwayomi project
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
import { useTranslation } from 'react-i18next';
import { useMemo } from 'react';
import List from '@mui/material/List';
import { requestManager } from '@/lib/requests/RequestManager.ts';
import { LoadingPlaceholder } from '@/components/util/LoadingPlaceholder.tsx';
import { EmptyView } from '@/components/util/EmptyView.tsx';
import { GetMigratableSourcesQuery } from '@/lib/graphql/generated/graphql.ts';
import { MigrationCard, TMigratableSource } from '@/components/MigrationCard.tsx';
import { StyledGroupItemWrapper } from '@/components/virtuoso/StyledGroupItemWrapper.tsx';
type TMigratableSourcesResult = GetMigratableSourcesQuery['mangas']['nodes'];
type TMigratableSources = Record<string, TMigratableSource>;
const getMigratableSources = (mangas?: TMigratableSourcesResult): TMigratableSources => {
if (!mangas) {
return {};
}
const uniqueSources: TMigratableSources = {};
mangas.forEach(({ sourceId, source }) => {
const uniqueSource = uniqueSources[sourceId] ?? {
...{ id: sourceId, name: sourceId, lang: 'unknown', iconUrl: null, mangaCount: 0, ...source },
};
uniqueSources[sourceId] = {
...uniqueSource,
mangaCount: uniqueSource.mangaCount + 1,
};
});
return uniqueSources;
};
export const Migration = () => {
const { t } = useTranslation();
const { data, loading, error } = requestManager.useGetMigratableSources();
const migratableSources = useMemo(() => getMigratableSources(data?.mangas.nodes), [data?.mangas.nodes]);
if (loading) {
return <LoadingPlaceholder />;
}
if (error) {
return <EmptyView message={t('global.error.label.failed_to_load_data')} messageExtra={error.message} />;
}
return (
<List>
{Object.values(migratableSources).map((migratableSource, index) => (
<StyledGroupItemWrapper
key={migratableSource.id}
isLastItem={index === Object.values(migratableSources).length - 1}
>
<MigrationCard {...migratableSource} />
</StyledGroupItemWrapper>
))}
</List>
);
};