mirror of
https://github.com/stashapp/stash.git
synced 2025-12-17 12:24:38 +03:00
Add delete file and generated files by default config options (#1852)
* add delete file and generated files by default config options * add alert message with files to be deleted Co-authored-by: WithoutPants <53250216+WithoutPants@users.noreply.github.com>
This commit is contained in:
@@ -116,6 +116,9 @@ fragment ConfigDefaultSettingsData on ConfigDefaultSettingsResult {
|
|||||||
...IdentifyMetadataOptionsData
|
...IdentifyMetadataOptionsData
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
deleteFile
|
||||||
|
deleteGenerated
|
||||||
}
|
}
|
||||||
|
|
||||||
fragment ConfigData on ConfigResult {
|
fragment ConfigData on ConfigResult {
|
||||||
|
|||||||
@@ -304,10 +304,20 @@ type ConfigScrapingResult {
|
|||||||
|
|
||||||
type ConfigDefaultSettingsResult {
|
type ConfigDefaultSettingsResult {
|
||||||
identify: IdentifyMetadataTaskOptions
|
identify: IdentifyMetadataTaskOptions
|
||||||
|
|
||||||
|
"""If true, delete file checkbox will be checked by default"""
|
||||||
|
deleteFile: Boolean
|
||||||
|
"""If true, delete generated supporting files checkbox will be checked by default"""
|
||||||
|
deleteGenerated: Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
input ConfigDefaultSettingsInput {
|
input ConfigDefaultSettingsInput {
|
||||||
identify: IdentifyMetadataInput
|
identify: IdentifyMetadataInput
|
||||||
|
|
||||||
|
"""If true, delete file checkbox will be checked by default"""
|
||||||
|
deleteFile: Boolean
|
||||||
|
"""If true, delete generated files checkbox will be checked by default"""
|
||||||
|
deleteGenerated: Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
"""All configuration settings"""
|
"""All configuration settings"""
|
||||||
|
|||||||
@@ -359,6 +359,14 @@ func (r *mutationResolver) ConfigureDefaults(ctx context.Context, input models.C
|
|||||||
c.Set(config.DefaultIdentifySettings, input.Identify)
|
c.Set(config.DefaultIdentifySettings, input.Identify)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if input.DeleteFile != nil {
|
||||||
|
c.Set(config.DeleteFileDefault, *input.DeleteFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
if input.DeleteGenerated != nil {
|
||||||
|
c.Set(config.DeleteGeneratedDefault, *input.DeleteGenerated)
|
||||||
|
}
|
||||||
|
|
||||||
if err := c.Write(); err != nil {
|
if err := c.Write(); err != nil {
|
||||||
return makeConfigDefaultsResult(), err
|
return makeConfigDefaultsResult(), err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -163,8 +163,12 @@ func makeConfigScrapingResult() *models.ConfigScrapingResult {
|
|||||||
|
|
||||||
func makeConfigDefaultsResult() *models.ConfigDefaultSettingsResult {
|
func makeConfigDefaultsResult() *models.ConfigDefaultSettingsResult {
|
||||||
config := config.GetInstance()
|
config := config.GetInstance()
|
||||||
|
deleteFileDefault := config.GetDeleteFileDefault()
|
||||||
|
deleteGeneratedDefault := config.GetDeleteGeneratedDefault()
|
||||||
|
|
||||||
return &models.ConfigDefaultSettingsResult{
|
return &models.ConfigDefaultSettingsResult{
|
||||||
Identify: config.GetDefaultIdentifySettings(),
|
Identify: config.GetDefaultIdentifySettings(),
|
||||||
|
DeleteFile: &deleteFileDefault,
|
||||||
|
DeleteGenerated: &deleteGeneratedDefault,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -147,6 +147,9 @@ const FunscriptOffset = "funscript_offset"
|
|||||||
// Default settings
|
// Default settings
|
||||||
const (
|
const (
|
||||||
DefaultIdentifySettings = "defaults.identify_task"
|
DefaultIdentifySettings = "defaults.identify_task"
|
||||||
|
|
||||||
|
DeleteFileDefault = "defaults.delete_file"
|
||||||
|
DeleteGeneratedDefault = "defaults.delete_generated"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Security
|
// Security
|
||||||
@@ -880,6 +883,20 @@ func (i *Instance) GetFunscriptOffset() int {
|
|||||||
return viper.GetInt(FunscriptOffset)
|
return viper.GetInt(FunscriptOffset)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i *Instance) GetDeleteFileDefault() bool {
|
||||||
|
i.Lock()
|
||||||
|
defer i.Unlock()
|
||||||
|
viper.SetDefault(DeleteFileDefault, false)
|
||||||
|
return viper.GetBool(DeleteFileDefault)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Instance) GetDeleteGeneratedDefault() bool {
|
||||||
|
i.Lock()
|
||||||
|
defer i.Unlock()
|
||||||
|
viper.SetDefault(DeleteGeneratedDefault, true)
|
||||||
|
return viper.GetBool(DeleteGeneratedDefault)
|
||||||
|
}
|
||||||
|
|
||||||
// GetDefaultIdentifySettings returns the default Identify task settings.
|
// GetDefaultIdentifySettings returns the default Identify task settings.
|
||||||
// Returns nil if the settings could not be unmarshalled, or if it
|
// Returns nil if the settings could not be unmarshalled, or if it
|
||||||
// has not been set.
|
// has not been set.
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
### ✨ New Features
|
### ✨ New Features
|
||||||
|
* Support setting defaults for Delete File and Delete Generated Files in the Interface Settings. ([#1852](https://github.com/stashapp/stash/pull/1852))
|
||||||
* Added Identify task to automatically identify scenes from stash-box/scraper sources. See manual entry for details. ([#1839](https://github.com/stashapp/stash/pull/1839))
|
* Added Identify task to automatically identify scenes from stash-box/scraper sources. See manual entry for details. ([#1839](https://github.com/stashapp/stash/pull/1839))
|
||||||
* Added support for matching scenes using perceptual hashes when querying stash-box. ([#1858](https://github.com/stashapp/stash/pull/1858))
|
* Added support for matching scenes using perceptual hashes when querying stash-box. ([#1858](https://github.com/stashapp/stash/pull/1858))
|
||||||
* Generalised Tagger view to support tagging using supported scene scrapers. ([#1812](https://github.com/stashapp/stash/pull/1812))
|
* Generalised Tagger view to support tagging using supported scene scrapers. ([#1812](https://github.com/stashapp/stash/pull/1812))
|
||||||
@@ -6,6 +7,7 @@
|
|||||||
* Added interface options to disable creating performers/studios/tags from dropdown selectors. ([#1814](https://github.com/stashapp/stash/pull/1814))
|
* Added interface options to disable creating performers/studios/tags from dropdown selectors. ([#1814](https://github.com/stashapp/stash/pull/1814))
|
||||||
|
|
||||||
### 🎨 Improvements
|
### 🎨 Improvements
|
||||||
|
* Show files being deleted in the Delete dialogs. ([#1852](https://github.com/stashapp/stash/pull/1852))
|
||||||
* Added specific page titles. ([#1831](https://github.com/stashapp/stash/pull/1831))
|
* Added specific page titles. ([#1831](https://github.com/stashapp/stash/pull/1831))
|
||||||
* Added es-ES language option. ([#1886](https://github.com/stashapp/stash/pull/1886))
|
* Added es-ES language option. ([#1886](https://github.com/stashapp/stash/pull/1886))
|
||||||
* Show pagination at top and bottom of page. ([#1776](https://github.com/stashapp/stash/pull/1776))
|
* Show pagination at top and bottom of page. ([#1776](https://github.com/stashapp/stash/pull/1776))
|
||||||
|
|||||||
@@ -4,10 +4,11 @@ import { useGalleryDestroy } from "src/core/StashService";
|
|||||||
import * as GQL from "src/core/generated-graphql";
|
import * as GQL from "src/core/generated-graphql";
|
||||||
import { Modal } from "src/components/Shared";
|
import { Modal } from "src/components/Shared";
|
||||||
import { useToast } from "src/hooks";
|
import { useToast } from "src/hooks";
|
||||||
import { useIntl } from "react-intl";
|
import { ConfigurationContext } from "src/hooks/Config";
|
||||||
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
|
||||||
interface IDeleteGalleryDialogProps {
|
interface IDeleteGalleryDialogProps {
|
||||||
selected: Pick<GQL.Gallery, "id">[];
|
selected: GQL.SlimGalleryDataFragment[];
|
||||||
onClose: (confirmed: boolean) => void;
|
onClose: (confirmed: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,8 +32,14 @@ export const DeleteGalleriesDialog: React.FC<IDeleteGalleryDialogProps> = (
|
|||||||
{ count: props.selected.length, singularEntity, pluralEntity }
|
{ count: props.selected.length, singularEntity, pluralEntity }
|
||||||
);
|
);
|
||||||
|
|
||||||
const [deleteFile, setDeleteFile] = useState<boolean>(false);
|
const { configuration: config } = React.useContext(ConfigurationContext);
|
||||||
const [deleteGenerated, setDeleteGenerated] = useState<boolean>(true);
|
|
||||||
|
const [deleteFile, setDeleteFile] = useState<boolean>(
|
||||||
|
config?.defaults.deleteFile ?? false
|
||||||
|
);
|
||||||
|
const [deleteGenerated, setDeleteGenerated] = useState<boolean>(
|
||||||
|
config?.defaults.deleteGenerated ?? true
|
||||||
|
);
|
||||||
|
|
||||||
const Toast = useToast();
|
const Toast = useToast();
|
||||||
const [deleteGallery] = useGalleryDestroy(getGalleriesDeleteInput());
|
const [deleteGallery] = useGalleryDestroy(getGalleriesDeleteInput());
|
||||||
@@ -60,6 +67,50 @@ export const DeleteGalleriesDialog: React.FC<IDeleteGalleryDialogProps> = (
|
|||||||
props.onClose(true);
|
props.onClose(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function maybeRenderDeleteFileAlert() {
|
||||||
|
if (!deleteFile) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fsGalleries = props.selected.filter((g) => g.path);
|
||||||
|
if (fsGalleries.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="delete-dialog alert alert-danger text-break">
|
||||||
|
<p className="font-weight-bold">
|
||||||
|
<FormattedMessage
|
||||||
|
values={{
|
||||||
|
count: fsGalleries.length,
|
||||||
|
singularEntity: intl.formatMessage({ id: "file" }),
|
||||||
|
pluralEntity: intl.formatMessage({ id: "files" }),
|
||||||
|
}}
|
||||||
|
id="dialogs.delete_alert"
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
{fsGalleries.slice(0, 5).map((s) => (
|
||||||
|
<li key={s.path}>{s.path}</li>
|
||||||
|
))}
|
||||||
|
{fsGalleries.length > 5 && (
|
||||||
|
<FormattedMessage
|
||||||
|
values={{
|
||||||
|
count: fsGalleries.length - 5,
|
||||||
|
singularEntity: intl.formatMessage({ id: "file" }),
|
||||||
|
pluralEntity: intl.formatMessage({ id: "files" }),
|
||||||
|
}}
|
||||||
|
id="dialogs.delete_object_overflow"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<li>
|
||||||
|
<FormattedMessage id="dialogs.delete_galleries_extra" />
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
show
|
show
|
||||||
@@ -78,6 +129,7 @@ export const DeleteGalleriesDialog: React.FC<IDeleteGalleryDialogProps> = (
|
|||||||
isRunning={isDeleting}
|
isRunning={isDeleting}
|
||||||
>
|
>
|
||||||
<p>{message}</p>
|
<p>{message}</p>
|
||||||
|
{maybeRenderDeleteFileAlert()}
|
||||||
<Form>
|
<Form>
|
||||||
<Form.Check
|
<Form.Check
|
||||||
id="delete-file"
|
id="delete-file"
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ export const GalleryPage: React.FC<IProps> = ({ gallery }) => {
|
|||||||
if (isDeleteAlertOpen && gallery) {
|
if (isDeleteAlertOpen && gallery) {
|
||||||
return (
|
return (
|
||||||
<DeleteGalleriesDialog
|
<DeleteGalleriesDialog
|
||||||
selected={[gallery]}
|
selected={[{ ...gallery, image_count: NaN }]}
|
||||||
onClose={onDeleteDialogClosed}
|
onClose={onDeleteDialogClosed}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ import { useImagesDestroy } from "src/core/StashService";
|
|||||||
import * as GQL from "src/core/generated-graphql";
|
import * as GQL from "src/core/generated-graphql";
|
||||||
import { Modal } from "src/components/Shared";
|
import { Modal } from "src/components/Shared";
|
||||||
import { useToast } from "src/hooks";
|
import { useToast } from "src/hooks";
|
||||||
import { useIntl } from "react-intl";
|
import { ConfigurationContext } from "src/hooks/Config";
|
||||||
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
|
||||||
interface IDeleteImageDialogProps {
|
interface IDeleteImageDialogProps {
|
||||||
selected: GQL.SlimImageDataFragment[];
|
selected: GQL.SlimImageDataFragment[];
|
||||||
@@ -31,8 +32,14 @@ export const DeleteImagesDialog: React.FC<IDeleteImageDialogProps> = (
|
|||||||
{ count: props.selected.length, singularEntity, pluralEntity }
|
{ count: props.selected.length, singularEntity, pluralEntity }
|
||||||
);
|
);
|
||||||
|
|
||||||
const [deleteFile, setDeleteFile] = useState<boolean>(false);
|
const { configuration: config } = React.useContext(ConfigurationContext);
|
||||||
const [deleteGenerated, setDeleteGenerated] = useState<boolean>(true);
|
|
||||||
|
const [deleteFile, setDeleteFile] = useState<boolean>(
|
||||||
|
config?.defaults.deleteFile ?? false
|
||||||
|
);
|
||||||
|
const [deleteGenerated, setDeleteGenerated] = useState<boolean>(
|
||||||
|
config?.defaults.deleteGenerated ?? true
|
||||||
|
);
|
||||||
|
|
||||||
const Toast = useToast();
|
const Toast = useToast();
|
||||||
const [deleteImage] = useImagesDestroy(getImagesDeleteInput());
|
const [deleteImage] = useImagesDestroy(getImagesDeleteInput());
|
||||||
@@ -60,6 +67,42 @@ export const DeleteImagesDialog: React.FC<IDeleteImageDialogProps> = (
|
|||||||
props.onClose(true);
|
props.onClose(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function maybeRenderDeleteFileAlert() {
|
||||||
|
if (!deleteFile) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="delete-dialog alert alert-danger text-break">
|
||||||
|
<p className="font-weight-bold">
|
||||||
|
<FormattedMessage
|
||||||
|
values={{
|
||||||
|
count: props.selected.length,
|
||||||
|
singularEntity: intl.formatMessage({ id: "file" }),
|
||||||
|
pluralEntity: intl.formatMessage({ id: "files" }),
|
||||||
|
}}
|
||||||
|
id="dialogs.delete_alert"
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
{props.selected.slice(0, 5).map((s) => (
|
||||||
|
<li key={s.path}>{s.path}</li>
|
||||||
|
))}
|
||||||
|
{props.selected.length > 5 && (
|
||||||
|
<FormattedMessage
|
||||||
|
values={{
|
||||||
|
count: props.selected.length - 5,
|
||||||
|
singularEntity: intl.formatMessage({ id: "file" }),
|
||||||
|
pluralEntity: intl.formatMessage({ id: "files" }),
|
||||||
|
}}
|
||||||
|
id="dialogs.delete_object_overflow"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
show
|
show
|
||||||
@@ -78,6 +121,7 @@ export const DeleteImagesDialog: React.FC<IDeleteImageDialogProps> = (
|
|||||||
isRunning={isDeleting}
|
isRunning={isDeleting}
|
||||||
>
|
>
|
||||||
<p>{message}</p>
|
<p>{message}</p>
|
||||||
|
{maybeRenderDeleteFileAlert()}
|
||||||
<Form>
|
<Form>
|
||||||
<Form.Check
|
<Form.Check
|
||||||
id="delete-image"
|
id="delete-image"
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ import { useScenesDestroy } from "src/core/StashService";
|
|||||||
import * as GQL from "src/core/generated-graphql";
|
import * as GQL from "src/core/generated-graphql";
|
||||||
import { Modal } from "src/components/Shared";
|
import { Modal } from "src/components/Shared";
|
||||||
import { useToast } from "src/hooks";
|
import { useToast } from "src/hooks";
|
||||||
import { useIntl } from "react-intl";
|
import { ConfigurationContext } from "src/hooks/Config";
|
||||||
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
|
||||||
interface IDeleteSceneDialogProps {
|
interface IDeleteSceneDialogProps {
|
||||||
selected: GQL.SlimSceneDataFragment[];
|
selected: GQL.SlimSceneDataFragment[];
|
||||||
@@ -31,8 +32,14 @@ export const DeleteScenesDialog: React.FC<IDeleteSceneDialogProps> = (
|
|||||||
{ count: props.selected.length, singularEntity, pluralEntity }
|
{ count: props.selected.length, singularEntity, pluralEntity }
|
||||||
);
|
);
|
||||||
|
|
||||||
const [deleteFile, setDeleteFile] = useState<boolean>(false);
|
const { configuration: config } = React.useContext(ConfigurationContext);
|
||||||
const [deleteGenerated, setDeleteGenerated] = useState<boolean>(true);
|
|
||||||
|
const [deleteFile, setDeleteFile] = useState<boolean>(
|
||||||
|
config?.defaults.deleteFile ?? false
|
||||||
|
);
|
||||||
|
const [deleteGenerated, setDeleteGenerated] = useState<boolean>(
|
||||||
|
config?.defaults.deleteGenerated ?? true
|
||||||
|
);
|
||||||
|
|
||||||
const Toast = useToast();
|
const Toast = useToast();
|
||||||
const [deleteScene] = useScenesDestroy(getScenesDeleteInput());
|
const [deleteScene] = useScenesDestroy(getScenesDeleteInput());
|
||||||
@@ -60,6 +67,42 @@ export const DeleteScenesDialog: React.FC<IDeleteSceneDialogProps> = (
|
|||||||
props.onClose(true);
|
props.onClose(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function maybeRenderDeleteFileAlert() {
|
||||||
|
if (!deleteFile) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="delete-dialog alert alert-danger text-break">
|
||||||
|
<p className="font-weight-bold">
|
||||||
|
<FormattedMessage
|
||||||
|
values={{
|
||||||
|
count: props.selected.length,
|
||||||
|
singularEntity: intl.formatMessage({ id: "file" }),
|
||||||
|
pluralEntity: intl.formatMessage({ id: "files" }),
|
||||||
|
}}
|
||||||
|
id="dialogs.delete_alert"
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
{props.selected.slice(0, 5).map((s) => (
|
||||||
|
<li key={s.path}>{s.path}</li>
|
||||||
|
))}
|
||||||
|
{props.selected.length > 5 && (
|
||||||
|
<FormattedMessage
|
||||||
|
values={{
|
||||||
|
count: props.selected.length - 5,
|
||||||
|
singularEntity: intl.formatMessage({ id: "file" }),
|
||||||
|
pluralEntity: intl.formatMessage({ id: "files" }),
|
||||||
|
}}
|
||||||
|
id="dialogs.delete_object_overflow"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
show
|
show
|
||||||
@@ -78,6 +121,7 @@ export const DeleteScenesDialog: React.FC<IDeleteSceneDialogProps> = (
|
|||||||
isRunning={isDeleting}
|
isRunning={isDeleting}
|
||||||
>
|
>
|
||||||
<p>{message}</p>
|
<p>{message}</p>
|
||||||
|
{maybeRenderDeleteFileAlert()}
|
||||||
<Form>
|
<Form>
|
||||||
<Form.Check
|
<Form.Check
|
||||||
id="delete-file"
|
id="delete-file"
|
||||||
|
|||||||
@@ -2,10 +2,15 @@ import React, { useEffect, useState } from "react";
|
|||||||
import { Button, Form } from "react-bootstrap";
|
import { Button, Form } from "react-bootstrap";
|
||||||
import { useIntl } from "react-intl";
|
import { useIntl } from "react-intl";
|
||||||
import { DurationInput, LoadingIndicator } from "src/components/Shared";
|
import { DurationInput, LoadingIndicator } from "src/components/Shared";
|
||||||
import { useConfiguration, useConfigureInterface } from "src/core/StashService";
|
import {
|
||||||
|
useConfiguration,
|
||||||
|
useConfigureDefaults,
|
||||||
|
useConfigureInterface,
|
||||||
|
} from "src/core/StashService";
|
||||||
import { useToast } from "src/hooks";
|
import { useToast } from "src/hooks";
|
||||||
import * as GQL from "src/core/generated-graphql";
|
import * as GQL from "src/core/generated-graphql";
|
||||||
import { CheckboxGroup } from "./CheckboxGroup";
|
import { CheckboxGroup } from "./CheckboxGroup";
|
||||||
|
import { withoutTypename } from "src/utils";
|
||||||
|
|
||||||
const allMenuItems = [
|
const allMenuItems = [
|
||||||
{ id: "scenes", label: "Scenes" },
|
{ id: "scenes", label: "Scenes" },
|
||||||
@@ -39,6 +44,10 @@ export const SettingsInterfacePanel: React.FC = () => {
|
|||||||
const [language, setLanguage] = useState<string>("en");
|
const [language, setLanguage] = useState<string>("en");
|
||||||
const [handyKey, setHandyKey] = useState<string>();
|
const [handyKey, setHandyKey] = useState<string>();
|
||||||
const [funscriptOffset, setFunscriptOffset] = useState<number>(0);
|
const [funscriptOffset, setFunscriptOffset] = useState<number>(0);
|
||||||
|
const [deleteFileDefault, setDeleteFileDefault] = useState<boolean>(false);
|
||||||
|
const [deleteGeneratedDefault, setDeleteGeneratedDefault] = useState<boolean>(
|
||||||
|
true
|
||||||
|
);
|
||||||
const [
|
const [
|
||||||
disableDropdownCreate,
|
disableDropdownCreate,
|
||||||
setDisableDropdownCreate,
|
setDisableDropdownCreate,
|
||||||
@@ -61,35 +70,51 @@ export const SettingsInterfacePanel: React.FC = () => {
|
|||||||
disableDropdownCreate,
|
disableDropdownCreate,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const [updateDefaultsConfig] = useConfigureDefaults();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const iCfg = config?.configuration?.interface;
|
if (config) {
|
||||||
setMenuItemIds(iCfg?.menuItems ?? allMenuItems.map((item) => item.id));
|
const { interface: iCfg, defaults } = config.configuration;
|
||||||
setSoundOnPreview(iCfg?.soundOnPreview ?? true);
|
setMenuItemIds(iCfg.menuItems ?? allMenuItems.map((item) => item.id));
|
||||||
setWallShowTitle(iCfg?.wallShowTitle ?? true);
|
setSoundOnPreview(iCfg.soundOnPreview ?? true);
|
||||||
setWallPlayback(iCfg?.wallPlayback ?? "video");
|
setWallShowTitle(iCfg.wallShowTitle ?? true);
|
||||||
setMaximumLoopDuration(iCfg?.maximumLoopDuration ?? 0);
|
setWallPlayback(iCfg.wallPlayback ?? "video");
|
||||||
setAutostartVideo(iCfg?.autostartVideo ?? false);
|
setMaximumLoopDuration(iCfg.maximumLoopDuration ?? 0);
|
||||||
setShowStudioAsText(iCfg?.showStudioAsText ?? false);
|
setAutostartVideo(iCfg.autostartVideo ?? false);
|
||||||
setCSS(iCfg?.css ?? "");
|
setShowStudioAsText(iCfg.showStudioAsText ?? false);
|
||||||
setCSSEnabled(iCfg?.cssEnabled ?? false);
|
setCSS(iCfg.css ?? "");
|
||||||
setLanguage(iCfg?.language ?? "en-US");
|
setCSSEnabled(iCfg.cssEnabled ?? false);
|
||||||
setSlideshowDelay(iCfg?.slideshowDelay ?? 5000);
|
setLanguage(iCfg.language ?? "en-US");
|
||||||
setHandyKey(iCfg?.handyKey ?? "");
|
setSlideshowDelay(iCfg.slideshowDelay ?? 5000);
|
||||||
setFunscriptOffset(iCfg?.funscriptOffset ?? 0);
|
setHandyKey(iCfg.handyKey ?? "");
|
||||||
setDisableDropdownCreate({
|
setFunscriptOffset(iCfg.funscriptOffset ?? 0);
|
||||||
performer: iCfg?.disabledDropdownCreate.performer,
|
setDisableDropdownCreate({
|
||||||
studio: iCfg?.disabledDropdownCreate.studio,
|
performer: iCfg.disabledDropdownCreate.performer,
|
||||||
tag: iCfg?.disabledDropdownCreate.tag,
|
studio: iCfg.disabledDropdownCreate.studio,
|
||||||
});
|
tag: iCfg.disabledDropdownCreate.tag,
|
||||||
|
});
|
||||||
|
|
||||||
|
setDeleteFileDefault(defaults.deleteFile ?? false);
|
||||||
|
setDeleteGeneratedDefault(defaults.deleteGenerated ?? true);
|
||||||
|
}
|
||||||
}, [config]);
|
}, [config]);
|
||||||
|
|
||||||
async function onSave() {
|
async function onSave() {
|
||||||
const prevCSS = config?.configuration.interface.css;
|
const prevCSS = config?.configuration.interface.css;
|
||||||
const prevCSSenabled = config?.configuration.interface.cssEnabled;
|
const prevCSSenabled = config?.configuration.interface.cssEnabled;
|
||||||
try {
|
try {
|
||||||
|
if (config?.configuration.defaults) {
|
||||||
|
await updateDefaultsConfig({
|
||||||
|
variables: {
|
||||||
|
input: {
|
||||||
|
...withoutTypename(config?.configuration.defaults),
|
||||||
|
deleteFile: deleteFileDefault,
|
||||||
|
deleteGenerated: deleteGeneratedDefault,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
const result = await updateInterfaceConfig();
|
const result = await updateInterfaceConfig();
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.log(result);
|
|
||||||
|
|
||||||
// Force refetch of custom css if it was changed
|
// Force refetch of custom css if it was changed
|
||||||
if (
|
if (
|
||||||
@@ -389,6 +414,38 @@ export const SettingsInterfacePanel: React.FC = () => {
|
|||||||
</Form.Text>
|
</Form.Text>
|
||||||
</Form.Group>
|
</Form.Group>
|
||||||
|
|
||||||
|
<Form.Group>
|
||||||
|
<h5>
|
||||||
|
{intl.formatMessage({ id: "config.ui.delete_options.heading" })}
|
||||||
|
</h5>
|
||||||
|
<Form.Check
|
||||||
|
id="delete-file-default"
|
||||||
|
checked={deleteFileDefault}
|
||||||
|
label={intl.formatMessage({
|
||||||
|
id: "config.ui.delete_options.options.delete_file",
|
||||||
|
})}
|
||||||
|
onChange={() => {
|
||||||
|
setDeleteFileDefault(!deleteFileDefault);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Form.Check
|
||||||
|
id="delete-generated-default"
|
||||||
|
checked={deleteGeneratedDefault}
|
||||||
|
label={intl.formatMessage({
|
||||||
|
id:
|
||||||
|
"config.ui.delete_options.options.delete_generated_supporting_files",
|
||||||
|
})}
|
||||||
|
onChange={() => {
|
||||||
|
setDeleteGeneratedDefault(!deleteGeneratedDefault);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Form.Text className="text-muted">
|
||||||
|
{intl.formatMessage({
|
||||||
|
id: "config.ui.delete_options.description",
|
||||||
|
})}
|
||||||
|
</Form.Text>
|
||||||
|
</Form.Group>
|
||||||
|
|
||||||
<hr />
|
<hr />
|
||||||
<Button variant="primary" onClick={() => onSave()}>
|
<Button variant="primary" onClick={() => onSave()}>
|
||||||
{intl.formatMessage({ id: "actions.save" })}
|
{intl.formatMessage({ id: "actions.save" })}
|
||||||
|
|||||||
@@ -61,6 +61,7 @@
|
|||||||
"reshuffle": "Reshuffle",
|
"reshuffle": "Reshuffle",
|
||||||
"running": "running",
|
"running": "running",
|
||||||
"save": "Save",
|
"save": "Save",
|
||||||
|
"save_delete_settings": "Use these options by default when deleting",
|
||||||
"save_filter": "Save filter",
|
"save_filter": "Save filter",
|
||||||
"scan": "Scan",
|
"scan": "Scan",
|
||||||
"scrape_with": "Scrape with…",
|
"scrape_with": "Scrape with…",
|
||||||
@@ -364,6 +365,14 @@
|
|||||||
"heading": "Custom CSS",
|
"heading": "Custom CSS",
|
||||||
"option_label": "Custom CSS enabled"
|
"option_label": "Custom CSS enabled"
|
||||||
},
|
},
|
||||||
|
"delete_options": {
|
||||||
|
"description": "Default settings when deleting images, galleries, and scenes.",
|
||||||
|
"heading": "Delete Options",
|
||||||
|
"options": {
|
||||||
|
"delete_file": "Delete file by default",
|
||||||
|
"delete_generated_supporting_files": "Delete generated supporting files by default"
|
||||||
|
}
|
||||||
|
},
|
||||||
"editing": {
|
"editing": {
|
||||||
"disable_dropdown_create": {
|
"disable_dropdown_create": {
|
||||||
"heading": "Disable dropdown create",
|
"heading": "Disable dropdown create",
|
||||||
@@ -485,12 +494,14 @@
|
|||||||
"details": "Details",
|
"details": "Details",
|
||||||
"developmentVersion": "Development Version",
|
"developmentVersion": "Development Version",
|
||||||
"dialogs": {
|
"dialogs": {
|
||||||
|
"delete_alert": "The following {count, plural, one {{singularEntity}} other {{pluralEntity}}} will be deleted permanently:",
|
||||||
"delete_confirm": "Are you sure you want to delete {entityName}?",
|
"delete_confirm": "Are you sure you want to delete {entityName}?",
|
||||||
"delete_entity_desc": "{count, plural, one {Are you sure you want to delete this {singularEntity}? Unless the file is also deleted, this {singularEntity} will be re-added when scan is performed.} other {Are you sure you want to delete these {pluralEntity}? Unless the files are also deleted, these {pluralEntity} will be re-added when scan is performed.}}",
|
"delete_entity_desc": "{count, plural, one {Are you sure you want to delete this {singularEntity}? Unless the file is also deleted, this {singularEntity} will be re-added when scan is performed.} other {Are you sure you want to delete these {pluralEntity}? Unless the files are also deleted, these {pluralEntity} will be re-added when scan is performed.}}",
|
||||||
"delete_entity_title": "{count, plural, one {Delete {singularEntity}} other {Delete {pluralEntity}}}",
|
"delete_entity_title": "{count, plural, one {Delete {singularEntity}} other {Delete {pluralEntity}}}",
|
||||||
"delete_object_desc": "Are you sure you want to delete {count, plural, one {this {singularEntity}} other {these {pluralEntity}}}?",
|
"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_overflow": "…and {count} other {count, plural, one {{singularEntity}} other {{pluralEntity}}}.",
|
||||||
"delete_object_title": "Delete {count, plural, one {{singularEntity}} other {{pluralEntity}}}",
|
"delete_object_title": "Delete {count, plural, one {{singularEntity}} other {{pluralEntity}}}",
|
||||||
|
"delete_galleries_extra": "…plus any image files not attached to any other gallery.",
|
||||||
"edit_entity_title": "Edit {count, plural, one {{singularEntity}} other {{pluralEntity}}}",
|
"edit_entity_title": "Edit {count, plural, one {{singularEntity}} other {{pluralEntity}}}",
|
||||||
"export_include_related_objects": "Include related objects in export",
|
"export_include_related_objects": "Include related objects in export",
|
||||||
"export_title": "Export",
|
"export_title": "Export",
|
||||||
@@ -600,6 +611,8 @@
|
|||||||
"fake_tits": "Fake Tits",
|
"fake_tits": "Fake Tits",
|
||||||
"false": "False",
|
"false": "False",
|
||||||
"favourite": "Favourite",
|
"favourite": "Favourite",
|
||||||
|
"file": "file",
|
||||||
|
"files": "files",
|
||||||
"file_info": "File Info",
|
"file_info": "File Info",
|
||||||
"file_mod_time": "File Modification Time",
|
"file_mod_time": "File Modification Time",
|
||||||
"filesize": "File Size",
|
"filesize": "File Size",
|
||||||
|
|||||||
Reference in New Issue
Block a user