Fix scaling of filter dialog height

Signed-off-by: trivernis <trivernis@protonmail.com>
pull/4/head
trivernis 3 years ago
parent bade6214a0
commit 2fefc65d29

@ -9,20 +9,9 @@
<mat-icon>delete-sweep</mat-icon> <mat-icon>delete-sweep</mat-icon>
</button> </button>
</div> </div>
<mat-form-field appearance="fill" class="full-width"> <app-tag-input class="full-width" [allowNegation]="true" [availableTags]="getValidSearchTags()" (tagAdded)="addSearchTag($event); searchForFiles()">
<mat-label>Enter tags to filter for</mat-label>
<input #tagInput
(keydown)="addSearchTagByInput($event)"
[formControl]="formControl"
[matAutocomplete]="auto"
matInput/>
<button mat-button class="filter-dialog-button" (click)="openFilterDialog()"> <button mat-button class="filter-dialog-button" (click)="openFilterDialog()">
<mat-icon>filter_alt</mat-icon> <mat-icon>filter_alt</mat-icon>
</button> </button>
<mat-autocomplete #auto (optionSelected)="addSearchTagByAutocomplete($event)"> </app-tag-input>
<mat-option *ngFor="let tag of suggestionTags | async" [value]="tag">
{{tag}}
</mat-option>
</mat-autocomplete>
</mat-form-field>
<button (click)="openSortDialog()" id="sort-button" mat-flat-button>Sort: {{sortExpression.join(", ")}}</button> <button (click)="openSortDialog()" id="sort-button" mat-flat-button>Sort: {{sortExpression.join(", ")}}</button>

