Fix error when viewing scenes related to objects with illegal characters in name (#395)

* Fix gitattributes for v2.5
This commit is contained in:
WithoutPants 2020-03-14 08:06:55 +11:00 committed by GitHub
parent 6f5f3112e1
commit 1a6374fae9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 88 additions and 24 deletions

2
.gitattributes vendored
View File

@ -1,3 +1,3 @@
go.mod text eol=lf go.mod text eol=lf
go.sum text eol=lf go.sum text eol=lf
ui/v2.5/** -text ui/v2.5/**/*.ts* text eol=lf

View File

@ -146,9 +146,7 @@ export const Scene: React.FC = () => {
/> />
</Tab> </Tab>
<Tab eventKey="scene-operations-panel" title="Operations"> <Tab eventKey="scene-operations-panel" title="Operations">
<SceneOperationsPanel <SceneOperationsPanel scene={scene} />
scene={scene}
/>
</Tab> </Tab>
</Tabs> </Tabs>
</div> </div>

View File

@ -9,7 +9,9 @@ interface IOperationsPanelProps {
scene: GQL.SceneDataFragment; scene: GQL.SceneDataFragment;
} }
export const SceneOperationsPanel: FunctionComponent<IOperationsPanelProps> = (props: IOperationsPanelProps) => { export const SceneOperationsPanel: FunctionComponent<IOperationsPanelProps> = (
props: IOperationsPanelProps
) => {
const Toast = useToast(); const Toast = useToast();
const [generateScreenshot] = StashService.useSceneGenerateScreenshot(); const [generateScreenshot] = StashService.useSceneGenerateScreenshot();
@ -25,7 +27,10 @@ export const SceneOperationsPanel: FunctionComponent<IOperationsPanelProps> = (p
return ( return (
<> <>
<Button className="edit-button" onClick={() => onGenerateScreenshot(JWUtils.getPlayer().getPosition())}> <Button
className="edit-button"
onClick={() => onGenerateScreenshot(JWUtils.getPlayer().getPosition())}
>
Generate thumbnail from current Generate thumbnail from current
</Button> </Button>
<Button className="edit-button" onClick={() => onGenerateScreenshot()}> <Button className="edit-button" onClick={() => onGenerateScreenshot()}>

View File

@ -409,7 +409,7 @@ export class StashService {
public static useSceneGenerateScreenshot() { public static useSceneGenerateScreenshot() {
return GQL.useSceneGenerateScreenshotMutation({ return GQL.useSceneGenerateScreenshotMutation({
update: () => StashService.invalidateQueries(["findScenes"]), update: () => StashService.invalidateQueries(["findScenes"])
}); });
} }
@ -514,7 +514,7 @@ export class StashService {
public static mutateStopJob() { public static mutateStopJob() {
return StashService.client.mutate<GQL.StopJobMutation>({ return StashService.client.mutate<GQL.StopJobMutation>({
mutation: GQL.StopJobDocument, mutation: GQL.StopJobDocument
}); });
} }
@ -574,39 +574,39 @@ export class StashService {
public static mutateMetadataScan(input: GQL.ScanMetadataInput) { public static mutateMetadataScan(input: GQL.ScanMetadataInput) {
return StashService.client.mutate<GQL.MetadataScanMutation>({ return StashService.client.mutate<GQL.MetadataScanMutation>({
mutation: GQL.MetadataScanDocument, mutation: GQL.MetadataScanDocument,
variables: { input }, variables: { input }
}); });
} }
public static mutateMetadataAutoTag(input: GQL.AutoTagMetadataInput) { public static mutateMetadataAutoTag(input: GQL.AutoTagMetadataInput) {
return StashService.client.mutate<GQL.MetadataAutoTagMutation>({ return StashService.client.mutate<GQL.MetadataAutoTagMutation>({
mutation: GQL.MetadataAutoTagDocument, mutation: GQL.MetadataAutoTagDocument,
variables: { input }, variables: { input }
}); });
} }
public static mutateMetadataGenerate(input: GQL.GenerateMetadataInput) { public static mutateMetadataGenerate(input: GQL.GenerateMetadataInput) {
return StashService.client.mutate<GQL.MetadataGenerateMutation>({ return StashService.client.mutate<GQL.MetadataGenerateMutation>({
mutation: GQL.MetadataGenerateDocument, mutation: GQL.MetadataGenerateDocument,
variables: { input }, variables: { input }
}); });
} }
public static mutateMetadataClean() { public static mutateMetadataClean() {
return StashService.client.mutate<GQL.MetadataCleanMutation>({ return StashService.client.mutate<GQL.MetadataCleanMutation>({
mutation: GQL.MetadataCleanDocument, mutation: GQL.MetadataCleanDocument
}); });
} }
public static mutateMetadataExport() { public static mutateMetadataExport() {
return StashService.client.mutate<GQL.MetadataExportMutation>({ return StashService.client.mutate<GQL.MetadataExportMutation>({
mutation: GQL.MetadataExportDocument, mutation: GQL.MetadataExportDocument
}); });
} }
public static mutateMetadataImport() { public static mutateMetadataImport() {
return StashService.client.mutate<GQL.MetadataImportMutation>({ return StashService.client.mutate<GQL.MetadataImportMutation>({
mutation: GQL.MetadataImportDocument, mutation: GQL.MetadataImportDocument
}); });
} }

View File

@ -186,6 +186,10 @@ export abstract class Criterion {
} }
} }
*/ */
public encodeValue(): CriterionValue {
return this.value;
}
} }
export interface ICriterionOption { export interface ICriterionOption {

View File

@ -1,5 +1,5 @@
import { CriterionModifier } from "src/core/generated-graphql"; import { CriterionModifier } from "src/core/generated-graphql";
import { ILabeledId, IOptionType } from "../types"; import { ILabeledId, IOptionType, encodeILabeledId } from "../types";
import { Criterion, CriterionType, ICriterionOption } from "./criterion"; import { Criterion, CriterionType, ICriterionOption } from "./criterion";
export class PerformersCriterion extends Criterion { export class PerformersCriterion extends Criterion {
@ -13,6 +13,12 @@ export class PerformersCriterion extends Criterion {
]; ];
public options: IOptionType[] = []; public options: IOptionType[] = [];
public value: ILabeledId[] = []; public value: ILabeledId[] = [];
public encodeValue() {
return this.value.map(o => {
return encodeILabeledId(o);
});
}
} }
export class PerformersCriterionOption implements ICriterionOption { export class PerformersCriterionOption implements ICriterionOption {

View File

@ -1,5 +1,5 @@
import { CriterionModifier } from "src/core/generated-graphql"; import { CriterionModifier } from "src/core/generated-graphql";
import { ILabeledId, IOptionType } from "../types"; import { ILabeledId, IOptionType, encodeILabeledId } from "../types";
import { Criterion, CriterionType, ICriterionOption } from "./criterion"; import { Criterion, CriterionType, ICriterionOption } from "./criterion";
export class StudiosCriterion extends Criterion { export class StudiosCriterion extends Criterion {
@ -12,6 +12,12 @@ export class StudiosCriterion extends Criterion {
]; ];
public options: IOptionType[] = []; public options: IOptionType[] = [];
public value: ILabeledId[] = []; public value: ILabeledId[] = [];
public encodeValue() {
return this.value.map(o => {
return encodeILabeledId(o);
});
}
} }
export class StudiosCriterionOption implements ICriterionOption { export class StudiosCriterionOption implements ICriterionOption {

View File

@ -1,5 +1,5 @@
import * as GQL from "src/core/generated-graphql"; import * as GQL from "src/core/generated-graphql";
import { ILabeledId, IOptionType } from "../types"; import { ILabeledId, IOptionType, encodeILabeledId } from "../types";
import { Criterion, CriterionType, ICriterionOption } from "./criterion"; import { Criterion, CriterionType, ICriterionOption } from "./criterion";
export class TagsCriterion extends Criterion { export class TagsCriterion extends Criterion {
@ -22,6 +22,12 @@ export class TagsCriterion extends Criterion {
this.parameterName = "scene_tags"; this.parameterName = "scene_tags";
} }
} }
public encodeValue() {
return this.value.map(o => {
return encodeILabeledId(o);
});
}
} }
export class TagsCriterionOption implements ICriterionOption { export class TagsCriterionOption implements ICriterionOption {

View File

@ -270,7 +270,11 @@ export class ListFilterModel {
this.criteria.forEach(criterion => { this.criteria.forEach(criterion => {
const encodedCriterion: Partial<Criterion> = { const encodedCriterion: Partial<Criterion> = {
type: criterion.type, type: criterion.type,
value: criterion.value, // #394 - the presence of a # symbol results in the query URL being
// malformed. We could set encode: true in the queryString.stringify
// call below, but this results in a URL that gets pretty long and ugly.
// Instead, we'll encode the criteria values.
value: criterion.encodeValue(),
modifier: criterion.modifier modifier: criterion.modifier
}; };
const jsonCriterion = JSON.stringify(encodedCriterion); const jsonCriterion = JSON.stringify(encodedCriterion);

View File

@ -22,6 +22,10 @@ export interface ILabeledValue {
value: string; value: string;
} }
export function encodeILabeledId(o: ILabeledId) {
return { ...o, label: encodeURIComponent(o.label) };
}
export interface IOptionType { export interface IOptionType {
id: string; id: string;
name?: string; name?: string;

View File

@ -136,6 +136,10 @@ export abstract class Criterion<Option = any, Value = any> {
this.value = value; this.value = value;
} }
} }
public encodeValue(): Value {
return this.value;
}
} }
export interface ICriterionOption { export interface ICriterionOption {

View File

@ -1,5 +1,5 @@
import { CriterionModifier } from "../../../core/generated-graphql"; import { CriterionModifier } from "../../../core/generated-graphql";
import { ILabeledId } from "../types"; import { ILabeledId, encodeILabeledId } from "../types";
import { import {
Criterion, Criterion,
CriterionType, CriterionType,
@ -22,6 +22,10 @@ export class MoviesCriterion extends Criterion<IOptionType, ILabeledId[]> {
]; ];
public options: IOptionType[] = []; public options: IOptionType[] = [];
public value: ILabeledId[] = []; public value: ILabeledId[] = [];
public encodeValue() {
return this.value.map((o) => { return encodeILabeledId(o); });
}
} }
export class MoviesCriterionOption implements ICriterionOption { export class MoviesCriterionOption implements ICriterionOption {

View File

@ -1,5 +1,5 @@
import { CriterionModifier } from "../../../core/generated-graphql"; import { CriterionModifier } from "../../../core/generated-graphql";
import { ILabeledId } from "../types"; import { ILabeledId, encodeILabeledId } from "../types";
import { import {
Criterion, Criterion,
CriterionType, CriterionType,
@ -23,6 +23,10 @@ export class PerformersCriterion extends Criterion<IOptionType, ILabeledId[]> {
]; ];
public options: IOptionType[] = []; public options: IOptionType[] = [];
public value: ILabeledId[] = []; public value: ILabeledId[] = [];
public encodeValue() {
return this.value.map((o) => { return encodeILabeledId(o); });
}
} }
export class PerformersCriterionOption implements ICriterionOption { export class PerformersCriterionOption implements ICriterionOption {

View File

@ -1,5 +1,5 @@
import { CriterionModifier } from "../../../core/generated-graphql"; import { CriterionModifier } from "../../../core/generated-graphql";
import { ILabeledId } from "../types"; import { ILabeledId, encodeILabeledId } from "../types";
import { import {
Criterion, Criterion,
CriterionType, CriterionType,
@ -22,6 +22,10 @@ export class StudiosCriterion extends Criterion<IOptionType, ILabeledId[]> {
]; ];
public options: IOptionType[] = []; public options: IOptionType[] = [];
public value: ILabeledId[] = []; public value: ILabeledId[] = [];
public encodeValue() {
return this.value.map((o) => { return encodeILabeledId(o); });
}
} }
export class StudiosCriterionOption implements ICriterionOption { export class StudiosCriterionOption implements ICriterionOption {

View File

@ -1,6 +1,6 @@
import * as GQL from "../../../core/generated-graphql"; import * as GQL from "../../../core/generated-graphql";
import { CriterionModifier } from "../../../core/generated-graphql"; import { CriterionModifier } from "../../../core/generated-graphql";
import { ILabeledId } from "../types"; import { ILabeledId, encodeILabeledId } from "../types";
import { import {
Criterion, Criterion,
CriterionType, CriterionType,
@ -27,6 +27,10 @@ export class TagsCriterion extends Criterion<GQL.AllTagsForFilterAllTags, ILabel
this.parameterName = "scene_tags"; this.parameterName = "scene_tags";
} }
} }
public encodeValue() {
return this.value.map((o) => { return encodeILabeledId(o); });
}
} }
export class TagsCriterionOption implements ICriterionOption { export class TagsCriterionOption implements ICriterionOption {

View File

@ -271,7 +271,12 @@ export class ListFilterModel {
this.criteria.forEach((criterion) => { this.criteria.forEach((criterion) => {
const encodedCriterion: any = {}; const encodedCriterion: any = {};
encodedCriterion.type = criterion.type; encodedCriterion.type = criterion.type;
encodedCriterion.value = criterion.value; // #394 - the presence of a # symbol results in the query URL being
// malformed. We could set encode: true in the queryString.stringify
// call below, but this results in a URL that gets pretty long and ugly.
// Instead, we'll encode the criteria values.
encodedCriterion.value = criterion.encodeValue();
encodedCriterion.modifier = criterion.modifier; encodedCriterion.modifier = criterion.modifier;
const jsonCriterion = JSON.stringify(encodedCriterion); const jsonCriterion = JSON.stringify(encodedCriterion);
encodedCriteria.push(jsonCriterion); encodedCriteria.push(jsonCriterion);

View File

@ -20,6 +20,12 @@ export interface ILabeledId {
label: string; label: string;
} }
export function encodeILabeledId(o: ILabeledId) {
let ret = Object.assign({}, o);
ret.label = encodeURIComponent(o.label);
return ret;
}
export interface ILabeledValue { export interface ILabeledValue {
label: string; label: string;
value: string; value: string;