diff --git a/graphql/documents/data/performer-slim.graphql b/graphql/documents/data/performer-slim.graphql index fdfa6016bef..c2abc6023b7 100644 --- a/graphql/documents/data/performer-slim.graphql +++ b/graphql/documents/data/performer-slim.graphql @@ -1,5 +1,6 @@ fragment SlimPerformerData on Performer { id name + gender image_path } diff --git a/graphql/documents/data/performer.graphql b/graphql/documents/data/performer.graphql index e2ce624ecc3..cc5e6d2f1d5 100644 --- a/graphql/documents/data/performer.graphql +++ b/graphql/documents/data/performer.graphql @@ -3,6 +3,7 @@ fragment PerformerData on Performer { checksum name url + gender twitter instagram birthdate diff --git a/graphql/documents/mutations/performer.graphql b/graphql/documents/mutations/performer.graphql index ec785f5f237..ae0b5e17fb1 100644 --- a/graphql/documents/mutations/performer.graphql +++ b/graphql/documents/mutations/performer.graphql @@ -1,6 +1,7 @@ mutation PerformerCreate( $name: String, $url: String, + $gender: GenderEnum, $birthdate: String, $ethnicity: String, $country: String, @@ -20,6 +21,7 @@ mutation PerformerCreate( performerCreate(input: { name: $name, url: $url, + gender: $gender, birthdate: $birthdate, ethnicity: $ethnicity, country: $country, @@ -44,6 +46,7 @@ mutation PerformerUpdate( $id: ID!, $name: String, $url: String, + $gender: GenderEnum, $birthdate: String, $ethnicity: String, $country: String, @@ -64,6 +67,7 @@ mutation PerformerUpdate( id: $id, name: $name, url: $url, + gender: $gender, birthdate: $birthdate, ethnicity: $ethnicity, country: $country, diff --git a/graphql/schema/types/filters.graphql b/graphql/schema/types/filters.graphql index 10147033dfe..894f30e50a5 100644 --- a/graphql/schema/types/filters.graphql +++ b/graphql/schema/types/filters.graphql @@ -46,6 +46,8 @@ input PerformerFilterType { piercings: StringCriterionInput """Filter by aliases""" aliases: StringCriterionInput + """Filter by gender""" + gender: GenderCriterionInput } input SceneMarkerFilterType { @@ -114,4 +116,9 @@ input IntCriterionInput { input MultiCriterionInput { value: [ID!] modifier: CriterionModifier! +} + +input GenderCriterionInput { + value: GenderEnum + modifier: CriterionModifier! } \ No newline at end of file diff --git a/graphql/schema/types/performer.graphql b/graphql/schema/types/performer.graphql index a1ba8e6f730..621f23dd975 100644 --- a/graphql/schema/types/performer.graphql +++ b/graphql/schema/types/performer.graphql @@ -1,8 +1,17 @@ +enum GenderEnum { + MALE + FEMALE + TRANSGENDER_MALE + TRANSGENDER_FEMALE + INTERSEX +} + type Performer { id: ID! checksum: String! name: String url: String + gender: GenderEnum twitter: String instagram: String birthdate: String @@ -26,6 +35,7 @@ type Performer { input PerformerCreateInput { name: String url: String + gender: GenderEnum birthdate: String ethnicity: String country: String @@ -48,6 +58,7 @@ input PerformerUpdateInput { id: ID! name: String url: String + gender: GenderEnum birthdate: String ethnicity: String country: String diff --git a/pkg/api/resolver_model_performer.go b/pkg/api/resolver_model_performer.go index 94be0aeead3..29a4d2d9064 100644 --- a/pkg/api/resolver_model_performer.go +++ b/pkg/api/resolver_model_performer.go @@ -2,6 +2,7 @@ package api import ( "context" + "github.com/stashapp/stash/pkg/api/urlbuilders" "github.com/stashapp/stash/pkg/models" ) @@ -20,6 +21,19 @@ func (r *performerResolver) URL(ctx context.Context, obj *models.Performer) (*st return nil, nil } +func (r *performerResolver) Gender(ctx context.Context, obj *models.Performer) (*models.GenderEnum, error) { + var ret models.GenderEnum + + if obj.Gender.Valid { + ret = models.GenderEnum(obj.Gender.String) + if ret.IsValid() { + return &ret, nil + } + } + + return nil, nil +} + func (r *performerResolver) Twitter(ctx context.Context, obj *models.Performer) (*string, error) { if obj.Twitter.Valid { return &obj.Twitter.String, nil diff --git a/pkg/api/resolver_mutation_performer.go b/pkg/api/resolver_mutation_performer.go index 65c0895254b..50e787e2003 100644 --- a/pkg/api/resolver_mutation_performer.go +++ b/pkg/api/resolver_mutation_performer.go @@ -42,6 +42,9 @@ func (r *mutationResolver) PerformerCreate(ctx context.Context, input models.Per if input.URL != nil { newPerformer.URL = sql.NullString{String: *input.URL, Valid: true} } + if input.Gender != nil { + newPerformer.Gender = sql.NullString{String: input.Gender.String(), Valid: true} + } if input.Birthdate != nil { newPerformer.Birthdate = models.SQLiteDate{String: *input.Birthdate, Valid: true} } @@ -128,6 +131,9 @@ func (r *mutationResolver) PerformerUpdate(ctx context.Context, input models.Per if input.URL != nil { updatedPerformer.URL = sql.NullString{String: *input.URL, Valid: true} } + if input.Gender != nil { + updatedPerformer.Gender = sql.NullString{String: input.Gender.String(), Valid: true} + } if input.Birthdate != nil { updatedPerformer.Birthdate = models.SQLiteDate{String: *input.Birthdate, Valid: true} } diff --git a/pkg/database/database.go b/pkg/database/database.go index aedf3e0fc9a..f9f2392affd 100644 --- a/pkg/database/database.go +++ b/pkg/database/database.go @@ -19,7 +19,7 @@ import ( var DB *sqlx.DB var dbPath string -var appSchemaVersion uint = 4 +var appSchemaVersion uint = 5 var databaseSchemaVersion uint const sqlite3Driver = "sqlite3_regexp" diff --git a/pkg/database/migrations/5_performer_gender.down.sql b/pkg/database/migrations/5_performer_gender.down.sql new file mode 100644 index 00000000000..abe9c746cdd --- /dev/null +++ b/pkg/database/migrations/5_performer_gender.down.sql @@ -0,0 +1,89 @@ + +PRAGMA foreign_keys=off; + +-- need to re-create the performers table without the added column. +-- also need re-create the performers_scenes table due to the foreign key + +-- rename existing performers table +ALTER TABLE `performers` RENAME TO `performers_old`; +ALTER TABLE `performers_scenes` RENAME TO `performers_scenes_old`; + +-- drop the indexes +DROP INDEX IF EXISTS `index_performers_on_name`; +DROP INDEX IF EXISTS `index_performers_on_checksum`; +DROP INDEX IF EXISTS `index_performers_scenes_on_scene_id`; +DROP INDEX IF EXISTS `index_performers_scenes_on_performer_id`; + +-- recreate the tables +CREATE TABLE `performers` ( + `id` integer not null primary key autoincrement, + `image` blob not null, + `checksum` varchar(255) not null, + `name` varchar(255), + `url` varchar(255), + `twitter` varchar(255), + `instagram` varchar(255), + `birthdate` date, + `ethnicity` varchar(255), + `country` varchar(255), + `eye_color` varchar(255), + `height` varchar(255), + `measurements` varchar(255), + `fake_tits` varchar(255), + `career_length` varchar(255), + `tattoos` varchar(255), + `piercings` varchar(255), + `aliases` varchar(255), + `favorite` boolean not null default '0', + `created_at` datetime not null, + `updated_at` datetime not null +); + +CREATE TABLE `performers_scenes` ( + `performer_id` integer, + `scene_id` integer, + foreign key(`performer_id`) references `performers`(`id`), + foreign key(`scene_id`) references `scenes`(`id`) +); + +INSERT INTO `performers` + SELECT + `id`, + `image`, + `checksum`, + `name`, + `url`, + `twitter`, + `instagram`, + `birthdate`, + `ethnicity`, + `country`, + `eye_color`, + `height`, + `measurements`, + `fake_tits`, + `career_length`, + `tattoos`, + `piercings`, + `aliases`, + `favorite`, + `created_at`, + `updated_at` + FROM `performers_old`; + +INSERT INTO `performers_scenes` + SELECT + `performer_id`, + `scene_id` + FROM `performers_scenes_old`; + +DROP TABLE `performers_scenes_old`; +DROP TABLE `performers_old`; + +-- re-create the indexes after removing the old tables +CREATE INDEX `index_performers_on_name` on `performers` (`name`); +CREATE INDEX `index_performers_on_checksum` on `performers` (`checksum`); +CREATE INDEX `index_performers_scenes_on_scene_id` on `performers_scenes` (`scene_id`); +CREATE INDEX `index_performers_scenes_on_performer_id` on `performers_scenes` (`performer_id`); + +PRAGMA foreign_keys=on; diff --git a/pkg/database/migrations/5_performer_gender.up.sql b/pkg/database/migrations/5_performer_gender.up.sql new file mode 100644 index 00000000000..1f6e854856e --- /dev/null +++ b/pkg/database/migrations/5_performer_gender.up.sql @@ -0,0 +1 @@ +ALTER TABLE `performers` ADD COLUMN `gender` varchar(20); diff --git a/pkg/manager/jsonschema/performer.go b/pkg/manager/jsonschema/performer.go index 44aec069a4a..18b64d9eb95 100644 --- a/pkg/manager/jsonschema/performer.go +++ b/pkg/manager/jsonschema/performer.go @@ -3,12 +3,14 @@ package jsonschema import ( "encoding/json" "fmt" - "github.com/stashapp/stash/pkg/models" "os" + + "github.com/stashapp/stash/pkg/models" ) type Performer struct { Name string `json:"name,omitempty"` + Gender string `json:"gender,omitempty"` URL string `json:"url,omitempty"` Twitter string `json:"twitter,omitempty"` Instagram string `json:"instagram,omitempty"` diff --git a/pkg/manager/task_export.go b/pkg/manager/task_export.go index 0599a0eaa2c..96ccd88409b 100644 --- a/pkg/manager/task_export.go +++ b/pkg/manager/task_export.go @@ -238,6 +238,9 @@ func (t *ExportTask) ExportPerformers(ctx context.Context) { if performer.Name.Valid { newPerformerJSON.Name = performer.Name.String } + if performer.Gender.Valid { + newPerformerJSON.Gender = performer.Gender.String + } if performer.URL.Valid { newPerformerJSON.URL = performer.URL.String } diff --git a/pkg/manager/task_import.go b/pkg/manager/task_import.go index 218869f416b..15795b4c334 100644 --- a/pkg/manager/task_import.go +++ b/pkg/manager/task_import.go @@ -94,6 +94,9 @@ func (t *ImportTask) ImportPerformers(ctx context.Context) { if performerJSON.Name != "" { newPerformer.Name = sql.NullString{String: performerJSON.Name, Valid: true} } + if performerJSON.Gender != "" { + newPerformer.Gender = sql.NullString{String: performerJSON.Gender, Valid: true} + } if performerJSON.URL != "" { newPerformer.URL = sql.NullString{String: performerJSON.URL, Valid: true} } @@ -241,19 +244,19 @@ func (t *ImportTask) ImportMovies(ctx context.Context) { // Populate a new movie from the input newMovie := models.Movie{ - FrontImage: frontimageData, - BackImage: backimageData, - Checksum: checksum, - Name: sql.NullString{String: movieJSON.Name, Valid: true}, - Aliases: sql.NullString{String: movieJSON.Aliases, Valid: true}, - Date: models.SQLiteDate{String: movieJSON.Date, Valid: true}, - Duration: sql.NullString{String: movieJSON.Duration, Valid: true}, - Rating: sql.NullString{String: movieJSON.Rating, Valid: true}, - Director: sql.NullString{String: movieJSON.Director, Valid: true}, - Synopsis: sql.NullString{String: movieJSON.Synopsis, Valid: true}, - URL: sql.NullString{String: movieJSON.URL, Valid: true}, - CreatedAt: models.SQLiteTimestamp{Timestamp: t.getTimeFromJSONTime(movieJSON.CreatedAt)}, - UpdatedAt: models.SQLiteTimestamp{Timestamp: t.getTimeFromJSONTime(movieJSON.UpdatedAt)}, + FrontImage: frontimageData, + BackImage: backimageData, + Checksum: checksum, + Name: sql.NullString{String: movieJSON.Name, Valid: true}, + Aliases: sql.NullString{String: movieJSON.Aliases, Valid: true}, + Date: models.SQLiteDate{String: movieJSON.Date, Valid: true}, + Duration: sql.NullString{String: movieJSON.Duration, Valid: true}, + Rating: sql.NullString{String: movieJSON.Rating, Valid: true}, + Director: sql.NullString{String: movieJSON.Director, Valid: true}, + Synopsis: sql.NullString{String: movieJSON.Synopsis, Valid: true}, + URL: sql.NullString{String: movieJSON.URL, Valid: true}, + CreatedAt: models.SQLiteTimestamp{Timestamp: t.getTimeFromJSONTime(movieJSON.CreatedAt)}, + UpdatedAt: models.SQLiteTimestamp{Timestamp: t.getTimeFromJSONTime(movieJSON.UpdatedAt)}, } _, err = qb.Create(newMovie, tx) diff --git a/pkg/models/model_performer.go b/pkg/models/model_performer.go index 8d3beb3dbcc..71818a02500 100644 --- a/pkg/models/model_performer.go +++ b/pkg/models/model_performer.go @@ -9,6 +9,7 @@ type Performer struct { Image []byte `db:"image" json:"image"` Checksum string `db:"checksum" json:"checksum"` Name sql.NullString `db:"name" json:"name"` + Gender sql.NullString `db:"gender" json:"gender"` URL sql.NullString `db:"url" json:"url"` Twitter sql.NullString `db:"twitter" json:"twitter"` Instagram sql.NullString `db:"instagram" json:"instagram"` diff --git a/pkg/models/querybuilder_performer.go b/pkg/models/querybuilder_performer.go index 35e011849bd..84991c16137 100644 --- a/pkg/models/querybuilder_performer.go +++ b/pkg/models/querybuilder_performer.go @@ -18,10 +18,10 @@ func NewPerformerQueryBuilder() PerformerQueryBuilder { func (qb *PerformerQueryBuilder) Create(newPerformer Performer, tx *sqlx.Tx) (*Performer, error) { ensureTx(tx) result, err := tx.NamedExec( - `INSERT INTO performers (image, checksum, name, url, twitter, instagram, birthdate, ethnicity, country, + `INSERT INTO performers (image, checksum, name, url, gender, twitter, instagram, birthdate, ethnicity, country, eye_color, height, measurements, fake_tits, career_length, tattoos, piercings, aliases, favorite, created_at, updated_at) - VALUES (:image, :checksum, :name, :url, :twitter, :instagram, :birthdate, :ethnicity, :country, + VALUES (:image, :checksum, :name, :url, :gender, :twitter, :instagram, :birthdate, :ethnicity, :country, :eye_color, :height, :measurements, :fake_tits, :career_length, :tattoos, :piercings, :aliases, :favorite, :created_at, :updated_at) `, @@ -153,6 +153,11 @@ func (qb *PerformerQueryBuilder) Query(performerFilter *PerformerFilterType, fin query.addArg(thisArgs...) } + if gender := performerFilter.Gender; gender != nil { + query.addWhere("performers.gender = ?") + query.addArg(gender.Value.String()) + } + handleStringCriterion(tableName+".ethnicity", performerFilter.Ethnicity, &query) handleStringCriterion(tableName+".country", performerFilter.Country, &query) handleStringCriterion(tableName+".eye_color", performerFilter.EyeColor, &query) diff --git a/ui/v2.5/src/components/Performers/PerformerDetails/PerformerDetailsPanel.tsx b/ui/v2.5/src/components/Performers/PerformerDetails/PerformerDetailsPanel.tsx index 5ca968d60c2..385a41ee318 100644 --- a/ui/v2.5/src/components/Performers/PerformerDetails/PerformerDetailsPanel.tsx +++ b/ui/v2.5/src/components/Performers/PerformerDetails/PerformerDetailsPanel.tsx @@ -64,6 +64,7 @@ export const PerformerDetailsPanel: React.FC = ({ const [url, setUrl] = useState(); const [twitter, setTwitter] = useState(); const [instagram, setInstagram] = useState(); + const [gender, setGender] = useState(undefined); // Network state const [isLoading, setIsLoading] = useState(false); @@ -92,6 +93,7 @@ export const PerformerDetailsPanel: React.FC = ({ setUrl(state.url ?? undefined); setTwitter(state.twitter ?? undefined); setInstagram(state.instagram ?? undefined); + setGender(StashService.genderToString((state as GQL.PerformerDataFragment).gender ?? undefined)); } function updatePerformerEditStateFromScraper( @@ -153,7 +155,8 @@ export const PerformerDetailsPanel: React.FC = ({ url, twitter, instagram, - image + image, + gender: StashService.stringToGender(gender) }; if (!isNew) { @@ -397,6 +400,16 @@ export const PerformerDetailsPanel: React.FC = ({ } } + function renderGender() { + return TableUtils.renderHtmlSelect({ + title: "Gender", + value: gender, + isEditing: !!isEditing, + onChange: (value: string) => setGender(value), + selectOptions: [""].concat(StashService.getGenderStrings()), + }); + } + return ( <> {renderDeleteAlert()} @@ -406,6 +419,7 @@ export const PerformerDetailsPanel: React.FC = ({ {maybeRenderName()} {maybeRenderAliases()} + {renderGender()} {TableUtils.renderInputGroup({ title: "Birthdate", value: birthdate, diff --git a/ui/v2.5/src/core/StashService.ts b/ui/v2.5/src/core/StashService.ts index f8afb6f8381..471bf476077 100644 --- a/ui/v2.5/src/core/StashService.ts +++ b/ui/v2.5/src/core/StashService.ts @@ -681,6 +681,40 @@ export class StashService { }); } + private static stringGenderMap = new Map( + [["Male", GQL.GenderEnum.Male], + ["Female", GQL.GenderEnum.Female], + ["Transgender Male", GQL.GenderEnum.TransgenderMale], + ["Transgender Female", GQL.GenderEnum.TransgenderFemale], + ["Intersex", GQL.GenderEnum.Intersex]] + ); + + public static genderToString(value?: GQL.GenderEnum) { + if (!value) { + return undefined; + } + + const foundEntry = Array.from(StashService.stringGenderMap.entries()).find((e) => { + return e[1] === value; + }); + + if (foundEntry) { + return foundEntry[0]; + } + } + + public static stringToGender(value?: string) { + if (!value) { + return undefined; + } + + return StashService.stringGenderMap.get(value); + } + + public static getGenderStrings() { + return Array.from(StashService.stringGenderMap.keys()); + } + // eslint-disable-next-line @typescript-eslint/no-empty-function private constructor() {} } diff --git a/ui/v2.5/src/models/list-filter/criteria/criterion.ts b/ui/v2.5/src/models/list-filter/criteria/criterion.ts index 0c18df5d11f..752131b20f3 100644 --- a/ui/v2.5/src/models/list-filter/criteria/criterion.ts +++ b/ui/v2.5/src/models/list-filter/criteria/criterion.ts @@ -29,7 +29,8 @@ export type CriterionType = | "career_length" | "tattoos" | "piercings" - | "aliases"; + | "aliases" + | "gender"; type Option = string | number | IOptionType; export type CriterionValue = string | number | ILabeledId[]; @@ -87,6 +88,8 @@ export abstract class Criterion { return "Piercings"; case "aliases": return "Aliases"; + case "gender": + return "Gender"; } } diff --git a/ui/v2.5/src/models/list-filter/criteria/gender.ts b/ui/v2.5/src/models/list-filter/criteria/gender.ts new file mode 100644 index 00000000000..42a675a958d --- /dev/null +++ b/ui/v2.5/src/models/list-filter/criteria/gender.ts @@ -0,0 +1,21 @@ +import { CriterionModifier } from "src/core/generated-graphql"; +import { StashService } from "src/core/StashService"; +import { + Criterion, + CriterionType, + ICriterionOption, +} from "./criterion"; + +export class GenderCriterion extends Criterion { + public type: CriterionType = "gender"; + public parameterName: string = "gender"; + public modifier = CriterionModifier.Equals; + public modifierOptions = []; + public options: string[] = StashService.getGenderStrings(); + public value: string = ""; +} + +export class GenderCriterionOption implements ICriterionOption { + public label: string = Criterion.getLabel("gender"); + public value: CriterionType = "gender"; +} diff --git a/ui/v2.5/src/models/list-filter/criteria/utils.ts b/ui/v2.5/src/models/list-filter/criteria/utils.ts index c4d6040fe92..afd265d05b3 100644 --- a/ui/v2.5/src/models/list-filter/criteria/utils.ts +++ b/ui/v2.5/src/models/list-filter/criteria/utils.ts @@ -16,6 +16,7 @@ import { RatingCriterion } from "./rating"; import { ResolutionCriterion } from "./resolution"; import { StudiosCriterion } from "./studios"; import { TagsCriterion } from "./tags"; +import { GenderCriterion } from "./gender"; import { MoviesCriterion } from "./movies"; export function makeCriteria(type: CriterionType = "none") { @@ -60,6 +61,8 @@ export function makeCriteria(type: CriterionType = "none") { ]; return ret; } + case "gender": + return new GenderCriterion(); case "ethnicity": case "country": case "eye_color": diff --git a/ui/v2.5/src/models/list-filter/filter.ts b/ui/v2.5/src/models/list-filter/filter.ts index 29aaf43d43a..1fdb8ba67b5 100644 --- a/ui/v2.5/src/models/list-filter/filter.ts +++ b/ui/v2.5/src/models/list-filter/filter.ts @@ -46,6 +46,8 @@ import { } from "./criteria/tags"; import { makeCriteria } from "./criteria/utils"; import { DisplayMode, FilterMode } from "./types"; +import { GenderCriterionOption, GenderCriterion } from "./criteria/gender"; +import { StashService } from "src/core/StashService"; import { MoviesCriterionOption, MoviesCriterion } from "./criteria/movies"; interface IQueryParameters { @@ -141,7 +143,8 @@ export class ListFilterModel { this.criterionOptions = [ new NoneCriterionOption(), - new FavoriteCriterionOption() + new FavoriteCriterionOption(), + new GenderCriterionOption(), ]; this.criterionOptions = this.criterionOptions.concat( @@ -502,6 +505,11 @@ export class ListFilterModel { result.aliases = { value: aCrit.value, modifier: aCrit.modifier }; break; } + case "gender": { + const gCrit = criterion as GenderCriterion; + result.gender = { value: StashService.stringToGender(gCrit.value), modifier: gCrit.modifier }; + break; + } // no default } }); diff --git a/ui/v2/src/components/performers/PerformerDetails/PerformerDetailsPanel.tsx b/ui/v2/src/components/performers/PerformerDetails/PerformerDetailsPanel.tsx index e4e9b795c4d..261256995bf 100644 --- a/ui/v2/src/components/performers/PerformerDetails/PerformerDetailsPanel.tsx +++ b/ui/v2/src/components/performers/PerformerDetails/PerformerDetailsPanel.tsx @@ -54,6 +54,7 @@ export const PerformerDetailsPanel: FunctionComponent = const [url, setUrl] = useState(undefined); const [twitter, setTwitter] = useState(undefined); const [instagram, setInstagram] = useState(undefined); + const [gender, setGender] = useState(undefined); // Network state const [isLoading, setIsLoading] = useState(false); @@ -80,6 +81,7 @@ export const PerformerDetailsPanel: FunctionComponent = setUrl(state.url); setTwitter(state.twitter); setInstagram(state.instagram); + setGender(StashService.genderToString((state as GQL.PerformerDataFragment).gender)); } function updatePerformerEditStateFromScraper(state: Partial) { @@ -147,6 +149,7 @@ export const PerformerDetailsPanel: FunctionComponent = twitter, instagram, image, + gender: StashService.stringToGender(gender) }; if (!props.isNew) { @@ -373,6 +376,16 @@ export const PerformerDetailsPanel: FunctionComponent = } } + function renderGender() { + return TableUtils.renderHtmlSelect({ + title: "Gender", + value: gender, + isEditing: !!props.isEditing, + onChange: (value: string) => setGender(value), + selectOptions: [""].concat(StashService.getGenderStrings()), + }); + } + const twitterPrefix = "https://twitter.com/"; const instagramPrefix = "https://www.instagram.com/"; @@ -385,6 +398,7 @@ export const PerformerDetailsPanel: FunctionComponent = {maybeRenderName()} {maybeRenderAliases()} + {renderGender()} {TableUtils.renderInputGroup( {title: "Birthdate (YYYY-MM-DD)", value: birthdate, isEditing: !!props.isEditing, onChange: setBirthdate})} {renderEthnicity()} diff --git a/ui/v2/src/core/StashService.ts b/ui/v2/src/core/StashService.ts index dd0310b0490..1db69e2d470 100644 --- a/ui/v2/src/core/StashService.ts +++ b/ui/v2/src/core/StashService.ts @@ -580,6 +580,40 @@ export class StashService { }); } + private static stringGenderMap = new Map( + [["Male", GQL.GenderEnum.Male], + ["Female", GQL.GenderEnum.Female], + ["Transgender Male", GQL.GenderEnum.TransgenderMale], + ["Transgender Female", GQL.GenderEnum.TransgenderFemale], + ["Intersex", GQL.GenderEnum.Intersex]] + ); + + public static genderToString(value?: GQL.GenderEnum) { + if (!value) { + return undefined; + } + + const foundEntry = Array.from(StashService.stringGenderMap.entries()).find((e) => { + return e[1] === value; + }); + + if (foundEntry) { + return foundEntry[0]; + } + } + + public static stringToGender(value?: string) { + if (!value) { + return undefined; + } + + return StashService.stringGenderMap.get(value); + } + + public static getGenderStrings() { + return Array.from(StashService.stringGenderMap.keys()); + } + public static nullToUndefined(value: any): any { if (_.isPlainObject(value)) { return _.mapValues(value, StashService.nullToUndefined); diff --git a/ui/v2/src/models/list-filter/criteria/criterion.ts b/ui/v2/src/models/list-filter/criteria/criterion.ts index a660371bb28..dd72fc80e27 100644 --- a/ui/v2/src/models/list-filter/criteria/criterion.ts +++ b/ui/v2/src/models/list-filter/criteria/criterion.ts @@ -28,7 +28,8 @@ export type CriterionType = "career_length" | "tattoos" | "piercings" | - "aliases"; + "aliases" | + "gender"; export abstract class Criterion