Extract "Extensions" types, constants, utils into separate files
This commit is contained in:
@@ -21,7 +21,7 @@ import Tooltip from '@mui/material/Tooltip';
|
||||
import ListItem from '@mui/material/ListItem';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { cloneObject } from '@/util/cloneObject.tsx';
|
||||
import { translateExtensionLanguage } from '@/modules/extension/services/Extensions.ts';
|
||||
import { translateExtensionLanguage } from '@/modules/extension/Extensions.utils.ts';
|
||||
|
||||
function removeAll(firstList: any[], secondList: any[]) {
|
||||
secondList.forEach((item) => {
|
||||
|
||||
56
src/modules/extension/Extensions.constants.ts
Normal file
56
src/modules/extension/Extensions.constants.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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 {
|
||||
ExtensionAction,
|
||||
ExtensionGroupState,
|
||||
ExtensionState,
|
||||
InstalledState,
|
||||
InstalledStates,
|
||||
} from '@/modules/extension/Extensions.types.ts';
|
||||
import { TranslationKey } from '@/Base.types.ts';
|
||||
import { DefaultLanguage } from '@/modules/core/utils/Languages.ts';
|
||||
|
||||
export const EXTENSION_ACTION_TO_STATE_MAP: { [action in ExtensionAction]: ExtensionState } = {
|
||||
[ExtensionAction.UPDATE]: ExtensionState.UPDATING,
|
||||
[ExtensionAction.UNINSTALL]: ExtensionState.UNINSTALLING,
|
||||
[ExtensionAction.INSTALL]: ExtensionState.INSTALLING,
|
||||
} as const;
|
||||
|
||||
export const EXTENSION_ACTION_TO_NEXT_ACTION_MAP: { [action in ExtensionAction]: ExtensionAction } = {
|
||||
[ExtensionAction.UPDATE]: ExtensionAction.UNINSTALL,
|
||||
[ExtensionAction.UNINSTALL]: ExtensionAction.INSTALL,
|
||||
[ExtensionAction.INSTALL]: ExtensionAction.UNINSTALL,
|
||||
} as const;
|
||||
|
||||
export const INSTALLED_STATE_TO_TRANSLATION_KEY_MAP: { [installedState in InstalledStates]: TranslationKey } = {
|
||||
[InstalledState.UNINSTALL]: 'extension.action.label.uninstall',
|
||||
[InstalledState.INSTALL]: 'extension.action.label.install',
|
||||
[InstalledState.UPDATE]: 'extension.action.label.update',
|
||||
[InstalledState.OBSOLETE]: 'extension.state.label.obsolete',
|
||||
[InstalledState.UPDATING]: 'extension.state.label.updating',
|
||||
[InstalledState.UNINSTALLING]: 'extension.state.label.uninstalling',
|
||||
[InstalledState.INSTALLING]: 'extension.state.label.installing',
|
||||
} as const;
|
||||
|
||||
export const EXTENSION_ACTION_TO_FAILURE_TRANSLATION_KEY_MAP: {
|
||||
[action in ExtensionAction]: TranslationKey;
|
||||
} = {
|
||||
[ExtensionAction.UPDATE]: 'extension.label.update_failed',
|
||||
[ExtensionAction.INSTALL]: 'extension.label.installation_failed',
|
||||
[ExtensionAction.UNINSTALL]: 'extension.label.uninstallation_failed',
|
||||
};
|
||||
|
||||
export const extensionLanguageToTranslationKey: { [state in ExtensionGroupState | DefaultLanguage]: TranslationKey } = {
|
||||
[ExtensionGroupState.INSTALLED]: 'extension.state.label.installed',
|
||||
[ExtensionGroupState.UPDATE_PENDING]: 'extension.state.label.update_pending',
|
||||
[ExtensionGroupState.OBSOLETE]: 'extension.state.label.obsolete',
|
||||
[DefaultLanguage.ALL]: 'extension.language.all',
|
||||
[DefaultLanguage.OTHER]: 'extension.language.other',
|
||||
[DefaultLanguage.LOCAL_SOURCE]: 'extension.language.other',
|
||||
};
|
||||
62
src/modules/extension/Extensions.types.ts
Normal file
62
src/modules/extension/Extensions.types.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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 { DefaultLanguage } from '@/modules/core/utils/Languages.ts';
|
||||
import { ExtensionType } from '@/lib/graphql/generated/graphql.ts';
|
||||
|
||||
export enum ExtensionAction {
|
||||
UPDATE = 'UPDATE',
|
||||
UNINSTALL = 'UNINSTALL',
|
||||
INSTALL = 'INSTALL',
|
||||
}
|
||||
|
||||
export enum ExtensionState {
|
||||
OBSOLETE = 'OBSOLETE',
|
||||
UPDATING = 'UPDATING',
|
||||
UNINSTALLING = 'UNINSTALLING',
|
||||
INSTALLING = 'INSTALLING',
|
||||
}
|
||||
|
||||
export type InstalledStates = ExtensionAction | ExtensionState;
|
||||
|
||||
export const InstalledState = { ...ExtensionAction, ...ExtensionState } as const;
|
||||
|
||||
export enum ExtensionGroupState {
|
||||
INSTALLED = 'INSTALLED',
|
||||
UPDATE_PENDING = 'UPDATE_PENDING',
|
||||
OBSOLETE = 'OBSOLETE',
|
||||
}
|
||||
|
||||
export type TExtension = Pick<
|
||||
ExtensionType,
|
||||
| 'pkgName'
|
||||
| 'name'
|
||||
| 'lang'
|
||||
| 'versionCode'
|
||||
| 'versionName'
|
||||
| 'iconUrl'
|
||||
| 'repo'
|
||||
| 'isNsfw'
|
||||
| 'isInstalled'
|
||||
| 'isObsolete'
|
||||
| 'hasUpdate'
|
||||
>;
|
||||
|
||||
export type GroupedExtensionsResult<KEY extends string = string> = [KEY, TExtension[]][];
|
||||
|
||||
export type GroupedByExtensionState = {
|
||||
[state in ExtensionGroupState]: TExtension[];
|
||||
};
|
||||
|
||||
export type GroupedByLanguage = {
|
||||
[language in DefaultLanguage]: TExtension[];
|
||||
} & {
|
||||
[language: string]: TExtension[];
|
||||
};
|
||||
|
||||
export type GroupedExtensions = GroupedByExtensionState & GroupedByLanguage;
|
||||
110
src/modules/extension/Extensions.utils.ts
Normal file
110
src/modules/extension/Extensions.utils.ts
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* 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 { t } from 'i18next';
|
||||
import {
|
||||
ExtensionAction,
|
||||
ExtensionGroupState,
|
||||
ExtensionState,
|
||||
GroupedExtensions,
|
||||
GroupedExtensionsResult,
|
||||
InstalledState,
|
||||
TExtension,
|
||||
} from '@/modules/extension/Extensions.types.ts';
|
||||
import { DefaultLanguage, langCodeToName, langSortCmp } from '@/modules/core/utils/Languages.ts';
|
||||
import { extensionLanguageToTranslationKey } from '@/modules/extension/Extensions.constants.ts';
|
||||
|
||||
export const getInstalledState = (
|
||||
isInstalled: boolean,
|
||||
isObsolete: boolean,
|
||||
hasUpdate: boolean,
|
||||
): ExtensionAction | ExtensionState.OBSOLETE => {
|
||||
if (isObsolete) {
|
||||
return InstalledState.OBSOLETE;
|
||||
}
|
||||
|
||||
if (hasUpdate) {
|
||||
return InstalledState.UPDATE;
|
||||
}
|
||||
|
||||
return isInstalled ? InstalledState.UNINSTALL : InstalledState.INSTALL;
|
||||
};
|
||||
|
||||
export const isExtensionStateOrLanguage = (languageCode: string): boolean =>
|
||||
[
|
||||
ExtensionGroupState.INSTALLED,
|
||||
ExtensionGroupState.UPDATE_PENDING,
|
||||
ExtensionGroupState.OBSOLETE,
|
||||
DefaultLanguage.ALL,
|
||||
DefaultLanguage.OTHER,
|
||||
DefaultLanguage.LOCAL_SOURCE,
|
||||
].includes(languageCode as ExtensionGroupState | DefaultLanguage);
|
||||
|
||||
export const translateExtensionLanguage = (languageCode: string): string =>
|
||||
isExtensionStateOrLanguage(languageCode)
|
||||
? t(extensionLanguageToTranslationKey[languageCode as ExtensionGroupState | DefaultLanguage])
|
||||
: langCodeToName(languageCode);
|
||||
|
||||
export function getExtensionsInfo(extensions: TExtension[]): {
|
||||
allLangs: string[];
|
||||
groupedExtensions: GroupedExtensionsResult;
|
||||
} {
|
||||
const allLangs: string[] = [];
|
||||
const sortedExtensions: GroupedExtensions = {
|
||||
[ExtensionGroupState.OBSOLETE]: [],
|
||||
[ExtensionGroupState.INSTALLED]: [],
|
||||
[ExtensionGroupState.UPDATE_PENDING]: [],
|
||||
[DefaultLanguage.ALL]: [],
|
||||
[DefaultLanguage.OTHER]: [],
|
||||
[DefaultLanguage.LOCAL_SOURCE]: [],
|
||||
};
|
||||
extensions.forEach((extension) => {
|
||||
if (sortedExtensions[extension.lang] === undefined) {
|
||||
sortedExtensions[extension.lang] = [];
|
||||
if (extension.lang !== 'all') {
|
||||
allLangs.push(extension.lang);
|
||||
}
|
||||
}
|
||||
if (extension.isInstalled) {
|
||||
if (extension.hasUpdate) {
|
||||
sortedExtensions[ExtensionGroupState.UPDATE_PENDING].push(extension);
|
||||
return;
|
||||
}
|
||||
if (extension.isObsolete) {
|
||||
sortedExtensions[ExtensionGroupState.OBSOLETE].push(extension);
|
||||
return;
|
||||
}
|
||||
|
||||
sortedExtensions[ExtensionGroupState.INSTALLED].push(extension);
|
||||
} else {
|
||||
sortedExtensions[extension.lang].push(extension);
|
||||
}
|
||||
});
|
||||
|
||||
allLangs.sort(langSortCmp);
|
||||
const result: GroupedExtensionsResult<ExtensionGroupState | DefaultLanguage | string> = [
|
||||
[ExtensionGroupState.OBSOLETE, sortedExtensions[ExtensionGroupState.OBSOLETE]],
|
||||
[ExtensionGroupState.UPDATE_PENDING, sortedExtensions[ExtensionGroupState.UPDATE_PENDING]],
|
||||
[ExtensionGroupState.INSTALLED, sortedExtensions[ExtensionGroupState.INSTALLED]],
|
||||
[DefaultLanguage.ALL, sortedExtensions[DefaultLanguage.ALL]],
|
||||
[DefaultLanguage.OTHER, sortedExtensions[DefaultLanguage.OTHER]],
|
||||
[DefaultLanguage.LOCAL_SOURCE, sortedExtensions[DefaultLanguage.LOCAL_SOURCE]],
|
||||
];
|
||||
|
||||
const langExt: GroupedExtensionsResult = allLangs.map((lang) => [lang, sortedExtensions[lang]]);
|
||||
const groupedExtensions = result.concat(langExt);
|
||||
|
||||
groupedExtensions.forEach(([, groupedExtensionList]) =>
|
||||
groupedExtensionList.sort((a, b) => a.name.localeCompare(b.name)),
|
||||
);
|
||||
|
||||
return {
|
||||
allLangs,
|
||||
groupedExtensions,
|
||||
};
|
||||
}
|
||||
@@ -18,8 +18,20 @@ import { requestManager } from '@/lib/requests/RequestManager.ts';
|
||||
import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts';
|
||||
import { makeToast } from '@/modules/core/utils/Toast.ts';
|
||||
import { SpinnerImage } from '@/modules/core/components/SpinnerImage.tsx';
|
||||
import { TExtension } from '@/modules/extension/services/Extensions.ts';
|
||||
import { TranslationKey } from '@/Base.types.ts';
|
||||
import {
|
||||
ExtensionAction,
|
||||
ExtensionState,
|
||||
InstalledState,
|
||||
InstalledStates,
|
||||
TExtension,
|
||||
} from '@/modules/extension/Extensions.types.ts';
|
||||
import {
|
||||
EXTENSION_ACTION_TO_FAILURE_TRANSLATION_KEY_MAP,
|
||||
EXTENSION_ACTION_TO_NEXT_ACTION_MAP,
|
||||
EXTENSION_ACTION_TO_STATE_MAP,
|
||||
INSTALLED_STATE_TO_TRANSLATION_KEY_MAP,
|
||||
} from '@/modules/extension/Extensions.constants.ts';
|
||||
import { getInstalledState } from '@/modules/extension/Extensions.utils.ts';
|
||||
|
||||
interface IProps {
|
||||
extension: TExtension;
|
||||
@@ -27,69 +39,6 @@ interface IProps {
|
||||
showSourceRepo: boolean;
|
||||
}
|
||||
|
||||
enum ExtensionAction {
|
||||
UPDATE = 'UPDATE',
|
||||
UNINSTALL = 'UNINSTALL',
|
||||
INSTALL = 'INSTALL',
|
||||
}
|
||||
|
||||
enum ExtensionState {
|
||||
OBSOLETE = 'OBSOLETE',
|
||||
UPDATING = 'UPDATING',
|
||||
UNINSTALLING = 'UNINSTALLING',
|
||||
INSTALLING = 'INSTALLING',
|
||||
}
|
||||
|
||||
type InstalledStates = ExtensionAction | ExtensionState;
|
||||
|
||||
const InstalledState = { ...ExtensionAction, ...ExtensionState } as const;
|
||||
|
||||
const EXTENSION_ACTION_TO_STATE_MAP: { [action in ExtensionAction]: ExtensionState } = {
|
||||
[ExtensionAction.UPDATE]: ExtensionState.UPDATING,
|
||||
[ExtensionAction.UNINSTALL]: ExtensionState.UNINSTALLING,
|
||||
[ExtensionAction.INSTALL]: ExtensionState.INSTALLING,
|
||||
} as const;
|
||||
|
||||
const EXTENSION_ACTION_TO_NEXT_ACTION_MAP: { [action in ExtensionAction]: ExtensionAction } = {
|
||||
[ExtensionAction.UPDATE]: ExtensionAction.UNINSTALL,
|
||||
[ExtensionAction.UNINSTALL]: ExtensionAction.INSTALL,
|
||||
[ExtensionAction.INSTALL]: ExtensionAction.UNINSTALL,
|
||||
} as const;
|
||||
|
||||
const INSTALLED_STATE_TO_TRANSLATION_KEY_MAP: { [installedState in InstalledStates]: TranslationKey } = {
|
||||
[InstalledState.UNINSTALL]: 'extension.action.label.uninstall',
|
||||
[InstalledState.INSTALL]: 'extension.action.label.install',
|
||||
[InstalledState.UPDATE]: 'extension.action.label.update',
|
||||
[InstalledState.OBSOLETE]: 'extension.state.label.obsolete',
|
||||
[InstalledState.UPDATING]: 'extension.state.label.updating',
|
||||
[InstalledState.UNINSTALLING]: 'extension.state.label.uninstalling',
|
||||
[InstalledState.INSTALLING]: 'extension.state.label.installing',
|
||||
} as const;
|
||||
|
||||
const EXTENSION_ACTION_TO_FAILURE_TRANSLATION_KEY_MAP: {
|
||||
[action in ExtensionAction]: TranslationKey;
|
||||
} = {
|
||||
[ExtensionAction.UPDATE]: 'extension.label.update_failed',
|
||||
[ExtensionAction.INSTALL]: 'extension.label.installation_failed',
|
||||
[ExtensionAction.UNINSTALL]: 'extension.label.uninstallation_failed',
|
||||
};
|
||||
|
||||
const getInstalledState = (
|
||||
isInstalled: boolean,
|
||||
isObsolete: boolean,
|
||||
hasUpdate: boolean,
|
||||
): ExtensionAction | ExtensionState.OBSOLETE => {
|
||||
if (isObsolete) {
|
||||
return InstalledState.OBSOLETE;
|
||||
}
|
||||
|
||||
if (hasUpdate) {
|
||||
return InstalledState.UPDATE;
|
||||
}
|
||||
|
||||
return isInstalled ? InstalledState.UNINSTALL : InstalledState.INSTALL;
|
||||
};
|
||||
|
||||
export function ExtensionCard(props: IProps) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
|
||||
@@ -18,16 +18,8 @@ import Typography from '@mui/material/Typography';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
||||
import { extensionDefaultLangs, DefaultLanguage, langSortCmp } from '@/modules/core/utils/Languages.ts';
|
||||
import { extensionDefaultLangs } from '@/modules/core/utils/Languages.ts';
|
||||
import { useLocalStorage } from '@/modules/core/hooks/useStorage.tsx';
|
||||
import {
|
||||
ExtensionGroupState,
|
||||
GroupedExtensions,
|
||||
GroupedExtensionsResult,
|
||||
isExtensionStateOrLanguage,
|
||||
TExtension,
|
||||
translateExtensionLanguage,
|
||||
} from '@/modules/extension/services/Extensions.ts';
|
||||
import { AppbarSearch } from '@/modules/core/components/AppbarSearch.tsx';
|
||||
import { LoadingPlaceholder } from '@/modules/core/components/placeholder/LoadingPlaceholder.tsx';
|
||||
import { makeToast } from '@/modules/core/utils/Toast.ts';
|
||||
@@ -40,69 +32,15 @@ import { StyledGroupItemWrapper } from '@/modules/core/components/virtuoso/Style
|
||||
import { EmptyViewAbsoluteCentered } from '@/modules/core/components/placeholder/EmptyViewAbsoluteCentered.tsx';
|
||||
import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts';
|
||||
import { VirtuosoUtil } from '@/lib/virtuoso/Virtuoso.util.tsx';
|
||||
import {
|
||||
getExtensionsInfo,
|
||||
isExtensionStateOrLanguage,
|
||||
translateExtensionLanguage,
|
||||
} from '@/modules/extension/Extensions.utils.ts';
|
||||
|
||||
const LANGUAGE = 0;
|
||||
const EXTENSIONS = 1;
|
||||
|
||||
function getExtensionsInfo(extensions: TExtension[]): {
|
||||
allLangs: string[];
|
||||
groupedExtensions: GroupedExtensionsResult;
|
||||
} {
|
||||
const allLangs: string[] = [];
|
||||
const sortedExtensions: GroupedExtensions = {
|
||||
[ExtensionGroupState.OBSOLETE]: [],
|
||||
[ExtensionGroupState.INSTALLED]: [],
|
||||
[ExtensionGroupState.UPDATE_PENDING]: [],
|
||||
[DefaultLanguage.ALL]: [],
|
||||
[DefaultLanguage.OTHER]: [],
|
||||
[DefaultLanguage.LOCAL_SOURCE]: [],
|
||||
};
|
||||
extensions.forEach((extension) => {
|
||||
if (sortedExtensions[extension.lang] === undefined) {
|
||||
sortedExtensions[extension.lang] = [];
|
||||
if (extension.lang !== 'all') {
|
||||
allLangs.push(extension.lang);
|
||||
}
|
||||
}
|
||||
if (extension.isInstalled) {
|
||||
if (extension.hasUpdate) {
|
||||
sortedExtensions[ExtensionGroupState.UPDATE_PENDING].push(extension);
|
||||
return;
|
||||
}
|
||||
if (extension.isObsolete) {
|
||||
sortedExtensions[ExtensionGroupState.OBSOLETE].push(extension);
|
||||
return;
|
||||
}
|
||||
|
||||
sortedExtensions[ExtensionGroupState.INSTALLED].push(extension);
|
||||
} else {
|
||||
sortedExtensions[extension.lang].push(extension);
|
||||
}
|
||||
});
|
||||
|
||||
allLangs.sort(langSortCmp);
|
||||
const result: GroupedExtensionsResult<ExtensionGroupState | DefaultLanguage | string> = [
|
||||
[ExtensionGroupState.OBSOLETE, sortedExtensions[ExtensionGroupState.OBSOLETE]],
|
||||
[ExtensionGroupState.UPDATE_PENDING, sortedExtensions[ExtensionGroupState.UPDATE_PENDING]],
|
||||
[ExtensionGroupState.INSTALLED, sortedExtensions[ExtensionGroupState.INSTALLED]],
|
||||
[DefaultLanguage.ALL, sortedExtensions[DefaultLanguage.ALL]],
|
||||
[DefaultLanguage.OTHER, sortedExtensions[DefaultLanguage.OTHER]],
|
||||
[DefaultLanguage.LOCAL_SOURCE, sortedExtensions[DefaultLanguage.LOCAL_SOURCE]],
|
||||
];
|
||||
|
||||
const langExt: GroupedExtensionsResult = allLangs.map((lang) => [lang, sortedExtensions[lang]]);
|
||||
const groupedExtensions = result.concat(langExt);
|
||||
|
||||
groupedExtensions.forEach(([, groupedExtensionList]) =>
|
||||
groupedExtensionList.sort((a, b) => a.name.localeCompare(b.name)),
|
||||
);
|
||||
|
||||
return {
|
||||
allLangs,
|
||||
groupedExtensions,
|
||||
};
|
||||
}
|
||||
|
||||
export function Extensions({ tabsMenuHeight }: { tabsMenuHeight: number }) {
|
||||
const { t } = useTranslation();
|
||||
const { setAction } = useContext(NavBarContext);
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
* 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 { t } from 'i18next';
|
||||
import { DefaultLanguage, langCodeToName } from '@/modules/core/utils/Languages.ts';
|
||||
import { ExtensionType } from '@/lib/graphql/generated/graphql.ts';
|
||||
import { TranslationKey } from '@/Base.types.ts';
|
||||
|
||||
export enum ExtensionGroupState {
|
||||
INSTALLED = 'INSTALLED',
|
||||
UPDATE_PENDING = 'UPDATE_PENDING',
|
||||
OBSOLETE = 'OBSOLETE',
|
||||
}
|
||||
|
||||
export type TExtension = Pick<
|
||||
ExtensionType,
|
||||
| 'pkgName'
|
||||
| 'name'
|
||||
| 'lang'
|
||||
| 'versionCode'
|
||||
| 'versionName'
|
||||
| 'iconUrl'
|
||||
| 'repo'
|
||||
| 'isNsfw'
|
||||
| 'isInstalled'
|
||||
| 'isObsolete'
|
||||
| 'hasUpdate'
|
||||
>;
|
||||
|
||||
export type GroupedExtensionsResult<KEY extends string = string> = [KEY, TExtension[]][];
|
||||
|
||||
export type GroupedByExtensionState = {
|
||||
[state in ExtensionGroupState]: TExtension[];
|
||||
};
|
||||
|
||||
export type GroupedByLanguage = {
|
||||
[language in DefaultLanguage]: TExtension[];
|
||||
} & {
|
||||
[language: string]: TExtension[];
|
||||
};
|
||||
|
||||
export type GroupedExtensions = GroupedByExtensionState & GroupedByLanguage;
|
||||
|
||||
export const extensionLanguageToTranslationKey: { [state in ExtensionGroupState | DefaultLanguage]: TranslationKey } = {
|
||||
[ExtensionGroupState.INSTALLED]: 'extension.state.label.installed',
|
||||
[ExtensionGroupState.UPDATE_PENDING]: 'extension.state.label.update_pending',
|
||||
[ExtensionGroupState.OBSOLETE]: 'extension.state.label.obsolete',
|
||||
[DefaultLanguage.ALL]: 'extension.language.all',
|
||||
[DefaultLanguage.OTHER]: 'extension.language.other',
|
||||
[DefaultLanguage.LOCAL_SOURCE]: 'extension.language.other',
|
||||
};
|
||||
|
||||
export const isExtensionStateOrLanguage = (languageCode: string): boolean =>
|
||||
[
|
||||
ExtensionGroupState.INSTALLED,
|
||||
ExtensionGroupState.UPDATE_PENDING,
|
||||
ExtensionGroupState.OBSOLETE,
|
||||
DefaultLanguage.ALL,
|
||||
DefaultLanguage.OTHER,
|
||||
DefaultLanguage.LOCAL_SOURCE,
|
||||
].includes(languageCode as ExtensionGroupState | DefaultLanguage);
|
||||
|
||||
export const translateExtensionLanguage = (languageCode: string): string =>
|
||||
isExtensionStateOrLanguage(languageCode)
|
||||
? t(extensionLanguageToTranslationKey[languageCode as ExtensionGroupState | DefaultLanguage])
|
||||
: langCodeToName(languageCode);
|
||||
@@ -17,7 +17,6 @@ import Box from '@mui/material/Box';
|
||||
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
||||
import { useLocalStorage } from '@/modules/core/hooks/useStorage.tsx';
|
||||
import { langSortCmp, sourceDefualtLangs, sourceForcedDefaultLangs } from '@/modules/core/utils/Languages.ts';
|
||||
import { translateExtensionLanguage } from '@/modules/extension/services/Extensions.ts';
|
||||
import { AppbarSearch } from '@/modules/core/components/AppbarSearch.tsx';
|
||||
import { LangSelect } from '@/modules/core/components/inputs/LangSelect.tsx';
|
||||
import { useDebounce } from '@/modules/core/hooks/useDebounce.ts';
|
||||
@@ -29,6 +28,7 @@ import { LoadingPlaceholder } from '@/modules/core/components/placeholder/Loadin
|
||||
import { SourceType } from '@/lib/graphql/generated/graphql.ts';
|
||||
import { BaseMangaGrid } from '@/modules/manga/components/BaseMangaGrid.tsx';
|
||||
import { EmptyViewAbsoluteCentered } from '@/modules/core/components/placeholder/EmptyViewAbsoluteCentered.tsx';
|
||||
import { translateExtensionLanguage } from '@/modules/extension/Extensions.utils.ts';
|
||||
|
||||
type SourceLoadingState = { isLoading: boolean; hasResults: boolean; emptySearch: boolean };
|
||||
type SourceToLoadingStateMap = Map<string, SourceLoadingState>;
|
||||
|
||||
@@ -17,8 +17,8 @@ import { Link } from 'react-router-dom';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
||||
import { GetMigratableSourcesQuery } from '@/lib/graphql/generated/graphql.ts';
|
||||
import { translateExtensionLanguage } from '@/modules/extension/services/Extensions.ts';
|
||||
import { SpinnerImage } from '@/modules/core/components/SpinnerImage.tsx';
|
||||
import { translateExtensionLanguage } from '@/modules/extension/Extensions.utils.ts';
|
||||
|
||||
export type TMigratableSource = NonNullable<GetMigratableSourcesQuery['mangas']['nodes'][number]['source']> & {
|
||||
mangaCount: number;
|
||||
|
||||
@@ -18,11 +18,11 @@ import { useTranslation } from 'react-i18next';
|
||||
import { Link } from 'react-router-dom';
|
||||
import Stack from '@mui/material/Stack';
|
||||
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
||||
import { translateExtensionLanguage } from '@/modules/extension/services/Extensions.ts';
|
||||
import { SourceContentType } from '@/modules/source/screens/SourceMangas.tsx';
|
||||
import { SpinnerImage } from '@/modules/core/components/SpinnerImage.tsx';
|
||||
import { GetSourcesListQuery } from '@/lib/graphql/generated/graphql.ts';
|
||||
import { MediaQuery } from '@/modules/core/utils/MediaQuery.tsx';
|
||||
import { translateExtensionLanguage } from '@/modules/extension/Extensions.utils.ts';
|
||||
|
||||
interface IProps {
|
||||
source: GetSourcesListQuery['sources']['nodes'][number];
|
||||
|
||||
@@ -21,7 +21,6 @@ import {
|
||||
langSortCmp,
|
||||
DefaultLanguage,
|
||||
} from '@/modules/core/utils/Languages.ts';
|
||||
import { translateExtensionLanguage } from '@/modules/extension/services/Extensions.ts';
|
||||
import { LoadingPlaceholder } from '@/modules/core/components/placeholder/LoadingPlaceholder.tsx';
|
||||
import { SourceCard } from '@/modules/source/components/SourceCard.tsx';
|
||||
import { LangSelect } from '@/modules/core/components/inputs/LangSelect.tsx';
|
||||
@@ -29,6 +28,7 @@ import { NavBarContext } from '@/modules/navigation-bar/contexts/NavbarContext.t
|
||||
import { EmptyViewAbsoluteCentered } from '@/modules/core/components/placeholder/EmptyViewAbsoluteCentered.tsx';
|
||||
import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts';
|
||||
import { SourceType } from '@/lib/graphql/generated/graphql.ts';
|
||||
import { translateExtensionLanguage } from '@/modules/extension/Extensions.utils.ts';
|
||||
|
||||
function sourceToLangList(sources: Pick<SourceType, 'id' | 'lang'>[]) {
|
||||
const result = new Set<string>();
|
||||
|
||||
Reference in New Issue
Block a user