mirror of
https://github.com/stashapp/stash.git
synced 2025-12-17 20:34:37 +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
|
||||
}
|
||||
}
|
||||
|
||||
deleteFile
|
||||
deleteGenerated
|
||||
}
|
||||
|
||||
fragment ConfigData on ConfigResult {
|
||||
|
||||
@@ -304,10 +304,20 @@ type ConfigScrapingResult {
|
||||
|
||||
type ConfigDefaultSettingsResult {
|
||||
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 {
|
||||
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"""
|
||||
|
||||
@@ -359,6 +359,14 @@ func (r *mutationResolver) ConfigureDefaults(ctx context.Context, input models.C
|
||||
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 {
|
||||
return makeConfigDefaultsResult(), err
|
||||
}
|
||||
|
||||
@@ -163,8 +163,12 @@ func makeConfigScrapingResult() *models.ConfigScrapingResult {
|
||||
|
||||
func makeConfigDefaultsResult() *models.ConfigDefaultSettingsResult {
|
||||
config := config.GetInstance()
|
||||
deleteFileDefault := config.GetDeleteFileDefault()
|
||||
deleteGeneratedDefault := config.GetDeleteGeneratedDefault()
|
||||
|
||||
return &models.ConfigDefaultSettingsResult{
|
||||
Identify: config.GetDefaultIdentifySettings(),
|
||||
DeleteFile: &deleteFileDefault,
|
||||
DeleteGenerated: &deleteGeneratedDefault,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,6 +147,9 @@ const FunscriptOffset = "funscript_offset"
|
||||
// Default settings
|
||||
const (
|
||||
DefaultIdentifySettings = "defaults.identify_task"
|
||||
|
||||
DeleteFileDefault = "defaults.delete_file"
|
||||
DeleteGeneratedDefault = "defaults.delete_generated"
|
||||
)
|
||||
|
||||
// Security
|
||||
@@ -880,6 +883,20 @@ func (i *Instance) GetFunscriptOffset() int {
|
||||
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.
|
||||
// Returns nil if the settings could not be unmarshalled, or if it
|
||||
// has not been set.
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
### ✨ 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 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))
|
||||
@@ -6,6 +7,7 @@
|
||||
* Added interface options to disable creating performers/studios/tags from dropdown selectors. ([#1814](https://github.com/stashapp/stash/pull/1814))
|
||||
|
||||
### 🎨 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 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))
|
||||
|
||||
@@ -4,10 +4,11 @@ import { useGalleryDestroy } from "src/core/StashService";
|
||||
import * as GQL from "src/core/generated-graphql";
|
||||
import { Modal } from "src/components/Shared";
|
||||
import { useToast } from "src/hooks";
|
||||
import { useIntl } from "react-intl";
|
||||
import { ConfigurationContext } from "src/hooks/Config";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
|
||||
interface IDeleteGalleryDialogProps {
|
||||
selected: Pick<GQL.Gallery, "id">[];
|
||||
selected: GQL.SlimGalleryDataFragment[];
|
||||
onClose: (confirmed: boolean) => void;
|
||||
}
|
||||
|
||||
@@ -31,8 +32,14 @@ export const DeleteGalleriesDialog: React.FC<IDeleteGalleryDialogProps> = (
|
||||
{ count: props.selected.length, singularEntity, pluralEntity }
|
||||
);
|
||||
|
||||
const [deleteFile, setDeleteFile] = useState<boolean>(false);
|
||||
const [deleteGenerated, setDeleteGenerated] = useState<boolean>(true);
|
||||
const { configuration: config } = React.useContext(ConfigurationContext);
|
||||
|
||||
const [deleteFile, setDeleteFile] = useState<boolean>(
|
||||
config?.defaults.deleteFile ?? false
|
||||
);
|
||||
const [deleteGenerated, setDeleteGenerated] = useState<boolean>(
|
||||
config?.defaults.deleteGenerated ?? true
|
||||
);
|
||||
|
||||
const Toast = useToast();
|
||||
const [deleteGallery] = useGalleryDestroy(getGalleriesDeleteInput());
|
||||
@@ -60,6 +67,50 @@ export const DeleteGalleriesDialog: React.FC<IDeleteGalleryDialogProps> = (
|
||||
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 (
|
||||
<Modal
|
||||
show
|
||||
@@ -78,6 +129,7 @@ export const DeleteGalleriesDialog: React.FC<IDeleteGalleryDialogProps> = (
|
||||
isRunning={isDeleting}
|
||||
>
|
||||
<p>{message}</p>
|
||||
{maybeRenderDeleteFileAlert()}
|
||||
<Form>
|
||||
<Form.Check
|
||||
id="delete-file"
|
||||
|
||||
@@ -100,7 +100,7 @@ export const GalleryPage: React.FC<IProps> = ({ gallery }) => {
|
||||
if (isDeleteAlertOpen && gallery) {
|
||||
return (
|
||||
<DeleteGalleriesDialog
|
||||
selected={[gallery]}
|
||||
selected={[{ ...gallery, image_count: NaN }]}
|
||||
onClose={onDeleteDialogClosed}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -4,7 +4,8 @@ import { useImagesDestroy } from "src/core/StashService";
|
||||
import * as GQL from "src/core/generated-graphql";
|
||||
import { Modal } from "src/components/Shared";
|
||||
import { useToast } from "src/hooks";
|
||||
import { useIntl } from "react-intl";
|
||||
import { ConfigurationContext } from "src/hooks/Config";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
|
||||
interface IDeleteImageDialogProps {
|
||||
selected: GQL.SlimImageDataFragment[];
|
||||
@@ -31,8 +32,14 @@ export const DeleteImagesDialog: React.FC<IDeleteImageDialogProps> = (
|
||||
{ count: props.selected.length, singularEntity, pluralEntity }
|
||||
);
|
||||
|
||||
const [deleteFile, setDeleteFile] = useState<boolean>(false);
|
||||
const [deleteGenerated, setDeleteGenerated] = useState<boolean>(true);
|
||||
const { configuration: config } = React.useContext(ConfigurationContext);
|
||||
|
||||
const [deleteFile, setDeleteFile] = useState<boolean>(
|
||||
config?.defaults.deleteFile ?? false
|
||||
);
|
||||
const [deleteGenerated, setDeleteGenerated] = useState<boolean>(
|
||||
config?.defaults.deleteGenerated ?? true
|
||||
);
|
||||
|
||||
const Toast = useToast();
|
||||
const [deleteImage] = useImagesDestroy(getImagesDeleteInput());
|
||||
@@ -60,6 +67,42 @@ export const DeleteImagesDialog: React.FC<IDeleteImageDialogProps> = (
|
||||
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 (
|
||||
<Modal
|
||||
show
|
||||
@@ -78,6 +121,7 @@ export const DeleteImagesDialog: React.FC<IDeleteImageDialogProps> = (
|
||||
isRunning={isDeleting}
|
||||
>
|
||||
<p>{message}</p>
|
||||
{maybeRenderDeleteFileAlert()}
|
||||
<Form>
|
||||
<Form.Check
|
||||
id="delete-image"
|
||||
|
||||
@@ -4,7 +4,8 @@ import { useScenesDestroy } from "src/core/StashService";
|
||||
import * as GQL from "src/core/generated-graphql";
|
||||
import { Modal } from "src/components/Shared";
|
||||
import { useToast } from "src/hooks";
|
||||
import { useIntl } from "react-intl";
|
||||
import { ConfigurationContext } from "src/hooks/Config";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
|
||||
interface IDeleteSceneDialogProps {
|
||||
selected: GQL.SlimSceneDataFragment[];
|
||||
@@ -31,8 +32,14 @@ export const DeleteScenesDialog: React.FC<IDeleteSceneDialogProps> = (
|
||||
{ count: props.selected.length, singularEntity, pluralEntity }
|
||||
);
|
||||
|
||||
const [deleteFile, setDeleteFile] = useState<boolean>(false);
|
||||
const [deleteGenerated, setDeleteGenerated] = useState<boolean>(true);
|
||||
const { configuration: config } = React.useContext(ConfigurationContext);
|
||||
|
||||
const [deleteFile, setDeleteFile] = useState<boolean>(
|
||||
config?.defaults.deleteFile ?? false
|
||||
);
|
||||
const [deleteGenerated, setDeleteGenerated] = useState<boolean>(
|
||||
config?.defaults.deleteGenerated ?? true
|
||||
);
|
||||
|
||||
const Toast = useToast();
|
||||
const [deleteScene] = useScenesDestroy(getScenesDeleteInput());
|
||||
@@ -60,6 +67,42 @@ export const DeleteScenesDialog: React.FC<IDeleteSceneDialogProps> = (
|
||||
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 (
|
||||
<Modal
|
||||
show
|
||||
@@ -78,6 +121,7 @@ export const DeleteScenesDialog: React.FC<IDeleteSceneDialogProps> = (
|
||||
isRunning={isDeleting}
|
||||
>
|
||||
<p>{message}</p>
|
||||
{maybeRenderDeleteFileAlert()}
|
||||
<Form>
|
||||
<Form.Check
|
||||
id="delete-file"
|
||||
|
||||
@@ -2,10 +2,15 @@ import React, { useEffect, useState } from "react";
|
||||
import { Button, Form } from "react-bootstrap";
|
||||
import { useIntl } from "react-intl";
|
||||
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 * as GQL from "src/core/generated-graphql";
|
||||
import { CheckboxGroup } from "./CheckboxGroup";
|
||||
import { withoutTypename } from "src/utils";
|
||||
|
||||
const allMenuItems = [
|
||||
{ id: "scenes", label: "Scenes" },
|
||||
@@ -39,6 +44,10 @@ export const SettingsInterfacePanel: React.FC = () => {
|
||||
const [language, setLanguage] = useState<string>("en");
|
||||
const [handyKey, setHandyKey] = useState<string>();
|
||||
const [funscriptOffset, setFunscriptOffset] = useState<number>(0);
|
||||
const [deleteFileDefault, setDeleteFileDefault] = useState<boolean>(false);
|
||||
const [deleteGeneratedDefault, setDeleteGeneratedDefault] = useState<boolean>(
|
||||
true
|
||||
);
|
||||
const [
|
||||
disableDropdownCreate,
|
||||
setDisableDropdownCreate,
|
||||
@@ -61,35 +70,51 @@ export const SettingsInterfacePanel: React.FC = () => {
|
||||
disableDropdownCreate,
|
||||
});
|
||||
|
||||
const [updateDefaultsConfig] = useConfigureDefaults();
|
||||
|
||||
useEffect(() => {
|
||||
const iCfg = config?.configuration?.interface;
|
||||
setMenuItemIds(iCfg?.menuItems ?? allMenuItems.map((item) => item.id));
|
||||
setSoundOnPreview(iCfg?.soundOnPreview ?? true);
|
||||
setWallShowTitle(iCfg?.wallShowTitle ?? true);
|
||||
setWallPlayback(iCfg?.wallPlayback ?? "video");
|
||||
setMaximumLoopDuration(iCfg?.maximumLoopDuration ?? 0);
|
||||
setAutostartVideo(iCfg?.autostartVideo ?? false);
|
||||
setShowStudioAsText(iCfg?.showStudioAsText ?? false);
|
||||
setCSS(iCfg?.css ?? "");
|
||||
setCSSEnabled(iCfg?.cssEnabled ?? false);
|
||||
setLanguage(iCfg?.language ?? "en-US");
|
||||
setSlideshowDelay(iCfg?.slideshowDelay ?? 5000);
|
||||
setHandyKey(iCfg?.handyKey ?? "");
|
||||
setFunscriptOffset(iCfg?.funscriptOffset ?? 0);
|
||||
if (config) {
|
||||
const { interface: iCfg, defaults } = config.configuration;
|
||||
setMenuItemIds(iCfg.menuItems ?? allMenuItems.map((item) => item.id));
|
||||
setSoundOnPreview(iCfg.soundOnPreview ?? true);
|
||||
setWallShowTitle(iCfg.wallShowTitle ?? true);
|
||||
setWallPlayback(iCfg.wallPlayback ?? "video");
|
||||
setMaximumLoopDuration(iCfg.maximumLoopDuration ?? 0);
|
||||
setAutostartVideo(iCfg.autostartVideo ?? false);
|
||||
setShowStudioAsText(iCfg.showStudioAsText ?? false);
|
||||
setCSS(iCfg.css ?? "");
|
||||
setCSSEnabled(iCfg.cssEnabled ?? false);
|
||||
setLanguage(iCfg.language ?? "en-US");
|
||||
setSlideshowDelay(iCfg.slideshowDelay ?? 5000);
|
||||
setHandyKey(iCfg.handyKey ?? "");
|
||||
setFunscriptOffset(iCfg.funscriptOffset ?? 0);
|
||||
setDisableDropdownCreate({
|
||||
performer: iCfg?.disabledDropdownCreate.performer,
|
||||
studio: iCfg?.disabledDropdownCreate.studio,
|
||||
tag: iCfg?.disabledDropdownCreate.tag,
|
||||
performer: iCfg.disabledDropdownCreate.performer,
|
||||
studio: iCfg.disabledDropdownCreate.studio,
|
||||
tag: iCfg.disabledDropdownCreate.tag,
|
||||
});
|
||||
|
||||
setDeleteFileDefault(defaults.deleteFile ?? false);
|
||||
setDeleteGeneratedDefault(defaults.deleteGenerated ?? true);
|
||||
}
|
||||
}, [config]);
|
||||
|
||||
async function onSave() {
|
||||
const prevCSS = config?.configuration.interface.css;
|
||||
const prevCSSenabled = config?.configuration.interface.cssEnabled;
|
||||
try {
|
||||
if (config?.configuration.defaults) {
|
||||
await updateDefaultsConfig({
|
||||
variables: {
|
||||
input: {
|
||||
...withoutTypename(config?.configuration.defaults),
|
||||
deleteFile: deleteFileDefault,
|
||||
deleteGenerated: deleteGeneratedDefault,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
const result = await updateInterfaceConfig();
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(result);
|
||||
|
||||
// Force refetch of custom css if it was changed
|
||||
if (
|
||||
@@ -389,6 +414,38 @@ export const SettingsInterfacePanel: React.FC = () => {
|
||||
</Form.Text>
|
||||
</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 />
|
||||
<Button variant="primary" onClick={() => onSave()}>
|
||||
{intl.formatMessage({ id: "actions.save" })}
|
||||
|
||||
@@ -61,6 +61,7 @@
|
||||
"reshuffle": "Reshuffle",
|
||||
"running": "running",
|
||||
"save": "Save",
|
||||
"save_delete_settings": "Use these options by default when deleting",
|
||||
"save_filter": "Save filter",
|
||||
"scan": "Scan",
|
||||
"scrape_with": "Scrape with…",
|
||||
@@ -364,6 +365,14 @@
|
||||
"heading": "Custom CSS",
|
||||
"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": {
|
||||
"disable_dropdown_create": {
|
||||
"heading": "Disable dropdown create",
|
||||
@@ -485,12 +494,14 @@
|
||||
"details": "Details",
|
||||
"developmentVersion": "Development Version",
|
||||
"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_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_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}}}",
|
||||
"delete_galleries_extra": "…plus any image files not attached to any other gallery.",
|
||||
"edit_entity_title": "Edit {count, plural, one {{singularEntity}} other {{pluralEntity}}}",
|
||||
"export_include_related_objects": "Include related objects in export",
|
||||
"export_title": "Export",
|
||||
@@ -600,6 +611,8 @@
|
||||
"fake_tits": "Fake Tits",
|
||||
"false": "False",
|
||||
"favourite": "Favourite",
|
||||
"file": "file",
|
||||
"files": "files",
|
||||
"file_info": "File Info",
|
||||
"file_mod_time": "File Modification Time",
|
||||
"filesize": "File Size",
|
||||
|
||||
Reference in New Issue
Block a user