feat(server,web): improve performances in person page (1) (#4387)

* feat: improve performances in people page

* feat: add loadingspinner when searching

* fix: reset people on error

* fix: case insensitive

* feat: better sql query

* fix: reset people list before api request

* fix: format
This commit is contained in:
martin
2023-10-10 16:34:25 +02:00
committed by GitHub
parent f36c40bc6b
commit b8d6cc1e09
17 changed files with 475 additions and 44 deletions

View File

@@ -3789,6 +3789,50 @@
]
}
},
"/search/person": {
"get": {
"operationId": "searchPerson",
"parameters": [
{
"name": "name",
"required": true,
"in": "query",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"items": {
"$ref": "#/components/schemas/PersonResponseDto"
},
"type": "array"
}
}
},
"description": ""
}
},
"security": [
{
"bearer": []
},
{
"cookie": []
},
{
"api_key": []
}
],
"tags": [
"Search"
]
}
},
"/server-info": {
"get": {
"operationId": "getServerInfo",

View File

@@ -22,6 +22,7 @@ export interface IPersonRepository {
getAllForUser(userId: string, options: PersonSearchOptions): Promise<PersonEntity[]>;
getAllWithoutFaces(): Promise<PersonEntity[]>;
getById(personId: string): Promise<PersonEntity | null>;
getByName(userId: string, personName: string): Promise<PersonEntity[]>;
getAssets(personId: string): Promise<AssetEntity[]>;
prepareReassignFaces(data: UpdateFacesData): Promise<string[]>;

View File

@@ -85,3 +85,9 @@ export class SearchDto {
@Transform(toBoolean)
motion?: boolean;
}
export class SearchPeopleDto {
@IsString()
@IsNotEmpty()
name!: string;
}

View File

@@ -5,6 +5,7 @@ import { AssetResponseDto, mapAsset } from '../asset';
import { AuthUserDto } from '../auth';
import { usePagination } from '../domain.util';
import { IAssetFaceJob, IBulkEntityJob, JOBS_ASSET_PAGINATION_SIZE, JobName } from '../job';
import { PersonResponseDto } from '../person/person.dto';
import {
AssetFaceId,
IAlbumRepository,
@@ -21,7 +22,7 @@ import {
SearchStrategy,
} from '../repositories';
import { FeatureFlag, SystemConfigCore } from '../system-config';
import { SearchDto } from './dto';
import { SearchDto, SearchPeopleDto } from './dto';
import { SearchResponseDto } from './response-dto';
interface SyncQueue {
@@ -158,6 +159,10 @@ export class SearchService {
};
}
async searchPerson(authUser: AuthUserDto, dto: SearchPeopleDto): Promise<PersonResponseDto[]> {
return await this.personRepository.getByName(authUser.id, dto.name);
}
async handleIndexAlbums() {
if (!this.enabled) {
return false;

View File

@@ -1,4 +1,12 @@
import { AuthUserDto, SearchDto, SearchExploreResponseDto, SearchResponseDto, SearchService } from '@app/domain';
import {
AuthUserDto,
PersonResponseDto,
SearchDto,
SearchExploreResponseDto,
SearchPeopleDto,
SearchResponseDto,
SearchService,
} from '@app/domain';
import { Controller, Get, Query } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { AuthUser, Authenticated } from '../app.guard';
@@ -11,6 +19,11 @@ import { UseValidation } from '../app.utils';
export class SearchController {
constructor(private service: SearchService) {}
@Get('person')
searchPerson(@AuthUser() authUser: AuthUserDto, @Query() dto: SearchPeopleDto): Promise<PersonResponseDto[]> {
return this.service.searchPerson(authUser, dto);
}
@Get()
search(@AuthUser() authUser: AuthUserDto, @Query() dto: SearchDto): Promise<SearchResponseDto> {
return this.service.search(authUser, dto);

View File

@@ -95,6 +95,16 @@ export class PersonRepository implements IPersonRepository {
return this.personRepository.findOne({ where: { id: personId } });
}
getByName(userId: string, personName: string): Promise<PersonEntity[]> {
return this.personRepository
.createQueryBuilder('person')
.leftJoin('person.faces', 'face')
.where('person.ownerId = :userId', { userId })
.andWhere('LOWER(person.name) LIKE :name', { name: `${personName.toLowerCase()}%` })
.limit(20)
.getMany();
}
getAssets(personId: string): Promise<AssetEntity[]> {
return this.assetRepository.find({
where: {

View File

@@ -9,6 +9,8 @@ export const newPersonRepositoryMock = (): jest.Mocked<IPersonRepository> => {
getAssets: jest.fn(),
getAllWithoutFaces: jest.fn(),
getByName: jest.fn(),
create: jest.fn(),
update: jest.fn(),
deleteAll: jest.fn(),