diff --git a/ui/v2.5/src/components/Settings/Tasks/LibraryTasks.tsx b/ui/v2.5/src/components/Settings/Tasks/LibraryTasks.tsx index eace4b7dc..cd89ed953 100644 --- a/ui/v2.5/src/components/Settings/Tasks/LibraryTasks.tsx +++ b/ui/v2.5/src/components/Settings/Tasks/LibraryTasks.tsx @@ -8,6 +8,7 @@ import { } from "src/core/StashService"; import { withoutTypename } from "src/utils/data"; import { useConfigurationContext } from "src/hooks/Config"; +import { useAutoTagTrigger } from "src/hooks/useAutoTagTrigger"; import { IdentifyDialog } from "../../Dialogs/IdentifyDialog/IdentifyDialog"; import * as GQL from "src/core/generated-graphql"; import { DirectorySelectionDialog } from "./DirectorySelectionDialog"; @@ -195,6 +196,12 @@ export const LibraryTasks: React.FC = () => { }); } + const onAutoTagClick = useAutoTagTrigger( + () => runAutoTag(), + () => setDialogOpen({ autoTagAlert: true }), + ui.disableAutoTagWarning + ); + function renderScanDialog() { if (!dialogOpen.scan) { return; @@ -449,7 +456,7 @@ export const LibraryTasks: React.FC = () => { variant="secondary" type="submit" className="mr-2" - onClick={() => setDialogOpen({ autoTagAlert: true })} + onClick={onAutoTagClick} > … @@ -468,6 +475,13 @@ export const LibraryTasks: React.FC = () => { options={autoTagOptions} setOptions={onSetAutoTagOptions} /> + saveUI({ disableAutoTagWarning: v })} + /> diff --git a/ui/v2.5/src/components/Shared/AutoTagConfirmDialog.tsx b/ui/v2.5/src/components/Shared/AutoTagConfirmDialog.tsx index 0290c7e07..b4fcd21bd 100644 --- a/ui/v2.5/src/components/Shared/AutoTagConfirmDialog.tsx +++ b/ui/v2.5/src/components/Shared/AutoTagConfirmDialog.tsx @@ -1,6 +1,10 @@ -import React from "react"; +import React, { useContext, useEffect, useState } from "react"; +import { Form } from "react-bootstrap"; import { FormattedMessage, useIntl } from "react-intl"; import { faExclamationTriangle } from "@fortawesome/free-solid-svg-icons"; +import { useConfigureUISetting } from "src/core/StashService"; +import { SettingStateContext } from "src/components/Settings/context"; +import { useToast } from "src/hooks/Toast"; import { ModalComponent } from "./Modal"; import { Icon } from "./Icon"; @@ -31,6 +35,29 @@ export const AutoTagConfirmDialog: React.FC = ({ onCancel, }) => { const intl = useIntl(); + const Toast = useToast(); + const [dontShowAgain, setDontShowAgain] = useState(false); + const [saveUISetting] = useConfigureUISetting(); + const settingsContext = useContext(SettingStateContext); + + useEffect(() => { + if (show) { + setDontShowAgain(false); + } + }, [show]); + + function handleConfirm() { + if (dontShowAgain) { + if (settingsContext) { + settingsContext.saveUI({ disableAutoTagWarning: true }); + } else { + saveUISetting({ + variables: { key: "disableAutoTagWarning", value: true }, + }).catch((e: unknown) => Toast.error(e)); + } + } + onConfirm(); + } return ( = ({ accept={{ text: intl.formatMessage({ id: "actions.confirm" }), variant: "danger", - onClick: onConfirm, + onClick: handleConfirm, }} cancel={{ onClick: onCancel, }} > + setDontShowAgain(e.currentTarget.checked)} + label={intl.formatMessage({ + id: "dialogs.dont_show_again", + })} + /> ); }; diff --git a/ui/v2.5/src/components/Shared/DetailsEditNavbar.tsx b/ui/v2.5/src/components/Shared/DetailsEditNavbar.tsx index 159bb9f09..d4b0c9114 100644 --- a/ui/v2.5/src/components/Shared/DetailsEditNavbar.tsx +++ b/ui/v2.5/src/components/Shared/DetailsEditNavbar.tsx @@ -1,6 +1,7 @@ import { Button, Dropdown, Modal, SplitButton } from "react-bootstrap"; import React, { useState } from "react"; import { FormattedMessage, useIntl } from "react-intl"; +import { useAutoTagTrigger } from "src/hooks/useAutoTagTrigger"; import { ImageInput } from "./ImageInput"; import { AutoTagConfirmDialog } from "./AutoTagConfirmDialog"; import cx from "classnames"; @@ -33,6 +34,11 @@ export const DetailsEditNavbar: React.FC = (props: IProps) => { const [isDeleteAlertOpen, setIsDeleteAlertOpen] = useState(false); const [isAutoTagAlertOpen, setIsAutoTagAlertOpen] = useState(false); + const onAutoTagClick = useAutoTagTrigger( + () => props.onAutoTag?.(), + () => setIsAutoTagAlertOpen(true) + ); + function renderEditButton() { if (props.isNew) return; return ( @@ -116,7 +122,7 @@ export const DetailsEditNavbar: React.FC = (props: IProps) => { diff --git a/ui/v2.5/src/core/config.ts b/ui/v2.5/src/core/config.ts index e0cf008b5..3978d1887 100644 --- a/ui/v2.5/src/core/config.ts +++ b/ui/v2.5/src/core/config.ts @@ -105,6 +105,9 @@ export interface IUIConfig { taskDefaults?: Record; + // if true the auto tag confirmation warning is skipped + disableAutoTagWarning?: boolean; + defaultFilters?: DefaultFilters; taggerConfig?: ITaggerConfig; diff --git a/ui/v2.5/src/docs/en/Manual/AutoTagging.md b/ui/v2.5/src/docs/en/Manual/AutoTagging.md index 4725020d1..540a4b508 100644 --- a/ui/v2.5/src/docs/en/Manual/AutoTagging.md +++ b/ui/v2.5/src/docs/en/Manual/AutoTagging.md @@ -48,3 +48,7 @@ Performers or Tags that have Ignore Auto tag flag added to them will be skipped - **Auto tag:** You can run the Auto tag task on your entire library from the Tasks page. - **Selective auto tag:** You can run the Auto tag task on specific directories from the Tasks page. - **Individual pages:** You can run Auto tag tasks for specific Performers, Studios, and Tags from their respective pages. + +### Disable the confirmation warning + +A confirmation warning is shown before the auto tag task runs. If you use auto tag frequently, you can disable this warning by ticking the **Don't show this warning again** checkbox on the warning dialog, or by enabling **Settings** > **Tasks** > **Auto tag** > **Disable auto-tag warning**. diff --git a/ui/v2.5/src/hooks/useAutoTagTrigger.ts b/ui/v2.5/src/hooks/useAutoTagTrigger.ts new file mode 100644 index 000000000..4cb3ca38c --- /dev/null +++ b/ui/v2.5/src/hooks/useAutoTagTrigger.ts @@ -0,0 +1,20 @@ +import { useCallback } from "react"; +import { IUIConfig } from "src/core/config"; +import { useConfigurationContext } from "./Config"; + +export function useAutoTagTrigger( + onRun: () => void, + onOpenConfirm: () => void, + override?: boolean | null +) { + const { configuration } = useConfigurationContext(); + const ui = configuration?.ui as IUIConfig | undefined; + const disabled = override ?? ui?.disableAutoTagWarning ?? false; + return useCallback(() => { + if (disabled) { + onRun(); + return; + } + onOpenConfirm(); + }, [disabled, onRun, onOpenConfirm]); +} diff --git a/ui/v2.5/src/locales/en-GB.json b/ui/v2.5/src/locales/en-GB.json index 4974c06ca..b3d05fed7 100644 --- a/ui/v2.5/src/locales/en-GB.json +++ b/ui/v2.5/src/locales/en-GB.json @@ -509,7 +509,11 @@ "anonymising_database": "Anonymising database", "auto_tag": { "auto_tagging_all_paths": "Auto tagging all paths", - "auto_tagging_paths": "Auto tagging the following paths" + "auto_tagging_paths": "Auto tagging the following paths", + "disable_warning": { + "description": "Disable the confirmation warning shown before running auto tag.", + "heading": "Disable auto tag warning" + } }, "auto_tag_based_on_filenames": "Auto tag content based on file paths.", "auto_tag_confirm": "This will attempt to match your content against existing metadata.", @@ -1002,6 +1006,7 @@ "delete_object_desc": "Are you sure you want to delete {count, plural, one {this {singularEntity}} other {these {pluralEntity}}}?", "delete_object_overflow": "…and {count} other {count, plural, one {{singularEntity}} other {{pluralEntity}}}.", "delete_object_title": "Delete {count, plural, one {{singularEntity}} other {{pluralEntity}}}", + "dont_show_again": "Don't show this warning again", "dont_show_until_updated": "Don't show until next update", "edit_entity_title": "Edit {count, plural, one {{singularEntity}} other {{pluralEntity}}}", "edit_entity_count_title": "Edit {count} {count, plural, one {{singularEntity}} other {{pluralEntity}}}",