diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
index 02a528b8..9b4213a1 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -36,27 +36,6 @@ body:
validations:
required: true
-- type: input
- id: suwayomi-server-version
- attributes:
- label: Suwayomi-Server version
- description: You can find your Suwayomi-Server version in **More → About**.
- placeholder: |
- Example: "v1.1.1 | v1.1.1-r1701"
- validations:
- required: true
-
-- type: dropdown
- id: database
- attributes:
- label: Used database
- description: H2 is the default database
- options:
- - H2
- - PostgreSQL
- validations:
- required: true
-
- type: input
id: server-os
attributes:
@@ -87,33 +66,22 @@ body:
validations:
required: true
-- type: input
- id: suwayomi-webui-version
+- type: textarea
+ id: debug-information
attributes:
- label: Suwayomi-WebUI version
- description: You can find your Suwayomi-WebUI version in **More → About**.
- placeholder: |
- Example: "r1689 STABLE | r2401 PREVIEW"
- validations:
- required: true
-
-- type: input
- id: client-browser
- attributes:
- label: Used web browser
- description: The browser which is used to open Suwayomi-WebUI
- placeholder: |
- Example: "Chrome 134.0.6998.118 (64-Bit) | FireFox 136.0.2 (64-Bit) | Electron v35.0.2"
- validations:
- required: true
-
-- type: input
- id: client-os
- attributes:
- label: Client operating system
- description: The system on which the Suwayomi-WebUI is running on
- placeholder: |
- Example: "Windows 11 Pro 24H2 | Ubuntu 24.04.2 LTS"
+ label: Debug information
+ description: |
+ Provide the debug information from the About page.
+ _Note:_ You can paste the copied debug information into the placeholder below.
+ value: |
+
+ Click here to see debug information
+
+
+ ```
+ Replace this text with the copied debug information
+ ```
+
validations:
required: true
diff --git a/src/base/utils/Strings.ts b/src/base/utils/Strings.ts
index 52d4d4d7..63e7fb0b 100644
--- a/src/base/utils/Strings.ts
+++ b/src/base/utils/Strings.ts
@@ -16,3 +16,5 @@ export const enhancedCleanup = (str: string): string =>
export const reverseString = (str: string, separator: string = ''): string =>
str.split(separator).reverse().join(separator);
+
+export const indent = (str: string, level: number, char: string): string => char.repeat(level) + str;
diff --git a/src/features/extension/store/screens/ExtensionStores.tsx b/src/features/extension/store/screens/ExtensionStores.tsx
index b24b13ae..c32bf202 100644
--- a/src/features/extension/store/screens/ExtensionStores.tsx
+++ b/src/features/extension/store/screens/ExtensionStores.tsx
@@ -8,7 +8,7 @@
import { requestManager } from '@/lib/requests/RequestManager.ts';
import { EmptyViewAbsoluteCentered } from '@/base/components/feedback/EmptyViewAbsoluteCentered.tsx';
-import { getErrorMessage, noOp } from '@/lib/HelperFunctions.ts';
+import { copyToClipboard, getErrorMessage, noOp } from '@/lib/HelperFunctions.ts';
import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts';
import { useLingui } from '@lingui/react/macro';
import { LoadingPlaceholder } from '@/base/components/feedback/LoadingPlaceholder.tsx';
@@ -127,9 +127,8 @@ const ExtensionStoreCard = ({
)}
{
- await navigator.clipboard.writeText(indexUrl);
- makeToast(t`Copied to clipboard`, 'info');
+ onClick={() => {
+ copyToClipboard(indexUrl);
}}
color="inherit"
>
diff --git a/src/features/manga/components/details/MangaDetails.tsx b/src/features/manga/components/details/MangaDetails.tsx
index d871706c..71211ecc 100644
--- a/src/features/manga/components/details/MangaDetails.tsx
+++ b/src/features/manga/components/details/MangaDetails.tsx
@@ -27,7 +27,6 @@ import { FlexWrapButton } from '@/base/components/buttons/FlexWrapButton.tsx';
import { TrackMangaButton } from '@/features/manga/components/TrackMangaButton.tsx';
import { useManageMangaLibraryState } from '@/features/manga/hooks/useManageMangaLibraryState.tsx';
import { Metadata as BaseMetadata } from '@/base/components/texts/Metadata.tsx';
-import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts';
import type { MangaType, SourceType } from '@/lib/graphql/generated/graphql-base.types.ts';
import { useMetadataServerSettings } from '@/features/settings/services/ServerSettingsMetadata.ts';
import { MANGA_STATUS_TO_TRANSLATION } from '@/features/manga/Manga.constants.ts';
@@ -56,6 +55,7 @@ import { requestManager } from '@/lib/requests/RequestManager.ts';
import { IconBrowser } from '@/assets/icons/IconBrowser.tsx';
import { IconWebView } from '@/assets/icons/IconWebView.tsx';
import { MediaQuery } from '@/base/utils/MediaQuery.tsx';
+import { copyToClipboard } from '@/lib/HelperFunctions.ts';
const DetailsWrapper = styled('div')(({ theme }) => ({
display: 'flex',
@@ -240,15 +240,6 @@ export const MangaDetails = ({
const { updateLibraryState } = useManageMangaLibraryState(manga);
- const copyTitle = async () => {
- try {
- await navigator.clipboard.writeText(manga.title);
- makeToast(t`Copied to clipboard`, 'info');
- } catch (e) {
- defaultPromiseErrorHandler('MangaDetails::copyTitleLongPress')(e);
- }
- };
-
return (
@@ -263,7 +254,7 @@ export const MangaDetails = ({
{!!navigator.clipboard && (
-
+ copyToClipboard(manga.title)} color="inherit">
diff --git a/src/features/metadata/Metadata.utils.ts b/src/features/metadata/Metadata.utils.ts
index c49a77d7..b72ed7a1 100644
--- a/src/features/metadata/Metadata.utils.ts
+++ b/src/features/metadata/Metadata.utils.ts
@@ -12,6 +12,8 @@ import { getActiveDevice } from '@/features/device/services/Device.ts';
export const extractOriginalKey = (key: string) => key.split('_').slice(-1)[0];
+export const getMetadataKeyRaw = (key: string, prefixes: string[]): string => `${prefixes.join('_')}_${key}`;
+
/**
* Returns the key with the provided prefixes.
*
@@ -34,7 +36,7 @@ export const getMetadataKey = (key: string, prefixes: string[] = [], appPrefix:
(prefix) => prefix.toLowerCase() !== 'default',
);
- return `${finalPrefix.join('_')}_${key}`;
+ return getMetadataKeyRaw(key, finalPrefix);
};
export const doesAppMetadataKeyExistIn = (
@@ -46,3 +48,19 @@ export const doesAppMetadataKeyExistIn = (
export const doesMetadataKeyExistIn = (meta: Metadata | undefined, key: string): boolean =>
Object.prototype.hasOwnProperty.call(meta ?? {}, key);
+
+export const getAppMetadataFrom = (
+ meta: Metadata,
+ prefixes: string[] = [],
+ appPrefix: string = APP_METADATA_KEY_PREFIX,
+): Metadata => {
+ const appMetadata: Metadata = {};
+
+ Object.entries(meta).forEach(([key, value]) => {
+ if (key.startsWith([appPrefix, ...prefixes].join('_'))) {
+ appMetadata[key] = value;
+ }
+ });
+
+ return appMetadata;
+};
diff --git a/src/features/metadata/services/MetadataMigrations.ts b/src/features/metadata/services/MetadataMigrations.ts
index 789ab22f..02ee07f7 100644
--- a/src/features/metadata/services/MetadataMigrations.ts
+++ b/src/features/metadata/services/MetadataMigrations.ts
@@ -20,7 +20,7 @@ import type {
MetadataHolderType,
MetadataKeyValuePair,
} from '@/features/metadata/Metadata.types.ts';
-import { extractOriginalKey, getMetadataKey } from '@/features/metadata/Metadata.utils.ts';
+import { extractOriginalKey, getAppMetadataFrom, getMetadataKey } from '@/features/metadata/Metadata.utils.ts';
import type { MangaIdInfo } from '@/features/manga/Manga.types.ts';
import type { CategoryIdInfo } from '@/features/category/Category.types.ts';
import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts';
@@ -37,22 +37,6 @@ const getAppKeyPrefixForMigration = (migrationId: number): string => {
return appKeyPrefix?.appKeyPrefix?.newPrefix ?? APP_METADATA_KEY_PREFIX;
};
-const getAppMetadataFrom = (
- meta: Metadata,
- prefixes: string[] = [],
- appPrefix: string = APP_METADATA_KEY_PREFIX,
-): Metadata => {
- const appMetadata: Metadata = {};
-
- Object.entries(meta).forEach(([key, value]) => {
- if (key.startsWith([appPrefix, ...prefixes].join('_'))) {
- appMetadata[key] = value;
- }
- });
-
- return appMetadata;
-};
-
const applyAppKeyPrefixMigration = (meta: Metadata, migration: IMetadataMigration): Metadata => {
const migratedMetadata: Metadata = { ...meta };
diff --git a/src/features/reader/overlay/mobile/ReaderOverlayHeaderMobile.tsx b/src/features/reader/overlay/mobile/ReaderOverlayHeaderMobile.tsx
index 8d79e2e5..a3797703 100644
--- a/src/features/reader/overlay/mobile/ReaderOverlayHeaderMobile.tsx
+++ b/src/features/reader/overlay/mobile/ReaderOverlayHeaderMobile.tsx
@@ -20,7 +20,6 @@ import { memo } from 'react';
import { useLingui } from '@lingui/react/macro';
import { CustomTooltip } from '@/base/components/CustomTooltip.tsx';
import { TypographyMaxLines } from '@/base/components/texts/TypographyMaxLines.tsx';
-import { makeToast } from '@/base/utils/Toast.ts';
import type { MobileHeaderProps } from '@/features/reader/overlay/ReaderOverlay.types.ts';
import { LoadingPlaceholder } from '@/base/components/feedback/LoadingPlaceholder.tsx';
import { AppRoutes } from '@/base/AppRoute.constants.ts';
@@ -35,6 +34,7 @@ import {
useReaderScrollbarStore,
useReaderStore,
} from '@/features/reader/stores/ReaderStore.ts';
+import { copyToClipboard } from '@/lib/HelperFunctions.ts';
const DEFAULT_MANGA = { ...FALLBACK_MANGA, title: '' };
@@ -113,13 +113,7 @@ const BaseReaderOverlayHeaderMobile = ({ isVisible, ref }: MobileHeaderProps & {
>
{t`Open in WebView`}
-