@ -8,12 +8,7 @@ import {
Output, Output,
ViewChild ViewChild
} from '@angular/core'; } from '@angular/core';
import {TagService} from "../../services/tag/tag.service";
import {FileService} from "../../services/file/file.service"; import {FileService} from "../../services/file/file.service";
import {FormControl} from "@angular/forms";
import {MatAutocompleteSelectedEvent} from "@angular/material/autocomplete";
import {map, startWith} from "rxjs/operators";
import {Observable} from "rxjs";
import {TagQuery} from "../../models/TagQuery"; import {TagQuery} from "../../models/TagQuery";
import {SortKey} from "../../models/SortKey"; import {SortKey} from "../../models/SortKey";
import {MatDialog} from "@angular/material/dialog"; import {MatDialog} from "@angular/material/dialog";
@ -35,24 +30,20 @@ import {Tag} from "../../models/Tag";
export class FileSearchComponent implements AfterViewChecked, OnInit { export class FileSearchComponent implements AfterViewChecked, OnInit {
public sortExpression: SortKey[] = [new SortKey("FileImportedTime", public sortExpression: SortKey[] = [new SortKey("FileImportedTime",
"Ascending", undefined)]; "Ascending", undefined)];
public formControl = new FormControl();
public filters: FilterExpression[] = []; public filters: FilterExpression[] = [];
public suggestionTags: Observable<string[]>;
@Input() availableTags: Tag[] = []; @Input() availableTags: Tag[] = [];
@Input() validTags: string[] = [];
@Output() searchStartEvent = new EventEmitter<void>(); @Output() searchStartEvent = new EventEmitter<void>();
@Output() searchEndEvent = new EventEmitter<void>(); @Output() searchEndEvent = new EventEmitter<void>();
@ViewChild("tagInput") tagInput!: ElementRef<HTMLInputElement>; @ViewChild("tagInput") tagInput!: ElementRef<HTMLInputElement>;
@ViewChild("tagInputList") inputList!: ElementRef; @ViewChild("tagInputList") inputList!: ElementRef;
constructor(private errorBroker: ErrorBrokerService, private tagService: TagService, private fileService: FileService, public dialog: MatDialog) { constructor(
this.suggestionTags = this.formControl.valueChanges.pipe(startWith(null), private errorBroker: ErrorBrokerService,
map( private fileService: FileService,
(tag: string | null) => tag ? this.filterSuggestionTag( public dialog: MatDialog
tag) : this.validTags.slice(0, 20))); ) {}
}
public async ngOnInit() { public async ngOnInit() {
await this.searchForFiles(); await this.searchForFiles();
@ -82,12 +73,16 @@ export class FileSearchComponent implements AfterViewChecked, OnInit {
} }
} }
async removeAllSearchTags() { public getValidSearchTags(): Tag[] {
return this.availableTags.filter(t => this.filters.findIndex(f => f.partiallyEq(t.getNormalizedOutput())) < 0);
}
public async removeAllSearchTags() {
this.filters = []; this.filters = [];
await this.searchForFiles(); await this.searchForFiles();
} }
async removeFilterExpression(expr: FilterExpression) { public async removeFilterExpression(expr: FilterExpression) {
const index = this.filters.indexOf(expr); const index = this.filters.indexOf(expr);
if (index >= 0) { if (index >= 0) {
this.filters.splice(index, 1); this.filters.splice(index, 1);
@ -95,26 +90,7 @@ export class FileSearchComponent implements AfterViewChecked, OnInit {
await this.searchForFiles(); await this.searchForFiles();
} }
async addSearchTagByInput(event: KeyboardEvent) { public openSortDialog() {
if (event.key === "Enter") {
const tag = (this.formControl.value as string ?? "").trim();
if (tag.length > 0 && this.validTags.includes(tag.replace(/-/g, ''))) {
this.addSearchTag(tag);
this.formControl.setValue(null);
await this.searchForFiles();
}
}
}
async addSearchTagByAutocomplete(event: MatAutocompleteSelectedEvent) {
const tag = event.option.viewValue;
this.addSearchTag(tag);
this.formControl.setValue(null);
this.tagInput.nativeElement.value = '';
await this.searchForFiles();
}
openSortDialog() {
const sortEntries = this.sortExpression.map( const sortEntries = this.sortExpression.map(
key => JSON.parse(JSON.stringify(key))).map( key => JSON.parse(JSON.stringify(key))).map(
key => new SortKey(key.sortType, key.sortDirection, key.namespaceName)) key => new SortKey(key.sortType, key.sortDirection, key.namespaceName))
@ -133,22 +109,11 @@ export class FileSearchComponent implements AfterViewChecked, OnInit {
}); });
} }
private filterSuggestionTag(tag: string) {
const negated = tag.startsWith("-");
const normalizedTag = tag.replace(/^-/, "");
return this.validTags.filter(
t => t.includes(normalizedTag) && this.filters.findIndex(
f => f.eq(t)) < 0)
.map(t => negated ? "-" + t : t)
.slice(0, 20);
}
public openFilterDialog(): void { public openFilterDialog(): void {
const filterEntries = this.filters.map(f => f.clone()); const filterEntries = this.filters.map(f => f.clone());
const filterDialog = this.dialog.open(FilterDialogComponent, { const filterDialog = this.dialog.open(FilterDialogComponent, {
minWidth: "25vw", minWidth: "25vw",
height: "80vh", maxHeight: "80vh",
data: { data: {
filterEntries, filterEntries,
availableTags: this.availableTags, availableTags: this.availableTags,

@ -1,15 +1,18 @@
<h1 mat-dialog-title>Filters</h1> <h1 mat-dialog-title>Filters</h1>
<div mat-dialog-content fxLayout="column" class="filter-dialog-content"> <div mat-dialog-content class="filter-dialog-content">
<div fxFlex fxFlexFill class="filter-dialog-list"> <div class="filter-dialog-list">
<mat-list> <mat-list class="mat-filter-dialog-list">
<mat-list-item class="filter-list-item" *ngFor="let expression of filters" [class.selected]="expression.selected"> <mat-list-item class="filter-list-item" *ngFor="let expression of filters" [class.selected]="expression.selected">
<app-tag-filter-list-item (querySelect)="this.addToSelection($event)" (queryUnselect)="this.removeFromSelection($event)" (removeClicked)="this.removeFilter($event)" <app-tag-filter-list-item (querySelect)="this.addToSelection($event)"
(contextmenu)="contextMenu.onContextMenu($event)" [expression]="expression"></app-tag-filter-list-item> (queryUnselect)="this.removeFromSelection($event)"
(removeClicked)="this.removeFilter($event)"
(contextmenu)="contextMenu.onContextMenu($event)"
[expression]="expression"></app-tag-filter-list-item>
</mat-list-item> </mat-list-item>
</mat-list> </mat-list>
</div> </div>
<mat-divider fxFlex="10px"></mat-divider> <mat-divider></mat-divider>
<app-tag-input fxFlex="5em" class="tag-input" [allowNegation]="true" [availableTags]="this.availableTags" <app-tag-input class="tag-input" [allowNegation]="true" [availableTags]="this.availableTags"
(tagAdded)="this.addFilter($event)"></app-tag-input> (tagAdded)="this.addFilter($event)"></app-tag-input>
</div> </div>
<div class="dialog-actions" mat-dialog-actions> <div class="dialog-actions" mat-dialog-actions>

@ -10,6 +10,7 @@
.tag-input { .tag-input {
width: 100%; width: 100%;
height: 5em;
} }
mat-list-item.filter-list-item { mat-list-item.filter-list-item {
@ -29,13 +30,16 @@ app-tag-filter-list-item {
.filter-dialog-content { .filter-dialog-content {
overflow: hidden; overflow: hidden;
height: 100%;
width: 100%; width: 100%;
margin: 0; max-height: 60vh;
} }
.filter-dialog-list { .filter-dialog-list {
max-height: calc(60vh - 5em);
overflow-y: auto; overflow-y: auto;
height: 100%;
width: 100%; width: 100%;
} }
mat-list.mat-filter-dialog-list {
padding: 0;
}

@ -1,4 +1,4 @@
<mat-form-field> <mat-form-field appearance="fill">
<mat-label> <mat-label>
Enter a tag Enter a tag
</mat-label> </mat-label>
@ -7,6 +7,7 @@
matInput matInput
(keydown.enter)="addTagByInput($event)" (keydown.enter)="addTagByInput($event)"
[matAutocomplete]="auto"> [matAutocomplete]="auto">
<ng-content></ng-content>
<mat-autocomplete #auto (optionSelected)="addTagByAutocomplete($event)"> <mat-autocomplete #auto (optionSelected)="addTagByAutocomplete($event)">
<mat-option *ngFor="let tag of autosuggestTags | async" [value]="tag"> <mat-option *ngFor="let tag of autosuggestTags | async" [value]="tag">
{{tag}} {{tag}}

@ -5,7 +5,6 @@
<div id="file-search-input"> <div id="file-search-input">
<app-file-search #filesearch (searchEndEvent)="this.searchEndEvent.emit()" <app-file-search #filesearch (searchEndEvent)="this.searchEndEvent.emit()"
(searchStartEvent)="this.searchStartEvent.emit()" (searchStartEvent)="this.searchStartEvent.emit()"
[validTags]="this.getValidTagsForSearch()"
[availableTags]="this.allTags"></app-file-search> [availableTags]="this.allTags"></app-file-search>
</div> </div>
<mat-divider fxFlex="1em"></mat-divider> <mat-divider fxFlex="1em"></mat-divider>

@ -74,10 +74,6 @@ export class FilesTabSidebarComponent implements OnInit, OnChanges {
await this.fileSearch.searchForFiles(); await this.fileSearch.searchForFiles();
} }
getValidTagsForSearch(): string[] {
return this.tagsOfFiles.map(t => t.getNormalizedOutput())
}
async showFileDetails(files: File[]) { async showFileDetails(files: File[]) {
this.tagsOfSelection = await this.tagService.getTagsForFiles(files.map(f => f.hash)) this.tagsOfSelection = await this.tagService.getTagsForFiles(files.map(f => f.hash))
this.tagsOfSelection = this.tagsOfSelection.sort( this.tagsOfSelection = this.tagsOfSelection.sort(

Loading…
Cancel
Save