Add loading indicator to file search

Signed-off-by: trivernis <trivernis@protonmail.com>
pull/4/head
trivernis 3 years ago
parent 1120d61cf1
commit 46d823720c

@ -1581,7 +1581,7 @@ checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
[[package]]
name = "mediarepo-api"
version = "0.1.0"
source = "git+https://github.com/Trivernis/mediarepo-api.git?rev=476b9d152457f78c73f6f6a36c2421cbce9c9194#476b9d152457f78c73f6f6a36c2421cbce9c9194"
source = "git+https://github.com/Trivernis/mediarepo-api.git?rev=c944cf5d770ac895bd01464c92d41005055c0580#c944cf5d770ac895bd01464c92d41005055c0580"
dependencies = [
"async-trait",
"chrono",

@ -30,7 +30,7 @@ features = ["env-filter"]
[dependencies.mediarepo-api]
git = "https://github.com/Trivernis/mediarepo-api.git"
rev = "476b9d152457f78c73f6f6a36c2421cbce9c9194"
rev = "c944cf5d770ac895bd01464c92d41005055c0580"
features = ["tauri-plugin"]
[features]

@ -37,6 +37,9 @@ import {MatDialogModule} from "@angular/material/dialog";
import {MatSelectModule} from "@angular/material/select";
import { FileGalleryComponent } from './components/file-gallery/file-gallery.component';
import { FileGalleryEntryComponent } from './components/file-gallery/file-gallery-entry/file-gallery-entry.component';
import {MatProgressSpinnerModule} from "@angular/material/progress-spinner";
import {BlockUIModule} from "primeng/blockui";
import {PanelModule} from "primeng/panel";
@NgModule({
declarations: [
@ -80,6 +83,9 @@ import { FileGalleryEntryComponent } from './components/file-gallery/file-galler
MatRippleModule,
MatDialogModule,
MatSelectModule,
MatProgressSpinnerModule,
BlockUIModule,
PanelModule,
],
providers: [],
bootstrap: [AppComponent]

@ -1,3 +1,4 @@
<div class="image-wrapper" (click)="fileSelectEvent.emit(this.file)" [class.selected]="this.file.selected">
<mat-progress-spinner *ngIf="!contentUrl"></mat-progress-spinner>
<img [src]="contentUrl">
</div>

@ -1,5 +1,6 @@
img {
max-height: 100%;
max-width: 100%;
width: auto;
margin: auto;
}

@ -2,13 +2,16 @@
<button mat-icon-button class="close-button" (click)="this.closeEvent.emit()">
<mat-icon>close</mat-icon>
</button>
<div class="file-full-view" fxFlex="80%" (dblclick)="this.selectedFile? this.fileDblClickEvent.emit(this.selectedFile.data) : null">
<div class="file-full-view" fxFlex="80%"
(dblclick)="this.selectedFile? this.fileDblClickEvent.emit(this.selectedFile.data) : null">
<div class="file-full-view-inner">
<img [src]="this.fileContentUrl"/>
</div>
</div>
<mat-divider fxFlex></mat-divider>
<div class="file-scroll-view" fxFlex="20%">
<cdk-virtual-scroll-viewport #virtualScroll orientation="horizontal" itemSize="250" minBufferPx="1000" maxBufferPx="3000" class="file-scroll-viewport">
<cdk-virtual-scroll-viewport #virtualScroll orientation="horizontal" itemSize="250" minBufferPx="1000"
maxBufferPx="3000" class="file-scroll-viewport">
<div *cdkVirtualFor="let entry of entries" class="file-item">
<app-file-gallery-entry [file]="entry" (fileSelectEvent)="onEntrySelect($event)"></app-file-gallery-entry>
</div>

@ -67,10 +67,13 @@ export class FileGalleryComponent implements OnChanges, OnInit {
}
public async ngOnChanges(changes: SimpleChanges): Promise<void> {
this.entries = this.files.map(f => new Selectable(f, f == this.selectedFile?.data));
this.entries = this.files.map(f => new Selectable(f, f.hash == this.selectedFile?.data.hash));
const selectedIndex = this.files.findIndex(f => f.hash === this.selectedFile?.data.hash);
if (!this.selectedFile || this.files.indexOf(this.selectedFile.data) < 0) {
if (!this.selectedFile || selectedIndex < 0) {
await this.onEntrySelect(this.getPreselectedEntry() ?? this.entries[0])
} else {
await this.onEntrySelect(this.entries[selectedIndex])
}
}

@ -5,7 +5,7 @@
(click)="removeSearchTag(tag)">{{tag.getNormalizedTag()}}</div>
</div>
</div>
<button id="delete-all-tags-button" mat-button (click)="removeAllSearchTags()">
<button id="delete-all-tags-button" mat-icon-button (click)="removeAllSearchTags()">
<mat-icon>delete-sweep</mat-icon>
</button>
</div>

@ -1,7 +1,7 @@
import {
AfterViewChecked,
Component,
ElementRef,
ElementRef, EventEmitter, Output,
ViewChild
} from '@angular/core';
import {TagService} from "../../services/tag/tag.service";
@ -14,6 +14,7 @@ import {TagQuery} from "../../models/TagQuery";
import {SortKey} from "../../models/SortKey";
import {MatDialog} from "@angular/material/dialog";
import {FilterDialogComponent} from "./filter-dialog/filter-dialog.component";
import {ErrorBrokerService} from "../../services/error-broker/error-broker.service";
@Component({
selector: 'app-file-search',
@ -30,12 +31,16 @@ export class FileSearchComponent implements AfterViewChecked {
public formControl = new FormControl();
public searchTags: TagQuery[] = [];
public suggestionTags: Observable<string[]>;
@Output() searchStartEvent = new EventEmitter<void>();
@Output() searchEndEvent = new EventEmitter<void>();
private allTags: string[] = [];
@ViewChild("tagInput") tagInput!: ElementRef<HTMLInputElement>;
@ViewChild("tagInputList") inputList!: ElementRef;
constructor(private tagService: TagService, private fileService: FileService, public dialog: MatDialog) {
constructor(private errorBroker: ErrorBrokerService, private tagService: TagService, private fileService: FileService, public dialog: MatDialog) {
this.tagService.tags.subscribe(
(tag) => this.allTags = tag.map(t => t.getNormalizedOutput()));
@ -48,7 +53,13 @@ export class FileSearchComponent implements AfterViewChecked {
}
public async searchForFiles() {
this.searchStartEvent.emit();
try {
await this.fileService.findFiles(this.searchTags, this.sortExpression);
} catch (err) {
this.errorBroker.showError(err);
}
this.searchEndEvent.emit();
}
public addSearchTag(tag: string) {

@ -18,7 +18,7 @@ export class SortKey {
public toBackendType(): any {
if (this.sortType == "Namespace") {
return {"Namespace": {direction: this.sortDirection, tag: this.namespaceName}}
return {"Namespace": {direction: this.sortDirection, name: this.namespaceName}}
} else {
let returnObj: any = {};
returnObj[this.sortType] = this.sortDirection;

@ -2,7 +2,8 @@
<mat-drawer mode="side" opened disableClose>
<div fxLayout="column" class="drawer-sidebar-inner">
<div id="file-search-input" fxFlex="220px">
<app-file-search #filesearch></app-file-search>
<app-file-search #filesearch (searchStartEvent)="contentLoading = true"
(searchEndEvent)="contentLoading = false"></app-file-search>
</div>
<div id="file-tag-list" fxFlex fxFlexAlign="start" fxFlexFill>
<h1>Selection Tags</h1>
@ -16,6 +17,9 @@
</div>
</mat-drawer>
<mat-drawer-content>
<div *ngIf="contentLoading" class="spinner-overlay">
<mat-progress-spinner color="primary" mode="indeterminate"></mat-progress-spinner>
</div>
<app-file-grid *ngIf="!this.showGallery" (fileDblClickEvent)="openGallery($event)" [files]="files"
(fileSelectEvent)="onFileSelect($event)"
(fileMultiselectEvent)="onFileMultiSelect($event)"
@ -23,6 +27,5 @@
<app-file-gallery *ngIf="this.showGallery" [files]="files" (fileSelectEvent)="onFileSelect($event)"
(fileDblClickEvent)="openFile($event)" [preselectedFile]="this.preselectedFile"
(closeEvent)="this.showGallery = false"></app-file-gallery>
</mat-drawer-content>
</mat-drawer-container>

@ -53,3 +53,21 @@ app-file-gallery {
height: 100%;
width: 100%;
}
.spinner-overlay {
position: absolute;
top: 0;
right: 0;
height: 100%;
width: 100%;
background-color: rgba(0, 0, 0, 0.5);
z-index: 998;
overflow: hidden;
display: flex;
backdrop-filter: blur(5px);
mat-progress-spinner {
z-index: 999;
margin: auto;
}
}

@ -21,6 +21,7 @@ export class SearchPageComponent implements OnInit {
private openingLightbox = false;
showGallery = false;
preselectedFile: File | undefined;
contentLoading = false;
@ViewChild('filesearch') fileSearch!: FileSearchComponent;
@ -34,7 +35,9 @@ export class SearchPageComponent implements OnInit {
async ngOnInit() {
this.fileService.displayedFiles.subscribe((files) => this.files = files);
this.contentLoading = true;
await this.fileService.findFiles([], [new SortKey("FileImportedTime", "Ascending", undefined)])
this.contentLoading = false;
}
async onFileMultiSelect(files: File[]) {

Loading…
Cancel
Save