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,6 +1,6 @@
|
||||
/* 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 _ from "lodash";
|
||||
import { StashService } from "src/core/StashService";
|
||||
@@ -25,6 +25,7 @@ const initialParserInput = {
|
||||
const initialShowFieldsState = new Map<string, boolean>([
|
||||
["Title", true],
|
||||
["Date", true],
|
||||
["Rating", true],
|
||||
["Performers", true],
|
||||
["Tags", true],
|
||||
["Studio", true],
|
||||
@@ -36,9 +37,12 @@ export const SceneFilenameParser: React.FC = () => {
|
||||
const [parserInput, setParserInput] = useState<IParserInput>(
|
||||
initialParserInput
|
||||
);
|
||||
const prevParserInputRef = useRef<IParserInput>();
|
||||
const prevParserInput = prevParserInputRef.current;
|
||||
|
||||
const [allTitleSet, setAllTitleSet] = useState<boolean>(false);
|
||||
const [allDateSet, setAllDateSet] = useState<boolean>(false);
|
||||
const [allRatingSet, setAllRatingSet] = useState<boolean>(false);
|
||||
const [allPerformerSet, setAllPerformerSet] = useState<boolean>(false);
|
||||
const [allTagSet, setAllTagSet] = useState<boolean>(false);
|
||||
const [allStudioSet, setAllStudioSet] = useState<boolean>(false);
|
||||
@@ -54,6 +58,10 @@ export const SceneFilenameParser: React.FC = () => {
|
||||
|
||||
const [updateScenes] = StashService.useScenesUpdate(getScenesUpdateData());
|
||||
|
||||
useEffect(() => {
|
||||
prevParserInputRef.current = parserInput;
|
||||
}, [parserInput]);
|
||||
|
||||
const determineFieldsToHide = useCallback(() => {
|
||||
const { pattern } = parserInput;
|
||||
const titleSet = pattern.includes("{title}");
|
||||
@@ -63,6 +71,7 @@ export const SceneFilenameParser: React.FC = () => {
|
||||
ParserField.fullDateFields.some((f) => {
|
||||
return pattern.includes(`{${f.field}}`);
|
||||
});
|
||||
const ratingSet = pattern.includes("{rating}");
|
||||
const performerSet = pattern.includes("{performer}");
|
||||
const tagSet = pattern.includes("{tag}");
|
||||
const studioSet = pattern.includes("{studio}");
|
||||
@@ -70,6 +79,7 @@ export const SceneFilenameParser: React.FC = () => {
|
||||
const newShowFields = new Map<string, boolean>([
|
||||
["Title", titleSet],
|
||||
["Date", dateSet],
|
||||
["Rating", ratingSet],
|
||||
["Performers", performerSet],
|
||||
["Tags", tagSet],
|
||||
["Studio", studioSet],
|
||||
@@ -96,38 +106,47 @@ export const SceneFilenameParser: React.FC = () => {
|
||||
[determineFieldsToHide]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (parserInput.findClicked) {
|
||||
setParserResult([]);
|
||||
setIsLoading(true);
|
||||
const parseSceneFilenames = useCallback(() => {
|
||||
setParserResult([]);
|
||||
setIsLoading(true);
|
||||
|
||||
const parserFilter = {
|
||||
q: parserInput.pattern,
|
||||
page: parserInput.page,
|
||||
per_page: parserInput.pageSize,
|
||||
sort: "path",
|
||||
direction: GQL.SortDirectionEnum.Asc,
|
||||
};
|
||||
const parserFilter = {
|
||||
q: parserInput.pattern,
|
||||
page: parserInput.page,
|
||||
per_page: parserInput.pageSize,
|
||||
sort: "path",
|
||||
direction: GQL.SortDirectionEnum.Asc,
|
||||
};
|
||||
|
||||
const parserInputData = {
|
||||
ignoreWords: parserInput.ignoreWords,
|
||||
whitespaceCharacters: parserInput.whitespaceCharacters,
|
||||
capitalizeTitle: parserInput.capitalizeTitle,
|
||||
};
|
||||
const parserInputData = {
|
||||
ignoreWords: parserInput.ignoreWords,
|
||||
whitespaceCharacters: parserInput.whitespaceCharacters,
|
||||
capitalizeTitle: parserInput.capitalizeTitle,
|
||||
};
|
||||
|
||||
StashService.queryParseSceneFilenames(parserFilter, parserInputData)
|
||||
.then((response) => {
|
||||
const result = response.data.parseSceneFilenames;
|
||||
if (result) {
|
||||
parseResults(result.results);
|
||||
setTotalItems(result.count);
|
||||
}
|
||||
})
|
||||
.catch((err) => Toast.error(err))
|
||||
.finally(() => setIsLoading(false));
|
||||
}
|
||||
StashService.queryParseSceneFilenames(parserFilter, parserInputData)
|
||||
.then((response) => {
|
||||
const result = response.data.parseSceneFilenames;
|
||||
if (result) {
|
||||
parseResults(result.results);
|
||||
setTotalItems(result.count);
|
||||
}
|
||||
})
|
||||
.catch((err) => Toast.error(err))
|
||||
.finally(() => setIsLoading(false));
|
||||
}, [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) {
|
||||
const newInput = _.clone(parserInput);
|
||||
newInput.page = 1;
|
||||
@@ -144,9 +163,10 @@ export const SceneFilenameParser: React.FC = () => {
|
||||
}
|
||||
|
||||
function onFindClicked(input: IParserInput) {
|
||||
input.page = 1;
|
||||
input.findClicked = true;
|
||||
setParserInput(input);
|
||||
const newInput = _.clone(input);
|
||||
newInput.page = 1;
|
||||
newInput.findClicked = true;
|
||||
setParserInput(newInput);
|
||||
setTotalItems(0);
|
||||
}
|
||||
|
||||
@@ -167,6 +187,9 @@ export const SceneFilenameParser: React.FC = () => {
|
||||
}
|
||||
|
||||
setIsLoading(false);
|
||||
|
||||
// trigger a refresh of the results
|
||||
onFindClicked(parserInput);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
@@ -176,6 +199,9 @@ export const SceneFilenameParser: React.FC = () => {
|
||||
const newAllDateSet = !parserResult.some((r) => {
|
||||
return !r.date.isSet;
|
||||
});
|
||||
const newAllRatingSet = !parserResult.some((r) => {
|
||||
return !r.rating.isSet;
|
||||
});
|
||||
const newAllPerformerSet = !parserResult.some((r) => {
|
||||
return !r.performers.isSet;
|
||||
});
|
||||
@@ -188,6 +214,7 @@ export const SceneFilenameParser: React.FC = () => {
|
||||
|
||||
setAllTitleSet(newAllTitleSet);
|
||||
setAllDateSet(newAllDateSet);
|
||||
setAllRatingSet(newAllRatingSet);
|
||||
setAllTagSet(newAllPerformerSet);
|
||||
setAllTagSet(newAllTagSet);
|
||||
setAllStudioSet(newAllStudioSet);
|
||||
@@ -215,6 +242,17 @@ export const SceneFilenameParser: React.FC = () => {
|
||||
setAllDateSet(selected);
|
||||
}
|
||||
|
||||
function onSelectAllRatingSet(selected: boolean) {
|
||||
const newResult = [...parserResult];
|
||||
|
||||
newResult.forEach((r) => {
|
||||
r.rating.isSet = selected;
|
||||
});
|
||||
|
||||
setParserResult(newResult);
|
||||
setAllRatingSet(selected);
|
||||
}
|
||||
|
||||
function onSelectAllPerformerSet(selected: boolean) {
|
||||
const newResult = [...parserResult];
|
||||
|
||||
@@ -295,6 +333,7 @@ export const SceneFilenameParser: React.FC = () => {
|
||||
<th className="parser-field-filename">Filename</th>
|
||||
{renderHeader("Title", allTitleSet, onSelectAllTitleSet)}
|
||||
{renderHeader("Date", allDateSet, onSelectAllDateSet)}
|
||||
{renderHeader("Rating", allRatingSet, onSelectAllRatingSet)}
|
||||
{renderHeader(
|
||||
"Performers",
|
||||
allPerformerSet,
|
||||
|
||||
Reference in New Issue
Block a user