diff --git a/nise-frontend/src/app/search/search.component.ts b/nise-frontend/src/app/search/search.component.ts index aa5c0fb..4d214c0 100644 --- a/nise-frontend/src/app/search/search.component.ts +++ b/nise-frontend/src/app/search/search.component.ts @@ -5,17 +5,24 @@ import {HttpClient} from "@angular/common/http"; import {environment} from "../../environments/environment"; import {countryCodeToFlag, formatDuration} from "../format"; import {OsuGradeComponent} from "../../corelib/components/osu-grade/osu-grade.component"; -import {Field, Query, QueryBuilderComponent} from "../../corelib/components/query-builder/query-builder.component"; +import { + FieldType, + Operator, + Query, + QueryBuilderComponent +} from "../../corelib/components/query-builder/query-builder.component"; import {RouterLink} from "@angular/router"; import {CalculatePageRangePipe} from "../../corelib/calculate-page-range.pipe"; import {DownloadFilesService} from "../../corelib/service/download-files.service"; import {CuteLoadingComponent} from "../../corelib/components/cute-loading/cute-loading.component"; +import {Title} from "@angular/platform-browser"; export interface SchemaField { name: string; shortName: string; category: 'user' | 'score' | 'beatmap' | 'metrics'; type: 'number' | 'string' | 'flag' | 'grade' | 'boolean' | 'datetime' | 'playtime'; + validOperators: Operator[]; active: boolean; description: string; } @@ -63,6 +70,7 @@ interface Sorting { export class SearchComponent implements OnInit { constructor(private httpClient: HttpClient, + private title: Title, public downloadFilesService: DownloadFilesService) { } isError = false; @@ -76,10 +84,14 @@ export class SearchComponent implements OnInit { queries: Query[] | null = null; ngOnInit(): void { + this.title.setTitle("/k/ - advanced search"); this.isLoadingSchema = true; this.httpClient.get(`${environment.apiUrl}/search/schema`,).subscribe({ next: (response) => { this.fields = response.fields; + this.fields.forEach(field => { + field.validOperators = this.getOperators(field.type); + }) this.loadPreviousFromLocalStorage(); this.isLoadingSchema = false; }, @@ -89,6 +101,34 @@ export class SearchComponent implements OnInit { }); } + getOperators(fieldType: FieldType | undefined): Operator[] { + switch (fieldType) { + case 'number': + return ['=', '>', '<', '>=', '<=', '!='] + .map((operatorType: String) => ({operatorType: operatorType, acceptsValues: 'any'}) as Operator); + case 'string': + return ['=', 'contains', 'like'] + .map((operatorType: String) => ({operatorType: operatorType, acceptsValues: 'any'}) as Operator); + case 'boolean': + return ['=', '!='] + .map((operatorType: String) => ({operatorType: operatorType, acceptsValues: 'boolean'}) as Operator); + case 'flag': + return ['=', '!='] + .map((operatorType: String) => ({operatorType: operatorType, acceptsValues: 'flag'}) as Operator); + case 'grade': + return ['=', '!='] + .map((operatorType: String) => ({operatorType: operatorType, acceptsValues: 'grade'}) as Operator); + case 'datetime': + return ['before', 'after'] + .map((operatorType: String) => ({operatorType: operatorType, acceptsValues: 'datetime'}) as Operator); + case 'playtime': + return ['>', '<', '>=', '<='] + .map((operatorType: String) => ({operatorType: operatorType, acceptsValues: 'any'}) as Operator); + default: + return []; + } + } + private loadPreviousFromLocalStorage() { const storedQueries = localStorage.getItem('search_settings'); if (storedQueries) { @@ -227,6 +267,6 @@ export class SearchComponent implements OnInit { protected readonly countryCodeToFlag = countryCodeToFlag; protected readonly Math = Math; - protected readonly formatDuration = formatDuration; + } diff --git a/nise-frontend/src/corelib/components/query-builder/query-builder.component.ts b/nise-frontend/src/corelib/components/query-builder/query-builder.component.ts index 5aace96..b7ae1c6 100644 --- a/nise-frontend/src/corelib/components/query-builder/query-builder.component.ts +++ b/nise-frontend/src/corelib/components/query-builder/query-builder.component.ts @@ -8,13 +8,8 @@ export type FieldType = 'number' | 'string' | 'flag' | 'grade' | 'boolean' | 'da export type OperatorType = '=' | '>' | '<' | 'contains' | 'like' | '>=' | '<=' | '!='; export type ValueType = 'any' | 'boolean' | 'flag' | 'grade' | 'datetime'; -export interface Field { - name: string; - type: FieldType; -} - export interface Predicate { - field: Field | null; + field: SchemaField | null; operator: Operator | null; value: string | number | null; } @@ -27,7 +22,7 @@ export interface Operator { export interface Query { predicates: Predicate[]; logicalOperator: 'AND' | 'OR'; - childQueries?: Query[]; // Optional property for sub-queries + childQueries?: Query[]; } @Component({ diff --git a/nise-frontend/src/corelib/components/query/query.component.html b/nise-frontend/src/corelib/components/query/query.component.html index 8f88a2f..fc80666 100644 --- a/nise-frontend/src/corelib/components/query/query.component.html +++ b/nise-frontend/src/corelib/components/query/query.component.html @@ -30,7 +30,7 @@