mirror of
https://github.com/stashapp/stash.git
synced 2025-12-17 20:34:37 +03:00
Add scene rating to scene filename parser (#432)
* Fix scene parser display issues in 2.5 * Dropdown menu presentation improvements * Fix refresh on parser apply * Ignore line endings on scss files
This commit is contained in:
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -1,3 +1,4 @@
|
|||||||
go.mod text eol=lf
|
go.mod text eol=lf
|
||||||
go.sum text eol=lf
|
go.sum text eol=lf
|
||||||
ui/v2.5/**/*.ts* text eol=lf
|
ui/v2.5/**/*.ts* text eol=lf
|
||||||
|
ui/v2.5/**/*.scss text eol=lf
|
||||||
|
|||||||
@@ -87,6 +87,7 @@ func initParserFields() {
|
|||||||
//I = new ParserField("i", undefined, "Matches any ignored word", false);
|
//I = new ParserField("i", undefined, "Matches any ignored word", false);
|
||||||
|
|
||||||
ret["d"] = newParserField("d", `(?:\.|-|_)`, false)
|
ret["d"] = newParserField("d", `(?:\.|-|_)`, false)
|
||||||
|
ret["rating"] = newParserField("rating", `\d`, true)
|
||||||
ret["performer"] = newParserField("performer", ".*", true)
|
ret["performer"] = newParserField("performer", ".*", true)
|
||||||
ret["studio"] = newParserField("studio", ".*", true)
|
ret["studio"] = newParserField("studio", ".*", true)
|
||||||
ret["movie"] = newParserField("movie", ".*", true)
|
ret["movie"] = newParserField("movie", ".*", true)
|
||||||
@@ -224,6 +225,10 @@ func newSceneHolder(scene *models.Scene) *sceneHolder {
|
|||||||
return &ret
|
return &ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func validateRating(rating int) bool {
|
||||||
|
return rating >= 1 && rating <= 5
|
||||||
|
}
|
||||||
|
|
||||||
func validateDate(dateStr string) bool {
|
func validateDate(dateStr string) bool {
|
||||||
splits := strings.Split(dateStr, "-")
|
splits := strings.Split(dateStr, "-")
|
||||||
if len(splits) != 3 {
|
if len(splits) != 3 {
|
||||||
@@ -304,6 +309,14 @@ func (h *sceneHolder) setField(field parserField, value interface{}) {
|
|||||||
Valid: true,
|
Valid: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case "rating":
|
||||||
|
rating, _ := strconv.Atoi(value.(string))
|
||||||
|
if validateRating(rating) {
|
||||||
|
h.result.Rating = sql.NullInt64{
|
||||||
|
Int64: int64(rating),
|
||||||
|
Valid: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
case "performer":
|
case "performer":
|
||||||
// add performer to list
|
// add performer to list
|
||||||
h.performers = append(h.performers, value.(string))
|
h.performers = append(h.performers, value.(string))
|
||||||
@@ -661,6 +674,11 @@ func (p *SceneFilenameParser) setParserResult(h sceneHolder, result *models.Scen
|
|||||||
result.Date = &h.result.Date.String
|
result.Date = &h.result.Date.String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if h.result.Rating.Valid {
|
||||||
|
rating := int(h.result.Rating.Int64)
|
||||||
|
result.Rating = &rating
|
||||||
|
}
|
||||||
|
|
||||||
if len(h.performers) > 0 {
|
if len(h.performers) > 0 {
|
||||||
p.setPerformers(h, result)
|
p.setPerformers(h, result)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ export class ParserField {
|
|||||||
|
|
||||||
static Title = new ParserField("title");
|
static Title = new ParserField("title");
|
||||||
static Ext = new ParserField("ext", "File extension");
|
static Ext = new ParserField("ext", "File extension");
|
||||||
|
static Rating = new ParserField("rating");
|
||||||
|
|
||||||
static I = new ParserField("i", "Matches any ignored word");
|
static I = new ParserField("i", "Matches any ignored word");
|
||||||
static D = new ParserField("d", "Matches any delimiter (.-_)");
|
static D = new ParserField("d", "Matches any delimiter (.-_)");
|
||||||
@@ -39,6 +40,7 @@ export class ParserField {
|
|||||||
ParserField.Ext,
|
ParserField.Ext,
|
||||||
ParserField.D,
|
ParserField.D,
|
||||||
ParserField.I,
|
ParserField.I,
|
||||||
|
ParserField.Rating,
|
||||||
ParserField.Performer,
|
ParserField.Performer,
|
||||||
ParserField.Studio,
|
ParserField.Studio,
|
||||||
ParserField.Tag,
|
ParserField.Tag,
|
||||||
|
|||||||
@@ -131,6 +131,7 @@ export const ParserInput: React.FC<IParserInputProps> = (
|
|||||||
</Form.Label>
|
</Form.Label>
|
||||||
<InputGroup className="col-8">
|
<InputGroup className="col-8">
|
||||||
<Form.Control
|
<Form.Control
|
||||||
|
className="text-input"
|
||||||
id="filename-pattern"
|
id="filename-pattern"
|
||||||
onChange={(e: React.FormEvent<HTMLInputElement>) =>
|
onChange={(e: React.FormEvent<HTMLInputElement>) =>
|
||||||
setPattern(e.currentTarget.value)
|
setPattern(e.currentTarget.value)
|
||||||
@@ -144,8 +145,8 @@ export const ParserInput: React.FC<IParserInputProps> = (
|
|||||||
key={item.field}
|
key={item.field}
|
||||||
onSelect={() => addParserField(item)}
|
onSelect={() => addParserField(item)}
|
||||||
>
|
>
|
||||||
<span>{item.field}</span>
|
<span>{item.field || "{}"}</span>
|
||||||
<span className="ml-auto">{item.helperText}</span>
|
<span className="ml-auto text-muted">{item.helperText}</span>
|
||||||
</Dropdown.Item>
|
</Dropdown.Item>
|
||||||
))}
|
))}
|
||||||
</DropdownButton>
|
</DropdownButton>
|
||||||
@@ -160,6 +161,7 @@ export const ParserInput: React.FC<IParserInputProps> = (
|
|||||||
<Form.Label className="col-2">Ignored words</Form.Label>
|
<Form.Label className="col-2">Ignored words</Form.Label>
|
||||||
<InputGroup className="col-8">
|
<InputGroup className="col-8">
|
||||||
<Form.Control
|
<Form.Control
|
||||||
|
className="text-input"
|
||||||
onChange={(e: React.FormEvent<HTMLInputElement>) =>
|
onChange={(e: React.FormEvent<HTMLInputElement>) =>
|
||||||
setIgnoreWords(e.currentTarget.value)
|
setIgnoreWords(e.currentTarget.value)
|
||||||
}
|
}
|
||||||
@@ -178,6 +180,7 @@ export const ParserInput: React.FC<IParserInputProps> = (
|
|||||||
</Form.Label>
|
</Form.Label>
|
||||||
<InputGroup className="col-8">
|
<InputGroup className="col-8">
|
||||||
<Form.Control
|
<Form.Control
|
||||||
|
className="text-input"
|
||||||
onChange={(e: React.FormEvent<HTMLInputElement>) =>
|
onChange={(e: React.FormEvent<HTMLInputElement>) =>
|
||||||
setWhitespaceCharacters(e.currentTarget.value)
|
setWhitespaceCharacters(e.currentTarget.value)
|
||||||
}
|
}
|
||||||
@@ -206,6 +209,7 @@ export const ParserInput: React.FC<IParserInputProps> = (
|
|||||||
variant="secondary"
|
variant="secondary"
|
||||||
id="recipe-select"
|
id="recipe-select"
|
||||||
title="Select Parser Recipe"
|
title="Select Parser Recipe"
|
||||||
|
drop="up"
|
||||||
>
|
>
|
||||||
{builtInRecipes.map((item) => (
|
{builtInRecipes.map((item) => (
|
||||||
<Dropdown.Item
|
<Dropdown.Item
|
||||||
@@ -213,7 +217,7 @@ export const ParserInput: React.FC<IParserInputProps> = (
|
|||||||
onSelect={() => setParserRecipe(item)}
|
onSelect={() => setParserRecipe(item)}
|
||||||
>
|
>
|
||||||
<span>{item.pattern}</span>
|
<span>{item.pattern}</span>
|
||||||
<span className="mr-auto">{item.description}</span>
|
<span className="ml-auto text-muted">{item.description}</span>
|
||||||
</Dropdown.Item>
|
</Dropdown.Item>
|
||||||
))}
|
))}
|
||||||
</DropdownButton>
|
</DropdownButton>
|
||||||
@@ -237,7 +241,7 @@ export const ParserInput: React.FC<IParserInputProps> = (
|
|||||||
props.onPageSizeChanged(parseInt(e.currentTarget.value, 10))
|
props.onPageSizeChanged(parseInt(e.currentTarget.value, 10))
|
||||||
}
|
}
|
||||||
defaultValue={props.input.pageSize}
|
defaultValue={props.input.pageSize}
|
||||||
className="col-1 filter-item"
|
className="col-1 input-control filter-item"
|
||||||
>
|
>
|
||||||
{PAGE_SIZE_OPTIONS.map((val) => (
|
{PAGE_SIZE_OPTIONS.map((val) => (
|
||||||
<option key={val} value={val}>
|
<option key={val} value={val}>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* eslint-disable no-param-reassign, jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */
|
/* eslint-disable no-param-reassign, jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */
|
||||||
|
|
||||||
import React, { useEffect, useState, useCallback } from "react";
|
import React, { useEffect, useState, useCallback, useRef } from "react";
|
||||||
import { Button, Card, Form, Table } from "react-bootstrap";
|
import { Button, Card, Form, Table } from "react-bootstrap";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import { StashService } from "src/core/StashService";
|
import { StashService } from "src/core/StashService";
|
||||||
@@ -25,6 +25,7 @@ const initialParserInput = {
|
|||||||
const initialShowFieldsState = new Map<string, boolean>([
|
const initialShowFieldsState = new Map<string, boolean>([
|
||||||
["Title", true],
|
["Title", true],
|
||||||
["Date", true],
|
["Date", true],
|
||||||
|
["Rating", true],
|
||||||
["Performers", true],
|
["Performers", true],
|
||||||
["Tags", true],
|
["Tags", true],
|
||||||
["Studio", true],
|
["Studio", true],
|
||||||
@@ -36,9 +37,12 @@ export const SceneFilenameParser: React.FC = () => {
|
|||||||
const [parserInput, setParserInput] = useState<IParserInput>(
|
const [parserInput, setParserInput] = useState<IParserInput>(
|
||||||
initialParserInput
|
initialParserInput
|
||||||
);
|
);
|
||||||
|
const prevParserInputRef = useRef<IParserInput>();
|
||||||
|
const prevParserInput = prevParserInputRef.current;
|
||||||
|
|
||||||
const [allTitleSet, setAllTitleSet] = useState<boolean>(false);
|
const [allTitleSet, setAllTitleSet] = useState<boolean>(false);
|
||||||
const [allDateSet, setAllDateSet] = useState<boolean>(false);
|
const [allDateSet, setAllDateSet] = useState<boolean>(false);
|
||||||
|
const [allRatingSet, setAllRatingSet] = useState<boolean>(false);
|
||||||
const [allPerformerSet, setAllPerformerSet] = useState<boolean>(false);
|
const [allPerformerSet, setAllPerformerSet] = useState<boolean>(false);
|
||||||
const [allTagSet, setAllTagSet] = useState<boolean>(false);
|
const [allTagSet, setAllTagSet] = useState<boolean>(false);
|
||||||
const [allStudioSet, setAllStudioSet] = useState<boolean>(false);
|
const [allStudioSet, setAllStudioSet] = useState<boolean>(false);
|
||||||
@@ -54,6 +58,10 @@ export const SceneFilenameParser: React.FC = () => {
|
|||||||
|
|
||||||
const [updateScenes] = StashService.useScenesUpdate(getScenesUpdateData());
|
const [updateScenes] = StashService.useScenesUpdate(getScenesUpdateData());
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
prevParserInputRef.current = parserInput;
|
||||||
|
}, [parserInput]);
|
||||||
|
|
||||||
const determineFieldsToHide = useCallback(() => {
|
const determineFieldsToHide = useCallback(() => {
|
||||||
const { pattern } = parserInput;
|
const { pattern } = parserInput;
|
||||||
const titleSet = pattern.includes("{title}");
|
const titleSet = pattern.includes("{title}");
|
||||||
@@ -63,6 +71,7 @@ export const SceneFilenameParser: React.FC = () => {
|
|||||||
ParserField.fullDateFields.some((f) => {
|
ParserField.fullDateFields.some((f) => {
|
||||||
return pattern.includes(`{${f.field}}`);
|
return pattern.includes(`{${f.field}}`);
|
||||||
});
|
});
|
||||||
|
const ratingSet = pattern.includes("{rating}");
|
||||||
const performerSet = pattern.includes("{performer}");
|
const performerSet = pattern.includes("{performer}");
|
||||||
const tagSet = pattern.includes("{tag}");
|
const tagSet = pattern.includes("{tag}");
|
||||||
const studioSet = pattern.includes("{studio}");
|
const studioSet = pattern.includes("{studio}");
|
||||||
@@ -70,6 +79,7 @@ export const SceneFilenameParser: React.FC = () => {
|
|||||||
const newShowFields = new Map<string, boolean>([
|
const newShowFields = new Map<string, boolean>([
|
||||||
["Title", titleSet],
|
["Title", titleSet],
|
||||||
["Date", dateSet],
|
["Date", dateSet],
|
||||||
|
["Rating", ratingSet],
|
||||||
["Performers", performerSet],
|
["Performers", performerSet],
|
||||||
["Tags", tagSet],
|
["Tags", tagSet],
|
||||||
["Studio", studioSet],
|
["Studio", studioSet],
|
||||||
@@ -96,38 +106,47 @@ export const SceneFilenameParser: React.FC = () => {
|
|||||||
[determineFieldsToHide]
|
[determineFieldsToHide]
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
const parseSceneFilenames = useCallback(() => {
|
||||||
if (parserInput.findClicked) {
|
setParserResult([]);
|
||||||
setParserResult([]);
|
setIsLoading(true);
|
||||||
setIsLoading(true);
|
|
||||||
|
|
||||||
const parserFilter = {
|
const parserFilter = {
|
||||||
q: parserInput.pattern,
|
q: parserInput.pattern,
|
||||||
page: parserInput.page,
|
page: parserInput.page,
|
||||||
per_page: parserInput.pageSize,
|
per_page: parserInput.pageSize,
|
||||||
sort: "path",
|
sort: "path",
|
||||||
direction: GQL.SortDirectionEnum.Asc,
|
direction: GQL.SortDirectionEnum.Asc,
|
||||||
};
|
};
|
||||||
|
|
||||||
const parserInputData = {
|
const parserInputData = {
|
||||||
ignoreWords: parserInput.ignoreWords,
|
ignoreWords: parserInput.ignoreWords,
|
||||||
whitespaceCharacters: parserInput.whitespaceCharacters,
|
whitespaceCharacters: parserInput.whitespaceCharacters,
|
||||||
capitalizeTitle: parserInput.capitalizeTitle,
|
capitalizeTitle: parserInput.capitalizeTitle,
|
||||||
};
|
};
|
||||||
|
|
||||||
StashService.queryParseSceneFilenames(parserFilter, parserInputData)
|
StashService.queryParseSceneFilenames(parserFilter, parserInputData)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
const result = response.data.parseSceneFilenames;
|
const result = response.data.parseSceneFilenames;
|
||||||
if (result) {
|
if (result) {
|
||||||
parseResults(result.results);
|
parseResults(result.results);
|
||||||
setTotalItems(result.count);
|
setTotalItems(result.count);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((err) => Toast.error(err))
|
.catch((err) => Toast.error(err))
|
||||||
.finally(() => setIsLoading(false));
|
.finally(() => setIsLoading(false));
|
||||||
}
|
|
||||||
}, [parserInput, parseResults, Toast]);
|
}, [parserInput, parseResults, Toast]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// only refresh if parserInput actually changed
|
||||||
|
if (prevParserInput === parserInput) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parserInput.findClicked) {
|
||||||
|
parseSceneFilenames();
|
||||||
|
}
|
||||||
|
}, [parserInput, parseSceneFilenames, prevParserInput]);
|
||||||
|
|
||||||
function onPageSizeChanged(newSize: number) {
|
function onPageSizeChanged(newSize: number) {
|
||||||
const newInput = _.clone(parserInput);
|
const newInput = _.clone(parserInput);
|
||||||
newInput.page = 1;
|
newInput.page = 1;
|
||||||
@@ -144,9 +163,10 @@ export const SceneFilenameParser: React.FC = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function onFindClicked(input: IParserInput) {
|
function onFindClicked(input: IParserInput) {
|
||||||
input.page = 1;
|
const newInput = _.clone(input);
|
||||||
input.findClicked = true;
|
newInput.page = 1;
|
||||||
setParserInput(input);
|
newInput.findClicked = true;
|
||||||
|
setParserInput(newInput);
|
||||||
setTotalItems(0);
|
setTotalItems(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,6 +187,9 @@ export const SceneFilenameParser: React.FC = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
|
|
||||||
|
// trigger a refresh of the results
|
||||||
|
onFindClicked(parserInput);
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -176,6 +199,9 @@ export const SceneFilenameParser: React.FC = () => {
|
|||||||
const newAllDateSet = !parserResult.some((r) => {
|
const newAllDateSet = !parserResult.some((r) => {
|
||||||
return !r.date.isSet;
|
return !r.date.isSet;
|
||||||
});
|
});
|
||||||
|
const newAllRatingSet = !parserResult.some((r) => {
|
||||||
|
return !r.rating.isSet;
|
||||||
|
});
|
||||||
const newAllPerformerSet = !parserResult.some((r) => {
|
const newAllPerformerSet = !parserResult.some((r) => {
|
||||||
return !r.performers.isSet;
|
return !r.performers.isSet;
|
||||||
});
|
});
|
||||||
@@ -188,6 +214,7 @@ export const SceneFilenameParser: React.FC = () => {
|
|||||||
|
|
||||||
setAllTitleSet(newAllTitleSet);
|
setAllTitleSet(newAllTitleSet);
|
||||||
setAllDateSet(newAllDateSet);
|
setAllDateSet(newAllDateSet);
|
||||||
|
setAllRatingSet(newAllRatingSet);
|
||||||
setAllTagSet(newAllPerformerSet);
|
setAllTagSet(newAllPerformerSet);
|
||||||
setAllTagSet(newAllTagSet);
|
setAllTagSet(newAllTagSet);
|
||||||
setAllStudioSet(newAllStudioSet);
|
setAllStudioSet(newAllStudioSet);
|
||||||
@@ -215,6 +242,17 @@ export const SceneFilenameParser: React.FC = () => {
|
|||||||
setAllDateSet(selected);
|
setAllDateSet(selected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onSelectAllRatingSet(selected: boolean) {
|
||||||
|
const newResult = [...parserResult];
|
||||||
|
|
||||||
|
newResult.forEach((r) => {
|
||||||
|
r.rating.isSet = selected;
|
||||||
|
});
|
||||||
|
|
||||||
|
setParserResult(newResult);
|
||||||
|
setAllRatingSet(selected);
|
||||||
|
}
|
||||||
|
|
||||||
function onSelectAllPerformerSet(selected: boolean) {
|
function onSelectAllPerformerSet(selected: boolean) {
|
||||||
const newResult = [...parserResult];
|
const newResult = [...parserResult];
|
||||||
|
|
||||||
@@ -295,6 +333,7 @@ export const SceneFilenameParser: React.FC = () => {
|
|||||||
<th className="parser-field-filename">Filename</th>
|
<th className="parser-field-filename">Filename</th>
|
||||||
{renderHeader("Title", allTitleSet, onSelectAllTitleSet)}
|
{renderHeader("Title", allTitleSet, onSelectAllTitleSet)}
|
||||||
{renderHeader("Date", allDateSet, onSelectAllDateSet)}
|
{renderHeader("Date", allDateSet, onSelectAllDateSet)}
|
||||||
|
{renderHeader("Rating", allRatingSet, onSelectAllRatingSet)}
|
||||||
{renderHeader(
|
{renderHeader(
|
||||||
"Performers",
|
"Performers",
|
||||||
allPerformerSet,
|
allPerformerSet,
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ export class SceneParserResult {
|
|||||||
public filename: string;
|
public filename: string;
|
||||||
public title: ParserResult<string> = new ParserResult<string>();
|
public title: ParserResult<string> = new ParserResult<string>();
|
||||||
public date: ParserResult<string> = new ParserResult<string>();
|
public date: ParserResult<string> = new ParserResult<string>();
|
||||||
|
public rating: ParserResult<number> = new ParserResult<number>();
|
||||||
|
|
||||||
public studio: ParserResult<string> = new ParserResult<string>();
|
public studio: ParserResult<string> = new ParserResult<string>();
|
||||||
public tags: ParserResult<string[]> = new ParserResult<string[]>();
|
public tags: ParserResult<string[]> = new ParserResult<string[]>();
|
||||||
@@ -51,12 +52,14 @@ export class SceneParserResult {
|
|||||||
this.filename = TextUtils.fileNameFromPath(this.scene.path);
|
this.filename = TextUtils.fileNameFromPath(this.scene.path);
|
||||||
this.title.setOriginalValue(this.scene.title ?? undefined);
|
this.title.setOriginalValue(this.scene.title ?? undefined);
|
||||||
this.date.setOriginalValue(this.scene.date ?? undefined);
|
this.date.setOriginalValue(this.scene.date ?? undefined);
|
||||||
|
this.rating.setOriginalValue(this.scene.rating ?? undefined);
|
||||||
this.performers.setOriginalValue(this.scene.performers.map((p) => p.id));
|
this.performers.setOriginalValue(this.scene.performers.map((p) => p.id));
|
||||||
this.tags.setOriginalValue(this.scene.tags.map((t) => t.id));
|
this.tags.setOriginalValue(this.scene.tags.map((t) => t.id));
|
||||||
this.studio.setOriginalValue(this.scene.studio?.id);
|
this.studio.setOriginalValue(this.scene.studio?.id);
|
||||||
|
|
||||||
this.title.setValue(result.title ?? undefined);
|
this.title.setValue(result.title ?? undefined);
|
||||||
this.date.setValue(result.date ?? undefined);
|
this.date.setValue(result.date ?? undefined);
|
||||||
|
this.rating.setValue(result.rating ?? undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns true if any of its fields have set == true
|
// returns true if any of its fields have set == true
|
||||||
@@ -64,6 +67,7 @@ export class SceneParserResult {
|
|||||||
return (
|
return (
|
||||||
this.title.isSet ||
|
this.title.isSet ||
|
||||||
this.date.isSet ||
|
this.date.isSet ||
|
||||||
|
this.rating.isSet ||
|
||||||
this.performers.isSet ||
|
this.performers.isSet ||
|
||||||
this.studio.isSet ||
|
this.studio.isSet ||
|
||||||
this.tags.isSet
|
this.tags.isSet
|
||||||
@@ -75,7 +79,7 @@ export class SceneParserResult {
|
|||||||
id: this.id,
|
id: this.id,
|
||||||
details: this.scene.details,
|
details: this.scene.details,
|
||||||
url: this.scene.url,
|
url: this.scene.url,
|
||||||
rating: this.scene.rating,
|
rating: this.rating.isSet ? this.rating.value : this.scene.rating,
|
||||||
gallery_id: this.scene.gallery?.id,
|
gallery_id: this.scene.gallery?.id,
|
||||||
title: this.title.isSet ? this.title.value : this.scene.title,
|
title: this.title.isSet ? this.title.value : this.scene.title,
|
||||||
date: this.date.isSet ? this.date.value : this.scene.date,
|
date: this.date.isSet ? this.date.value : this.scene.date,
|
||||||
@@ -121,12 +125,12 @@ function SceneParserStringField(props: ISceneParserFieldProps<string>) {
|
|||||||
<td>
|
<td>
|
||||||
<Form.Group>
|
<Form.Group>
|
||||||
<Form.Control
|
<Form.Control
|
||||||
disabled
|
readOnly
|
||||||
className={props.className}
|
className={props.className}
|
||||||
defaultValue={result.originalValue || ""}
|
defaultValue={result.originalValue || ""}
|
||||||
/>
|
/>
|
||||||
<Form.Control
|
<Form.Control
|
||||||
disabled={!props.parserResult.isSet}
|
readOnly={!props.parserResult.isSet}
|
||||||
className={props.className}
|
className={props.className}
|
||||||
value={props.parserResult.value || ""}
|
value={props.parserResult.value || ""}
|
||||||
onChange={(event: React.FormEvent<HTMLInputElement>) =>
|
onChange={(event: React.FormEvent<HTMLInputElement>) =>
|
||||||
@@ -139,6 +143,60 @@ function SceneParserStringField(props: ISceneParserFieldProps<string>) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function SceneParserRatingField(
|
||||||
|
props: ISceneParserFieldProps<number | undefined>
|
||||||
|
) {
|
||||||
|
function maybeValueChanged(value?: number) {
|
||||||
|
if (value !== props.parserResult.value) {
|
||||||
|
props.onValueChanged(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = props.originalParserResult || props.parserResult;
|
||||||
|
const options = ["", 1, 2, 3, 4, 5];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<td>
|
||||||
|
<Form.Check
|
||||||
|
checked={props.parserResult.isSet}
|
||||||
|
onChange={() => {
|
||||||
|
props.onSetChanged(!props.parserResult.isSet);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<Form.Group>
|
||||||
|
<Form.Control
|
||||||
|
readOnly
|
||||||
|
className={props.className}
|
||||||
|
defaultValue={result.originalValue || ""}
|
||||||
|
/>
|
||||||
|
<Form.Control
|
||||||
|
as="select"
|
||||||
|
className={props.className}
|
||||||
|
disabled={!props.parserResult.isSet}
|
||||||
|
value={props.parserResult.value?.toString()}
|
||||||
|
onChange={(event: React.FormEvent<HTMLSelectElement>) =>
|
||||||
|
maybeValueChanged(
|
||||||
|
event.currentTarget.value === ""
|
||||||
|
? undefined
|
||||||
|
: Number.parseInt(event.currentTarget.value, 10)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{options.map((opt) => (
|
||||||
|
<option value={opt} key={opt}>
|
||||||
|
{opt}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</Form.Control>
|
||||||
|
</Form.Group>
|
||||||
|
</td>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function SceneParserPerformerField(props: ISceneParserFieldProps<string[]>) {
|
function SceneParserPerformerField(props: ISceneParserFieldProps<string[]>) {
|
||||||
function maybeValueChanged(value: string[]) {
|
function maybeValueChanged(value: string[]) {
|
||||||
if (value !== props.parserResult.value) {
|
if (value !== props.parserResult.value) {
|
||||||
@@ -165,6 +223,7 @@ function SceneParserPerformerField(props: ISceneParserFieldProps<string[]>) {
|
|||||||
<PerformerSelect isDisabled isMulti ids={originalPerformers} />
|
<PerformerSelect isDisabled isMulti ids={originalPerformers} />
|
||||||
<PerformerSelect
|
<PerformerSelect
|
||||||
isMulti
|
isMulti
|
||||||
|
isDisabled={!props.parserResult.isSet}
|
||||||
onSelect={(items) => {
|
onSelect={(items) => {
|
||||||
maybeValueChanged(items.map((i) => i.id));
|
maybeValueChanged(items.map((i) => i.id));
|
||||||
}}
|
}}
|
||||||
@@ -201,6 +260,7 @@ function SceneParserTagField(props: ISceneParserFieldProps<string[]>) {
|
|||||||
<TagSelect isDisabled isMulti ids={originalTags} />
|
<TagSelect isDisabled isMulti ids={originalTags} />
|
||||||
<TagSelect
|
<TagSelect
|
||||||
isMulti
|
isMulti
|
||||||
|
isDisabled={!props.parserResult.isSet}
|
||||||
onSelect={(items) => {
|
onSelect={(items) => {
|
||||||
maybeValueChanged(items.map((i) => i.id));
|
maybeValueChanged(items.map((i) => i.id));
|
||||||
}}
|
}}
|
||||||
@@ -238,6 +298,7 @@ function SceneParserStudioField(props: ISceneParserFieldProps<string>) {
|
|||||||
<Form.Group className={props.className}>
|
<Form.Group className={props.className}>
|
||||||
<StudioSelect isDisabled ids={originalStudio} />
|
<StudioSelect isDisabled ids={originalStudio} />
|
||||||
<StudioSelect
|
<StudioSelect
|
||||||
|
isDisabled={!props.parserResult.isSet}
|
||||||
onSelect={(items) => {
|
onSelect={(items) => {
|
||||||
maybeValueChanged(items[0].id);
|
maybeValueChanged(items[0].id);
|
||||||
}}
|
}}
|
||||||
@@ -256,7 +317,7 @@ interface ISceneParserRowProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const SceneParserRow = (props: ISceneParserRowProps) => {
|
export const SceneParserRow = (props: ISceneParserRowProps) => {
|
||||||
function changeParser<T>(result: ParserResult<T>, isSet: boolean, value: T) {
|
function changeParser<T>(result: ParserResult<T>, isSet: boolean, value?: T) {
|
||||||
const newParser = _.clone(result);
|
const newParser = _.clone(result);
|
||||||
newParser.isSet = isSet;
|
newParser.isSet = isSet;
|
||||||
newParser.value = value;
|
newParser.value = value;
|
||||||
@@ -275,6 +336,12 @@ export const SceneParserRow = (props: ISceneParserRowProps) => {
|
|||||||
props.onChange(newResult);
|
props.onChange(newResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onRatingChanged(set: boolean, value?: number) {
|
||||||
|
const newResult = _.clone(props.scene);
|
||||||
|
newResult.rating = changeParser(newResult.rating, set, value);
|
||||||
|
props.onChange(newResult);
|
||||||
|
}
|
||||||
|
|
||||||
function onPerformerIdsChanged(set: boolean, value: string[]) {
|
function onPerformerIdsChanged(set: boolean, value: string[]) {
|
||||||
const newResult = _.clone(props.scene);
|
const newResult = _.clone(props.scene);
|
||||||
newResult.performers = changeParser(newResult.performers, set, value);
|
newResult.performers = changeParser(newResult.performers, set, value);
|
||||||
@@ -302,7 +369,7 @@ export const SceneParserRow = (props: ISceneParserRowProps) => {
|
|||||||
<SceneParserStringField
|
<SceneParserStringField
|
||||||
key="title"
|
key="title"
|
||||||
fieldName="Title"
|
fieldName="Title"
|
||||||
className="parser-field-title"
|
className="parser-field-title input-control text-input"
|
||||||
parserResult={props.scene.title}
|
parserResult={props.scene.title}
|
||||||
onSetChanged={(isSet) =>
|
onSetChanged={(isSet) =>
|
||||||
onTitleChanged(isSet, props.scene.title.value ?? "")
|
onTitleChanged(isSet, props.scene.title.value ?? "")
|
||||||
@@ -316,7 +383,7 @@ export const SceneParserRow = (props: ISceneParserRowProps) => {
|
|||||||
<SceneParserStringField
|
<SceneParserStringField
|
||||||
key="date"
|
key="date"
|
||||||
fieldName="Date"
|
fieldName="Date"
|
||||||
className="parser-field-date"
|
className="parser-field-date input-control text-input"
|
||||||
parserResult={props.scene.date}
|
parserResult={props.scene.date}
|
||||||
onSetChanged={(isSet) =>
|
onSetChanged={(isSet) =>
|
||||||
onDateChanged(isSet, props.scene.date.value ?? "")
|
onDateChanged(isSet, props.scene.date.value ?? "")
|
||||||
@@ -326,11 +393,25 @@ export const SceneParserRow = (props: ISceneParserRowProps) => {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{props.showFields.get("Rating") && (
|
||||||
|
<SceneParserRatingField
|
||||||
|
key="rating"
|
||||||
|
fieldName="Rating"
|
||||||
|
className="parser-field-rating input-control text-input"
|
||||||
|
parserResult={props.scene.rating}
|
||||||
|
onSetChanged={(isSet) =>
|
||||||
|
onRatingChanged(isSet, props.scene.rating.value ?? undefined)
|
||||||
|
}
|
||||||
|
onValueChanged={(value) =>
|
||||||
|
onRatingChanged(props.scene.rating.isSet, value)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{props.showFields.get("Performers") && (
|
{props.showFields.get("Performers") && (
|
||||||
<SceneParserPerformerField
|
<SceneParserPerformerField
|
||||||
key="performers"
|
key="performers"
|
||||||
fieldName="Performers"
|
fieldName="Performers"
|
||||||
className="parser-field-performers"
|
className="parser-field-performers input-control text-input"
|
||||||
parserResult={props.scene.performers}
|
parserResult={props.scene.performers}
|
||||||
originalParserResult={props.scene.performers}
|
originalParserResult={props.scene.performers}
|
||||||
onSetChanged={(set) =>
|
onSetChanged={(set) =>
|
||||||
@@ -345,7 +426,7 @@ export const SceneParserRow = (props: ISceneParserRowProps) => {
|
|||||||
<SceneParserTagField
|
<SceneParserTagField
|
||||||
key="tags"
|
key="tags"
|
||||||
fieldName="Tags"
|
fieldName="Tags"
|
||||||
className="parser-field-tags"
|
className="parser-field-tags input-control text-input"
|
||||||
parserResult={props.scene.tags}
|
parserResult={props.scene.tags}
|
||||||
originalParserResult={props.scene.tags}
|
originalParserResult={props.scene.tags}
|
||||||
onSetChanged={(isSet) =>
|
onSetChanged={(isSet) =>
|
||||||
@@ -360,7 +441,7 @@ export const SceneParserRow = (props: ISceneParserRowProps) => {
|
|||||||
<SceneParserStudioField
|
<SceneParserStudioField
|
||||||
key="studio"
|
key="studio"
|
||||||
fieldName="Studio"
|
fieldName="Studio"
|
||||||
className="parser-field-studio"
|
className="parser-field-studio input-control text-input"
|
||||||
parserResult={props.scene.studio}
|
parserResult={props.scene.studio}
|
||||||
originalParserResult={props.scene.studio}
|
originalParserResult={props.scene.studio}
|
||||||
onSetChanged={(set) =>
|
onSetChanged={(set) =>
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
#recipe-select::after {
|
||||||
|
content: none;
|
||||||
|
}
|
||||||
|
|
||||||
.scene-parser-results {
|
.scene-parser-results {
|
||||||
margin-left: 31ch;
|
margin-left: 31ch;
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
|
|||||||
@@ -55,7 +55,8 @@ code,
|
|||||||
|
|
||||||
.text-input,
|
.text-input,
|
||||||
.text-input:focus,
|
.text-input:focus,
|
||||||
.text-input[readonly] {
|
.text-input[readonly],
|
||||||
|
.text-input:disabled {
|
||||||
background-color: $textfield-bg;
|
background-color: $textfield-bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,20 +172,41 @@ div.react-select__control {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
div.react-select__menu {
|
div.react-select__menu,
|
||||||
|
div.dropdown-menu {
|
||||||
background-color: $secondary;
|
background-color: $secondary;
|
||||||
color: $text-color;
|
color: $text-color;
|
||||||
|
|
||||||
.react-select__option {
|
.react-select__option,
|
||||||
|
.dropdown-item {
|
||||||
color: $text-color;
|
color: $text-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.react-select__option--is-focused {
|
.react-select__option--is-focused,
|
||||||
|
.dropdown-item:focus,
|
||||||
|
.dropdown-item:hover {
|
||||||
background-color: #8a9ba826;
|
background-color: #8a9ba826;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.dropdown-menu {
|
||||||
|
max-height: 300px;
|
||||||
|
overflow-y: auto;
|
||||||
|
|
||||||
|
.dropdown-item {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
& > * {
|
||||||
|
margin-right: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > :last-child {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* we don't want to override this for dialogs, which are light colored */
|
/* we don't want to override this for dialogs, which are light colored */
|
||||||
.modal {
|
.modal {
|
||||||
div.react-select__control {
|
div.react-select__control {
|
||||||
@@ -374,8 +396,8 @@ div.react-select__menu {
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
input[type="file"], /* FF, IE7+, chrome (except button) */
|
input[type=file], /* FF, IE7+, chrome (except button) */
|
||||||
input[type="file"]::-webkit-file-upload-button {
|
input[type=file]::-webkit-file-upload-button {
|
||||||
/* chromes and blink button */
|
/* chromes and blink button */
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ class ParserField {
|
|||||||
static Performer = new ParserField("performer");
|
static Performer = new ParserField("performer");
|
||||||
static Studio = new ParserField("studio");
|
static Studio = new ParserField("studio");
|
||||||
static Tag = new ParserField("tag");
|
static Tag = new ParserField("tag");
|
||||||
|
static Rating = new ParserField("rating");
|
||||||
|
|
||||||
// date fields
|
// date fields
|
||||||
static Date = new ParserField("date", "YYYY-MM-DD");
|
static Date = new ParserField("date", "YYYY-MM-DD");
|
||||||
@@ -89,6 +90,7 @@ class ParserField {
|
|||||||
ParserField.Ext,
|
ParserField.Ext,
|
||||||
ParserField.D,
|
ParserField.D,
|
||||||
ParserField.I,
|
ParserField.I,
|
||||||
|
ParserField.Rating,
|
||||||
ParserField.Performer,
|
ParserField.Performer,
|
||||||
ParserField.Studio,
|
ParserField.Studio,
|
||||||
ParserField.Tag,
|
ParserField.Tag,
|
||||||
@@ -119,6 +121,7 @@ class SceneParserResult {
|
|||||||
public filename: string;
|
public filename: string;
|
||||||
public title: ParserResult<string> = new ParserResult();
|
public title: ParserResult<string> = new ParserResult();
|
||||||
public date: ParserResult<string> = new ParserResult();
|
public date: ParserResult<string> = new ParserResult();
|
||||||
|
public rating: ParserResult<number> = new ParserResult();
|
||||||
|
|
||||||
public studio: ParserResult<GQL.SlimSceneDataStudio> = new ParserResult();
|
public studio: ParserResult<GQL.SlimSceneDataStudio> = new ParserResult();
|
||||||
public studioId: ParserResult<string> = new ParserResult();
|
public studioId: ParserResult<string> = new ParserResult();
|
||||||
@@ -133,6 +136,7 @@ class SceneParserResult {
|
|||||||
this.scene = result.scene;
|
this.scene = result.scene;
|
||||||
|
|
||||||
this.id = this.scene.id;
|
this.id = this.scene.id;
|
||||||
|
this.rating.setOriginalValue(this.scene.rating);
|
||||||
this.filename = TextUtils.fileNameFromPath(this.scene.path);
|
this.filename = TextUtils.fileNameFromPath(this.scene.path);
|
||||||
this.title.setOriginalValue(this.scene.title);
|
this.title.setOriginalValue(this.scene.title);
|
||||||
this.date.setOriginalValue(this.scene.date);
|
this.date.setOriginalValue(this.scene.date);
|
||||||
@@ -144,6 +148,7 @@ class SceneParserResult {
|
|||||||
this.studio.setOriginalValue(this.scene.studio);
|
this.studio.setOriginalValue(this.scene.studio);
|
||||||
|
|
||||||
this.title.setValue(result.title);
|
this.title.setValue(result.title);
|
||||||
|
this.rating.setValue(result.rating);
|
||||||
this.date.setValue(result.date);
|
this.date.setValue(result.date);
|
||||||
this.performerIds.setValue(result.performer_ids);
|
this.performerIds.setValue(result.performer_ids);
|
||||||
this.tagIds.setValue(result.tag_ids);
|
this.tagIds.setValue(result.tag_ids);
|
||||||
@@ -186,7 +191,7 @@ class SceneParserResult {
|
|||||||
|
|
||||||
// returns true if any of its fields have set == true
|
// returns true if any of its fields have set == true
|
||||||
public isChanged() {
|
public isChanged() {
|
||||||
return this.title.set || this.date.set || this.performerIds.set || this.studioId.set || this.tagIds.set;
|
return this.title.set || this.date.set || this.rating.set || this.performerIds.set || this.studioId.set || this.tagIds.set;
|
||||||
}
|
}
|
||||||
|
|
||||||
public toSceneUpdateInput() {
|
public toSceneUpdateInput() {
|
||||||
@@ -205,6 +210,7 @@ class SceneParserResult {
|
|||||||
|
|
||||||
SceneParserResult.setInput(ret, "title", this.title);
|
SceneParserResult.setInput(ret, "title", this.title);
|
||||||
SceneParserResult.setInput(ret, "date", this.date);
|
SceneParserResult.setInput(ret, "date", this.date);
|
||||||
|
SceneParserResult.setInput(ret, "rating", this.rating);
|
||||||
SceneParserResult.setInput(ret, "performer_ids", this.performerIds);
|
SceneParserResult.setInput(ret, "performer_ids", this.performerIds);
|
||||||
SceneParserResult.setInput(ret, "studio_id", this.studioId);
|
SceneParserResult.setInput(ret, "studio_id", this.studioId);
|
||||||
SceneParserResult.setInput(ret, "tag_ids", this.tagIds);
|
SceneParserResult.setInput(ret, "tag_ids", this.tagIds);
|
||||||
@@ -282,6 +288,7 @@ export const SceneFilenameParser: FunctionComponent<IProps> = (props: IProps) =>
|
|||||||
|
|
||||||
const [allTitleSet, setAllTitleSet] = useState<boolean>(false);
|
const [allTitleSet, setAllTitleSet] = useState<boolean>(false);
|
||||||
const [allDateSet, setAllDateSet] = useState<boolean>(false);
|
const [allDateSet, setAllDateSet] = useState<boolean>(false);
|
||||||
|
const [allRatingSet, setAllRatingSet] = useState<boolean>(false);
|
||||||
const [allPerformerSet, setAllPerformerSet] = useState<boolean>(false);
|
const [allPerformerSet, setAllPerformerSet] = useState<boolean>(false);
|
||||||
const [allTagSet, setAllTagSet] = useState<boolean>(false);
|
const [allTagSet, setAllTagSet] = useState<boolean>(false);
|
||||||
const [allStudioSet, setAllStudioSet] = useState<boolean>(false);
|
const [allStudioSet, setAllStudioSet] = useState<boolean>(false);
|
||||||
@@ -311,6 +318,7 @@ export const SceneFilenameParser: FunctionComponent<IProps> = (props: IProps) =>
|
|||||||
return new Map<string, boolean>([
|
return new Map<string, boolean>([
|
||||||
["Title", true],
|
["Title", true],
|
||||||
["Date", true],
|
["Date", true],
|
||||||
|
["Rating", true],
|
||||||
["Performers", true],
|
["Performers", true],
|
||||||
["Tags", true],
|
["Tags", true],
|
||||||
["Studio", true]
|
["Studio", true]
|
||||||
@@ -419,6 +427,7 @@ export const SceneFilenameParser: FunctionComponent<IProps> = (props: IProps) =>
|
|||||||
ParserField.fullDateFields.some((f) => {
|
ParserField.fullDateFields.some((f) => {
|
||||||
return pattern.includes("{" + f.field + "}");
|
return pattern.includes("{" + f.field + "}");
|
||||||
});
|
});
|
||||||
|
var ratingSet = pattern.includes("{rating}");
|
||||||
var performerSet = pattern.includes("{performer}");
|
var performerSet = pattern.includes("{performer}");
|
||||||
var tagSet = pattern.includes("{tag}");
|
var tagSet = pattern.includes("{tag}");
|
||||||
var studioSet = pattern.includes("{studio}");
|
var studioSet = pattern.includes("{studio}");
|
||||||
@@ -426,6 +435,7 @@ export const SceneFilenameParser: FunctionComponent<IProps> = (props: IProps) =>
|
|||||||
var showFieldsCopy = _.clone(showFields);
|
var showFieldsCopy = _.clone(showFields);
|
||||||
showFieldsCopy.set("Title", titleSet);
|
showFieldsCopy.set("Title", titleSet);
|
||||||
showFieldsCopy.set("Date", dateSet);
|
showFieldsCopy.set("Date", dateSet);
|
||||||
|
showFieldsCopy.set("Rating", ratingSet);
|
||||||
showFieldsCopy.set("Performers", performerSet);
|
showFieldsCopy.set("Performers", performerSet);
|
||||||
showFieldsCopy.set("Tags", tagSet);
|
showFieldsCopy.set("Tags", tagSet);
|
||||||
showFieldsCopy.set("Studio", studioSet);
|
showFieldsCopy.set("Studio", studioSet);
|
||||||
@@ -439,6 +449,9 @@ export const SceneFilenameParser: FunctionComponent<IProps> = (props: IProps) =>
|
|||||||
var newAllDateSet = !parserResult.some((r) => {
|
var newAllDateSet = !parserResult.some((r) => {
|
||||||
return !r.date.set;
|
return !r.date.set;
|
||||||
});
|
});
|
||||||
|
var newAllRatingSet = !parserResult.some((r) => {
|
||||||
|
return !r.rating.set;
|
||||||
|
});
|
||||||
var newAllPerformerSet = !parserResult.some((r) => {
|
var newAllPerformerSet = !parserResult.some((r) => {
|
||||||
return !r.performerIds.set;
|
return !r.performerIds.set;
|
||||||
});
|
});
|
||||||
@@ -455,6 +468,9 @@ export const SceneFilenameParser: FunctionComponent<IProps> = (props: IProps) =>
|
|||||||
if (newAllDateSet !== allDateSet) {
|
if (newAllDateSet !== allDateSet) {
|
||||||
setAllDateSet(newAllDateSet);
|
setAllDateSet(newAllDateSet);
|
||||||
}
|
}
|
||||||
|
if (newAllRatingSet !== allRatingSet) {
|
||||||
|
setAllRatingSet(newAllRatingSet);
|
||||||
|
}
|
||||||
if (newAllPerformerSet !== allPerformerSet) {
|
if (newAllPerformerSet !== allPerformerSet) {
|
||||||
setAllTagSet(newAllPerformerSet);
|
setAllTagSet(newAllPerformerSet);
|
||||||
}
|
}
|
||||||
@@ -488,6 +504,17 @@ export const SceneFilenameParser: FunctionComponent<IProps> = (props: IProps) =>
|
|||||||
setAllDateSet(selected);
|
setAllDateSet(selected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onSelectAllRatingSet(selected : boolean) {
|
||||||
|
var newResult = [...parserResult];
|
||||||
|
|
||||||
|
newResult.forEach((r) => {
|
||||||
|
r.rating.set = selected;
|
||||||
|
});
|
||||||
|
|
||||||
|
setParserResult(newResult);
|
||||||
|
setAllRatingSet(selected);
|
||||||
|
}
|
||||||
|
|
||||||
function onSelectAllPerformerSet(selected : boolean) {
|
function onSelectAllPerformerSet(selected : boolean) {
|
||||||
var newResult = [...parserResult];
|
var newResult = [...parserResult];
|
||||||
|
|
||||||
@@ -545,14 +572,18 @@ export const SceneFilenameParser: FunctionComponent<IProps> = (props: IProps) =>
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 3,
|
id: 3,
|
||||||
label: "Performers",
|
label: "Rating",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 4,
|
id: 4,
|
||||||
label: "Tags",
|
label: "Performers",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 5,
|
id: 5,
|
||||||
|
label: "Tags",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 6,
|
||||||
label: "Studio",
|
label: "Studio",
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -960,6 +991,12 @@ export const SceneFilenameParser: FunctionComponent<IProps> = (props: IProps) =>
|
|||||||
props.onChange(newResult);
|
props.onChange(newResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onRatingChanged(set : boolean, value: number | undefined) {
|
||||||
|
var newResult = _.clone(props.scene);
|
||||||
|
newResult.rating = changeParser(newResult.rating, set, value);
|
||||||
|
props.onChange(newResult);
|
||||||
|
}
|
||||||
|
|
||||||
function onPerformerIdsChanged(set : boolean, value: string[] | undefined) {
|
function onPerformerIdsChanged(set : boolean, value: string[] | undefined) {
|
||||||
var newResult = _.clone(props.scene);
|
var newResult = _.clone(props.scene);
|
||||||
newResult.performerIds = changeParser(newResult.performerIds, set, value);
|
newResult.performerIds = changeParser(newResult.performerIds, set, value);
|
||||||
@@ -1004,6 +1041,16 @@ export const SceneFilenameParser: FunctionComponent<IProps> = (props: IProps) =>
|
|||||||
renderOriginalInputField={renderOriginalInputGroup}
|
renderOriginalInputField={renderOriginalInputGroup}
|
||||||
renderNewInputField={renderNewInputGroup}
|
renderNewInputField={renderNewInputGroup}
|
||||||
/>
|
/>
|
||||||
|
<SceneParserField
|
||||||
|
key="rating"
|
||||||
|
fieldName="Rating"
|
||||||
|
className="parser-field-rating"
|
||||||
|
parserResult={props.scene.rating}
|
||||||
|
onSetChanged={(set) => onRatingChanged(set, props.scene.rating.value)}
|
||||||
|
onValueChanged={(value) => onRatingChanged(props.scene.rating.set, value)}
|
||||||
|
renderOriginalInputField={renderOriginalInputGroup}
|
||||||
|
renderNewInputField={renderNewInputGroup}
|
||||||
|
/>
|
||||||
<SceneParserField
|
<SceneParserField
|
||||||
key="performers"
|
key="performers"
|
||||||
fieldName="Performers"
|
fieldName="Performers"
|
||||||
@@ -1083,6 +1130,7 @@ export const SceneFilenameParser: FunctionComponent<IProps> = (props: IProps) =>
|
|||||||
<th>Filename</th>
|
<th>Filename</th>
|
||||||
{renderHeader("Title", allTitleSet, onSelectAllTitleSet)}
|
{renderHeader("Title", allTitleSet, onSelectAllTitleSet)}
|
||||||
{renderHeader("Date", allDateSet, onSelectAllDateSet)}
|
{renderHeader("Date", allDateSet, onSelectAllDateSet)}
|
||||||
|
{renderHeader("Rating", allRatingSet, onSelectAllRatingSet)}
|
||||||
{renderHeader("Performers", allPerformerSet, onSelectAllPerformerSet)}
|
{renderHeader("Performers", allPerformerSet, onSelectAllPerformerSet)}
|
||||||
{renderHeader("Tags", allTagSet, onSelectAllTagSet)}
|
{renderHeader("Tags", allTagSet, onSelectAllTagSet)}
|
||||||
{renderHeader("Studio", allStudioSet, onSelectAllStudioSet)}
|
{renderHeader("Studio", allStudioSet, onSelectAllStudioSet)}
|
||||||
|
|||||||
Reference in New Issue
Block a user