Don't load all people for search, display series being merged in

This commit is contained in:
Amelia 2025-05-08 13:44:28 +02:00
parent 940fe80609
commit 39b6382467
No known key found for this signature in database
GPG key ID: D6D0ECE365407EAA
6 changed files with 44 additions and 8 deletions

View file

@ -48,6 +48,13 @@ public class PersonController : BaseApiController
return Ok(await _unitOfWork.PersonRepository.GetPersonDtoByName(name, User.GetUserId()));
}
[HttpGet("search-people")]
public async Task<ActionResult<List<PersonDto>>> SearchPeople([FromQuery] string name)
{
var people = await _unitOfWork.PersonRepository.SearchPeople(name);
return Ok(people.Select(person => _mapper.Map<PersonDto>(person)).ToList());
}
/// <summary>
/// Returns all roles for a Person
/// </summary>

View file

@ -67,6 +67,8 @@ public interface IPersonRepository
/// <returns></returns>
Task<IList<Person>> GetPeopleByNames(List<string> normalizedNames, PersonIncludes includes = PersonIncludes.Aliases);
Task<Person?> GetPersonByAniListId(int aniListId, PersonIncludes includes = PersonIncludes.Aliases);
Task<IList<Person>> SearchPeople(string query, PersonIncludes includes = PersonIncludes.Aliases);
}
public class PersonRepository : IPersonRepository
@ -303,6 +305,15 @@ public class PersonRepository : IPersonRepository
.FirstOrDefaultAsync();
}
public async Task<IList<Person>> SearchPeople(string query, PersonIncludes includes = PersonIncludes.Aliases)
{
return await _context.Person
.Includes(includes)
.Where(p => EF.Functions.Like(p.Name, $"%{query}%")
|| p.Aliases.Any(pa => EF.Functions.Like(pa.Alias, $"%{query}%")))
.ToListAsync();
}
public async Task<IList<Person>> GetAllPeople(PersonIncludes includes = PersonIncludes.Aliases)
{
return await _context.Person

View file

@ -30,8 +30,8 @@ export class PersonService {
return this.httpClient.get<Person | null>(this.baseUrl + `person?name=${name}`);
}
getAliases(personId: number) {
return this.httpClient.get<Array<string>>(this.baseUrl + `person/aliases?personId=${personId}`);
searchPerson(name: string) {
return this.httpClient.get<Array<Person>>(this.baseUrl + `person/search-people?name=${name}`);
}
getRolesForPerson(personId: number) {

View file

@ -41,6 +41,15 @@
</ng-template>
</app-badge-expander>
@if (knownFor$ | async; as knownFor) {
<h5 class="mt-2">{{t('known-for-title')}}</h5>
<app-badge-expander [items]="knownFor">
<ng-template #badgeExpanderItem let-item let-position="idx" let-last="last">
{{item.name}}
</ng-template>
</app-badge-expander>
}
</div>
</div>
</div>

View file

@ -1,4 +1,4 @@
import {Component, EventEmitter, inject, Input, OnInit} from '@angular/core';
import {Component, DestroyRef, EventEmitter, inject, Input, OnInit} from '@angular/core';
import {Person} from "../../../_models/metadata/person";
import {PersonService} from "../../../_services/person.service";
import {NgbActiveModal} from "@ng-bootstrap/ng-bootstrap";
@ -8,10 +8,13 @@ import {TypeaheadComponent} from "../../../typeahead/_components/typeahead.compo
import {TypeaheadSettings} from "../../../typeahead/_models/typeahead-settings";
import {map} from "rxjs/operators";
import {UtilityService} from "../../../shared/_services/utility.service";
import {MetadataService} from "../../../_services/metadata.service";
import {SettingItemComponent} from "../../../settings/_components/setting-item/setting-item.component";
import {BadgeExpanderComponent} from "../../../shared/badge-expander/badge-expander.component";
import {FilterField} from "../../../_models/metadata/v2/filter-field";
import {Observable, of} from "rxjs";
import {Series} from "../../../_models/series";
import {takeUntilDestroyed} from "@angular/core/rxjs-interop";
import {AsyncPipe} from "@angular/common";
@Component({
selector: 'app-merge-person-modal',
@ -19,7 +22,8 @@ import {FilterField} from "../../../_models/metadata/v2/filter-field";
TranslocoDirective,
TypeaheadComponent,
SettingItemComponent,
BadgeExpanderComponent
BadgeExpanderComponent,
AsyncPipe
],
templateUrl: './merge-person-modal.component.html',
styleUrl: './merge-person-modal.component.scss'
@ -28,7 +32,7 @@ export class MergePersonModalComponent implements OnInit {
private readonly personService = inject(PersonService);
public readonly utilityService = inject(UtilityService);
private readonly metadataService = inject(MetadataService);
private readonly destroyRef = inject(DestroyRef);
private readonly modal = inject(NgbActiveModal);
protected readonly toastr = inject(ToastrService);
@ -38,6 +42,7 @@ export class MergePersonModalComponent implements OnInit {
@Input({required: true}) person!: Person;
mergee: Person | null = null;
knownFor$: Observable<Series[]> | null = null;
save() {
if (!this.mergee) {
@ -67,7 +72,8 @@ export class MergePersonModalComponent implements OnInit {
return a.name == b.name;
}
this.typeAheadSettings.fetchFn = (filter: string) => {
return this.metadataService.getAllPeople().pipe(map(people => {
if (filter.length == 0) return of([]);
return this.personService.searchPerson(filter).pipe(map(people => {
return people.filter(p => this.utilityService.filter(p.name, filter) && p.id != this.person.id);
}));
};
@ -80,6 +86,8 @@ export class MergePersonModalComponent implements OnInit {
this.typeAheadUnfocus.emit(this.typeAheadSettings.id);
this.mergee = people[0];
this.knownFor$ = this.personService.getSeriesMostKnownFor(this.mergee.id)
.pipe(takeUntilDestroyed(this.destroyRef));
}
protected readonly FilterField = FilterField;

View file

@ -2278,7 +2278,8 @@
"save": "{{common.save}}",
"src": "Merge Person",
"merge-warning": "If you proceed, the selected person will be removed. If the target person has no existing names, the selected person's name will be added as their first name. Otherwise, the selected person's name will be added as an additional alias.",
"alias-title": "New aliases"
"alias-title": "New aliases",
"known-for-title": "Known for"
},
"day-breakdown": {