mirror of
https://github.com/stashapp/stash.git
synced 2026-05-09 05:05:29 +02:00
initial work for autotag skip warning
This commit is contained in:
parent
a33cca6033
commit
35488c706f
10 changed files with 108 additions and 6 deletions
|
|
@ -428,6 +428,9 @@ input ConfigInterfaceInput {
|
|||
"Set to true to disable creating new objects via the dropdown menus"
|
||||
disableDropdownCreate: ConfigDisableDropdownCreateInput
|
||||
|
||||
"Set to true to skip the auto tag confirmation warning"
|
||||
disableAutoTagWarning: Boolean
|
||||
|
||||
"Handy Connection Key"
|
||||
handyKey: String
|
||||
"Funscript Time Offset"
|
||||
|
|
@ -505,6 +508,9 @@ type ConfigInterfaceResult {
|
|||
"Fields are true if creating via dropdown menus are disabled"
|
||||
disableDropdownCreate: ConfigDisableDropdownCreate!
|
||||
|
||||
"True if the auto tag confirmation warning should be skipped"
|
||||
disableAutoTagWarning: Boolean
|
||||
|
||||
"Handy Connection Key"
|
||||
handyKey: String
|
||||
"Funscript Time Offset"
|
||||
|
|
|
|||
|
|
@ -538,6 +538,8 @@ func (r *mutationResolver) ConfigureInterface(ctx context.Context, input ConfigI
|
|||
r.setConfigBool(config.DisableDropdownCreateGallery, ddc.Gallery)
|
||||
}
|
||||
|
||||
r.setConfigBool(config.DisableAutoTagWarning, input.DisableAutoTagWarning)
|
||||
|
||||
r.setConfigString(config.HandyKey, input.HandyKey)
|
||||
r.setConfigInt(config.FunscriptOffset, input.FunscriptOffset)
|
||||
r.setConfigBool(config.UseStashHostedFunscript, input.UseStashHostedFunscript)
|
||||
|
|
|
|||
|
|
@ -168,6 +168,7 @@ func makeConfigInterfaceResult() *ConfigInterfaceResult {
|
|||
useStashHostedFunscript := config.GetUseStashHostedFunscript()
|
||||
imageLightboxOptions := config.GetImageLightboxOptions()
|
||||
disableDropdownCreate := config.GetDisableDropdownCreate()
|
||||
disableAutoTagWarning := config.GetDisableAutoTagWarning()
|
||||
|
||||
return &ConfigInterfaceResult{
|
||||
SfwContentMode: config.GetSFWContentMode(),
|
||||
|
|
@ -196,6 +197,8 @@ func makeConfigInterfaceResult() *ConfigInterfaceResult {
|
|||
|
||||
DisableDropdownCreate: disableDropdownCreate,
|
||||
|
||||
DisableAutoTagWarning: &disableAutoTagWarning,
|
||||
|
||||
HandyKey: &handyKey,
|
||||
FunscriptOffset: &scriptOffset,
|
||||
UseStashHostedFunscript: &useStashHostedFunscript,
|
||||
|
|
|
|||
|
|
@ -237,6 +237,8 @@ const (
|
|||
DisableDropdownCreateMovie = "disable_dropdown_create.movie"
|
||||
DisableDropdownCreateGallery = "disable_dropdown_create.gallery"
|
||||
|
||||
DisableAutoTagWarning = "disable_auto_tag_warning"
|
||||
|
||||
HandyKey = "handy_key"
|
||||
FunscriptOffset = "funscript_offset"
|
||||
UseStashHostedFunscript = "use_stash_hosted_funscript"
|
||||
|
|
@ -1311,6 +1313,10 @@ func (i *Config) GetShowStudioAsText() bool {
|
|||
return i.getBool(ShowStudioAsText)
|
||||
}
|
||||
|
||||
func (i *Config) GetDisableAutoTagWarning() bool {
|
||||
return i.getBool(DisableAutoTagWarning)
|
||||
}
|
||||
|
||||
func (i *Config) getSlideshowDelay() int {
|
||||
// assume have lock
|
||||
|
||||
|
|
|
|||
|
|
@ -115,6 +115,7 @@ fragment ConfigInterfaceData on ConfigInterfaceResult {
|
|||
movie
|
||||
gallery
|
||||
}
|
||||
disableAutoTagWarning
|
||||
handyKey
|
||||
funscriptOffset
|
||||
useStashHostedFunscript
|
||||
|
|
|
|||
|
|
@ -75,7 +75,13 @@ const AutoTagOptions: React.FC<IAutoTagOptions> = ({
|
|||
export const LibraryTasks: React.FC = () => {
|
||||
const intl = useIntl();
|
||||
const Toast = useToast();
|
||||
const { ui, saveUI, loading } = useSettings();
|
||||
const {
|
||||
ui,
|
||||
saveUI,
|
||||
interface: iface,
|
||||
saveInterface,
|
||||
loading,
|
||||
} = useSettings();
|
||||
|
||||
const { taskDefaults } = ui;
|
||||
|
||||
|
|
@ -195,6 +201,14 @@ export const LibraryTasks: React.FC = () => {
|
|||
});
|
||||
}
|
||||
|
||||
function onAutoTagClick() {
|
||||
if (configuration?.interface.disableAutoTagWarning) {
|
||||
runAutoTag();
|
||||
return;
|
||||
}
|
||||
setDialogOpen({ autoTagAlert: true });
|
||||
}
|
||||
|
||||
function renderScanDialog() {
|
||||
if (!dialogOpen.scan) {
|
||||
return;
|
||||
|
|
@ -449,7 +463,7 @@ export const LibraryTasks: React.FC = () => {
|
|||
variant="secondary"
|
||||
type="submit"
|
||||
className="mr-2"
|
||||
onClick={() => setDialogOpen({ autoTagAlert: true })}
|
||||
onClick={onAutoTagClick}
|
||||
>
|
||||
<FormattedMessage id="actions.auto_tag" />…
|
||||
</Button>
|
||||
|
|
@ -468,6 +482,13 @@ export const LibraryTasks: React.FC = () => {
|
|||
options={autoTagOptions}
|
||||
setOptions={onSetAutoTagOptions}
|
||||
/>
|
||||
<BooleanSetting
|
||||
id="disable_auto_tag_warning"
|
||||
headingID="config.tasks.auto_tag.skip_warning.heading"
|
||||
subHeadingID="config.tasks.auto_tag.skip_warning.description"
|
||||
checked={iface.disableAutoTagWarning ?? undefined}
|
||||
onChange={(v) => saveInterface({ disableAutoTagWarning: v })}
|
||||
/>
|
||||
</SettingGroup>
|
||||
</SettingSection>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
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 { useConfigureInterface } from "src/core/StashService";
|
||||
import { SettingStateContext } from "src/components/Settings/context";
|
||||
import { ModalComponent } from "./Modal";
|
||||
import { Icon } from "./Icon";
|
||||
|
||||
|
|
@ -31,6 +34,34 @@ export const AutoTagConfirmDialog: React.FC<IAutoTagConfirmDialog> = ({
|
|||
onCancel,
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
const [dontShowAgain, setDontShowAgain] = useState(false);
|
||||
const [configureInterface] = useConfigureInterface();
|
||||
|
||||
useEffect(() => {
|
||||
if (show) {
|
||||
setDontShowAgain(false);
|
||||
}
|
||||
}, [show]);
|
||||
// route through SettingsContext when available so the Settings panel's
|
||||
// local state reflects the change without a page refresh
|
||||
const settingsContext = useContext(SettingStateContext);
|
||||
|
||||
async function handleConfirm() {
|
||||
if (dontShowAgain) {
|
||||
try {
|
||||
if (settingsContext) {
|
||||
settingsContext.saveInterface({ disableAutoTagWarning: true });
|
||||
} else {
|
||||
await configureInterface({
|
||||
variables: { input: { disableAutoTagWarning: true } },
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
// preference persistence failure must not block the confirmed action
|
||||
}
|
||||
}
|
||||
onConfirm();
|
||||
}
|
||||
|
||||
return (
|
||||
<ModalComponent
|
||||
|
|
@ -40,13 +71,21 @@ export const AutoTagConfirmDialog: React.FC<IAutoTagConfirmDialog> = ({
|
|||
accept={{
|
||||
text: intl.formatMessage({ id: "actions.confirm" }),
|
||||
variant: "danger",
|
||||
onClick: onConfirm,
|
||||
onClick: handleConfirm,
|
||||
}}
|
||||
cancel={{
|
||||
onClick: onCancel,
|
||||
}}
|
||||
>
|
||||
<AutoTagWarning />
|
||||
<Form.Check
|
||||
id="auto-tag-dont-show-again"
|
||||
checked={dontShowAgain}
|
||||
onChange={(e) => setDontShowAgain(e.currentTarget.checked)}
|
||||
label={intl.formatMessage({
|
||||
id: "dialogs.dont_show_again",
|
||||
})}
|
||||
/>
|
||||
</ModalComponent>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { Button, Dropdown, Modal, SplitButton } from "react-bootstrap";
|
||||
import React, { useState } from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
import { useConfigurationContext } from "src/hooks/Config";
|
||||
import { ImageInput } from "./ImageInput";
|
||||
import { AutoTagConfirmDialog } from "./AutoTagConfirmDialog";
|
||||
import cx from "classnames";
|
||||
|
|
@ -30,9 +31,23 @@ interface IProps {
|
|||
|
||||
export const DetailsEditNavbar: React.FC<IProps> = (props: IProps) => {
|
||||
const intl = useIntl();
|
||||
const { configuration } = useConfigurationContext();
|
||||
const [isDeleteAlertOpen, setIsDeleteAlertOpen] = useState<boolean>(false);
|
||||
const [isAutoTagAlertOpen, setIsAutoTagAlertOpen] = useState<boolean>(false);
|
||||
|
||||
const skipAutoTagWarning =
|
||||
configuration?.interface.disableAutoTagWarning ?? false;
|
||||
|
||||
function onAutoTagClick() {
|
||||
if (skipAutoTagWarning) {
|
||||
if (props.onAutoTag) {
|
||||
props.onAutoTag();
|
||||
}
|
||||
return;
|
||||
}
|
||||
setIsAutoTagAlertOpen(true);
|
||||
}
|
||||
|
||||
function renderEditButton() {
|
||||
if (props.isNew) return;
|
||||
return (
|
||||
|
|
@ -116,7 +131,7 @@ export const DetailsEditNavbar: React.FC<IProps> = (props: IProps) => {
|
|||
<Button
|
||||
variant="secondary"
|
||||
disabled={props.autoTagDisabled}
|
||||
onClick={() => setIsAutoTagAlertOpen(true)}
|
||||
onClick={onAutoTagClick}
|
||||
>
|
||||
<FormattedMessage id="actions.auto_tag" />…
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
### Skip the confirmation warning
|
||||
|
||||
A confirmation warning is shown before Auto tag runs. If you use Auto tag frequently you can bypass this warning by ticking the **Don't show this warning again** checkbox on the warning dialog, or by enabling **Settings → Tasks → Auto Tag → Skip auto tag warning**.
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
"skip_warning": {
|
||||
"description": "Skip the confirmation warning shown before running auto tag.",
|
||||
"heading": "Skip 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}}}",
|
||||
|
|
|
|||
Loading…
Reference in a new issue