diff --git a/mediarepo-ui/src/api/models/FilterQueryBuilder.ts b/mediarepo-ui/src/api/models/FilterQueryBuilder.ts index b75c879..04a8a39 100644 --- a/mediarepo-ui/src/api/models/FilterQueryBuilder.ts +++ b/mediarepo-ui/src/api/models/FilterQueryBuilder.ts @@ -143,7 +143,7 @@ export class FilterQueryBuilder { } break; case "FileSize": - value = this.parsePropertyValue(compareValue, parseNumber); + value = this.parsePropertyValue(compareValue, parseByteSize); if (value != undefined) { return this.fileSize(value[0], comparator, value[1]); } @@ -280,6 +280,35 @@ function parseNumber(value: string): number | undefined { return isNaN(num) ? undefined : num; } +function parseByteSize(value: string): number | undefined { + const valueMappings: { [key: string]: number } = { + "TiB": 1024 ** 4, + "GiB": 1024 ** 3, + "MiB": 1024 ** 2, + "KiB": 1024, + "TB": 1000 ** 4, + "GB": 1000 ** 3, + "MB": 1000 ** 2, + "KB": 1000 + }; + const stringValue = value.replace(/TiB|GiB|MiB|KiB|TB|GB|MB|KB$/i, ""); + let number = parseNumber(stringValue); + const checkUnit = (unit: string) => value.toLowerCase().includes(unit.toLowerCase()); + + if (number) { + for (const key of Object.keys(valueMappings)) { + if (checkUnit(key)) { + console.log("key", key, "valueMapping", valueMappings[key]); + number *= valueMappings[key]; + console.log("number", number); + break; + } + } + } + + return number; +} + function parseDate(value: string): Date | undefined { const date = Date.parse(value); diff --git a/mediarepo-ui/src/app/components/shared/input/filter-input/filter-input.component.html b/mediarepo-ui/src/app/components/shared/input/filter-input/filter-input.component.html index 072c1fb..6b0788d 100644 --- a/mediarepo-ui/src/app/components/shared/input/filter-input/filter-input.component.html +++ b/mediarepo-ui/src/app/components/shared/input/filter-input/filter-input.component.html @@ -6,6 +6,7 @@ (keydown.enter)="addExpressionByInput()" [formControl]="formControl" [matAutocomplete]="auto" + [value]="this.value" matInput> (); @@ -57,6 +58,9 @@ export class FilterInputComponent implements OnChanges { ); this.tagsForAutocomplete = this.availableTags.map( t => t.getNormalizedOutput()); + if (this.value) { + this.formControl.setValue(this.value); + } } ngOnChanges(changes: SimpleChanges): void { @@ -64,6 +68,9 @@ export class FilterInputComponent implements OnChanges { this.tagsForAutocomplete = this.availableTags.map( t => t.getNormalizedOutput()); } + if (changes["value"] && this.value) { + this.formControl.setValue(this.value); + } } public addExpressionByInput(): void { @@ -72,7 +79,6 @@ export class FilterInputComponent implements OnChanges { return; } const expressions = FilterQueryBuilder.buildFilterExpressionsFromString(this.formControl.value); - console.log(this.formControl.value, expressions); let valid: boolean; diff --git a/mediarepo-ui/src/app/components/shared/sidebar/file-search/file-search.component.html b/mediarepo-ui/src/app/components/shared/sidebar/file-search/file-search.component.html index 6ff8e10..9910822 100644 --- a/mediarepo-ui/src/app/components/shared/sidebar/file-search/file-search.component.html +++ b/mediarepo-ui/src/app/components/shared/sidebar/file-search/file-search.component.html @@ -4,7 +4,9 @@
-
@@ -19,6 +21,7 @@ + + + + diff --git a/mediarepo-ui/src/app/components/shared/sidebar/file-search/file-search.component.ts b/mediarepo-ui/src/app/components/shared/sidebar/file-search/file-search.component.ts index 17a8866..e7d2f88 100644 --- a/mediarepo-ui/src/app/components/shared/sidebar/file-search/file-search.component.ts +++ b/mediarepo-ui/src/app/components/shared/sidebar/file-search/file-search.component.ts @@ -9,7 +9,8 @@ import {clipboard} from "@tauri-apps/api"; import {TabState} from "../../../../models/TabState"; import {FilterQueryBuilder} from "../../../../../api/models/FilterQueryBuilder"; import {SearchFilters} from "../../../../../api/models/SearchFilters"; -import {FilterExpression} from "../../../../../api/api-types/files"; +import {FilterExpression,} from "../../../../../api/api-types/files"; +import {filterExpressionToString} from "../../../../utils/filter-utils"; @Component({ @@ -29,10 +30,11 @@ export class FileSearchComponent implements AfterViewChecked, OnInit { @Output() searchStartEvent = new EventEmitter(); @Output() searchEndEvent = new EventEmitter(); - @ViewChild("tagInput") tagInput!: ElementRef; @ViewChild("tagInputList") inputList!: ElementRef; public contextMenuTag: Tag | undefined; + public contextMenuFilter: FilterExpression | undefined = undefined; + public initialFilterInputValue: string | undefined; constructor( private errorBroker: ErrorBrokerService, @@ -136,4 +138,8 @@ export class FileSearchComponent implements AfterViewChecked, OnInit { public async copyToClipboard(text: string) { await clipboard.writeText(text); } + + public addFilterToInput(param: FilterExpression): void { + this.initialFilterInputValue = filterExpressionToString(param); + } } diff --git a/mediarepo-ui/src/app/components/shared/sidebar/file-search/filter-expression-item/property-query-item/property-query-item.component.ts b/mediarepo-ui/src/app/components/shared/sidebar/file-search/filter-expression-item/property-query-item/property-query-item.component.ts index 9b8aab6..b8b8e42 100644 --- a/mediarepo-ui/src/app/components/shared/sidebar/file-search/filter-expression-item/property-query-item/property-query-item.component.ts +++ b/mediarepo-ui/src/app/components/shared/sidebar/file-search/filter-expression-item/property-query-item/property-query-item.component.ts @@ -1,5 +1,6 @@ import {Component, Input, OnChanges, OnInit, SimpleChanges} from "@angular/core"; -import {PropertyQuery, ValueComparator} from "../../../../../../../api/api-types/files"; +import {PropertyQuery} from "../../../../../../../api/api-types/files"; +import {propertyQueryToString} from "../../../../../../utils/filter-utils"; @Component({ selector: "app-property-query-item", @@ -15,87 +16,13 @@ export class PropertyQueryItemComponent implements OnInit, OnChanges { constructor() { } - private static buildExpression(property: string, comparator: string, value: string): string { - return `.${property} ${comparator} ${value}`; - } - public ngOnInit(): void { - this.stringExpression = this.getStringExpression(); + this.stringExpression = propertyQueryToString(this.propertyQuery); } public ngOnChanges(changes: SimpleChanges): void { if (changes["propertyQuery"]) { - this.stringExpression = this.getStringExpression(); - } - } - - public getStringExpression(): string { - if ("Status" in this.propertyQuery) { - return PropertyQueryItemComponent.buildExpression("Status", "is", this.propertyQuery.Status); - } else if ("FileSize" in this.propertyQuery) { - return PropertyQueryItemComponent.buildExpression( - "FileSize", - this.getComparator(this.propertyQuery.FileSize), - this.getValue(this.propertyQuery.FileSize).toString() - ); - } else if ("ImportedTime" in this.propertyQuery) { - return PropertyQueryItemComponent.buildExpression( - "ImportedTime", - this.getComparator(this.propertyQuery.ImportedTime), - this.getValue(this.propertyQuery.ImportedTime).toISOString() - ); - } else if ("ChangedTime" in this.propertyQuery) { - return PropertyQueryItemComponent.buildExpression( - "ChangedTime", - this.getComparator(this.propertyQuery.ChangedTime), - this.getValue(this.propertyQuery.ChangedTime).toISOString() - ); - } else if ("CreatedTime" in this.propertyQuery) { - return PropertyQueryItemComponent.buildExpression( - "CreatedTime", - this.getComparator(this.propertyQuery.CreatedTime), - this.getValue(this.propertyQuery.CreatedTime).toISOString() - ); - } else if ("TagCount" in this.propertyQuery) { - return PropertyQueryItemComponent.buildExpression( - "TagCount", - this.getComparator(this.propertyQuery.TagCount), - this.getValue(this.propertyQuery.TagCount).toString() - ); - } else if ("Cd" in this.propertyQuery) { - return PropertyQueryItemComponent.buildExpression("ContentDescriptor", "is", this.propertyQuery.Cd); - } else if ("Id" in this.propertyQuery) { - return PropertyQueryItemComponent.buildExpression("FileId", "is", this.propertyQuery.Id.toString()); - } else { - return "Invalid Expression"; - } - } - - public getComparator(value: ValueComparator): "=" | "<" | ">" | "between" { - if ("Greater" in value) { - return ">"; - } else if ("Equal" in value) { - return "="; - } else if ("Less" in value) { - return "<"; - } else { - return "between"; - } - } - - public getValue(value: ValueComparator): T { - const singleValueKeys: ("Greater" | "Equal" | "Less")[] = ["Greater", "Equal", "Less"]; - - for (const key of singleValueKeys) { - if (key in value) { - //@ts-ignore - return value[key]; - } - } - if ("Between" in value) { - return value.Between[0]; - } else { - return "" as unknown as T; // unreachable + this.stringExpression = propertyQueryToString(this.propertyQuery); } } } diff --git a/mediarepo-ui/src/app/utils/filter-utils.ts b/mediarepo-ui/src/app/utils/filter-utils.ts new file mode 100644 index 0000000..8a5e3ee --- /dev/null +++ b/mediarepo-ui/src/app/utils/filter-utils.ts @@ -0,0 +1,102 @@ +import {FilterExpression, FilterQuery, PropertyQuery, TagQuery, ValueComparator} from "../../api/api-types/files"; + +export function filterExpressionToString(expression: FilterExpression) { + let stringExpression = ""; + + if ("OrExpression" in expression) { + for (const query of expression.OrExpression) { + stringExpression += filterQueryToString(query) + " OR "; + } + stringExpression = stringExpression.replace(/ OR $/, ""); + } else { + stringExpression += filterQueryToString(expression.Query); + } + + return stringExpression; +} + +function filterQueryToString(query: FilterQuery): string { + if ("Tag" in query) { + return tagQueryToString(query.Tag); + } else { + return propertyQueryToString(query.Property); + } +} + +function tagQueryToString(tagQuery: TagQuery): string { + return `${tagQuery.negate ? "-" : ""}${tagQuery.tag}`; +} + +export function propertyQueryToString(propertyQuery: PropertyQuery): string { + if ("Status" in propertyQuery) { + return buildExpression("Status", "is", propertyQuery.Status); + } else if ("FileSize" in propertyQuery) { + return buildExpression( + "FileSize", + getComparator(propertyQuery.FileSize), + getValue(propertyQuery.FileSize).toString() + ); + } else if ("ImportedTime" in propertyQuery) { + return buildExpression( + "ImportedTime", + getComparator(propertyQuery.ImportedTime), + getValue(propertyQuery.ImportedTime).toISOString() + ); + } else if ("ChangedTime" in propertyQuery) { + return buildExpression( + "ChangedTime", + getComparator(propertyQuery.ChangedTime), + getValue(propertyQuery.ChangedTime).toISOString() + ); + } else if ("CreatedTime" in propertyQuery) { + return buildExpression( + "CreatedTime", + getComparator(propertyQuery.CreatedTime), + getValue(propertyQuery.CreatedTime).toISOString() + ); + } else if ("TagCount" in propertyQuery) { + return buildExpression( + "TagCount", + getComparator(propertyQuery.TagCount), + getValue(propertyQuery.TagCount).toString() + ); + } else if ("Cd" in propertyQuery) { + return buildExpression("ContentDescriptor", "is", propertyQuery.Cd); + } else if ("Id" in propertyQuery) { + return buildExpression("FileId", "is", propertyQuery.Id.toString()); + } else { + return "Invalid Expression"; + } +} + +function getComparator(value: ValueComparator): "=" | "<" | ">" | "between" { + if ("Greater" in value) { + return ">"; + } else if ("Equal" in value) { + return "="; + } else if ("Less" in value) { + return "<"; + } else { + return "between"; + } +} + +function getValue(value: ValueComparator): T { + const singleValueKeys: ("Greater" | "Equal" | "Less")[] = ["Greater", "Equal", "Less"]; + + for (const key of singleValueKeys) { + if (key in value) { + //@ts-ignore + return value[key]; + } + } + if ("Between" in value) { + return value.Between[0]; + } else { + return "" as unknown as T; // unreachable + } +} + +function buildExpression(property: string, comparator: string, value: string): string { + return `.${property} ${comparator} ${value}`; +}