commit
5c6f479332
@ -1,5 +1,5 @@
|
|||||||
<ng-content></ng-content>
|
<ng-content></ng-content>
|
||||||
<div *ngIf="this.busy" [class.blur]="this.blurBackground" [class.darken]="this.darkenBackground"
|
<div *ngIf="this.busy" [class.blur]="this.blurBackground" [class.darken]="this.darkenBackground"
|
||||||
class="busy-indicator-overlay">
|
class="busy-indicator-overlay">
|
||||||
<mat-progress-spinner [mode]="mode" [value]="value" color="primary"></mat-progress-spinner>
|
<mat-progress-spinner *ngIf="this.busy" [mode]="mode" [value]="value" color="primary"></mat-progress-spinner>
|
||||||
</div>
|
</div>
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
import { HasPropertyPipe } from './has-property.pipe';
|
||||||
|
|
||||||
|
describe('HasPropertyPipe', () => {
|
||||||
|
it('create an instance', () => {
|
||||||
|
const pipe = new HasPropertyPipe();
|
||||||
|
expect(pipe).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,11 @@
|
|||||||
|
import {Pipe, PipeTransform} from "@angular/core";
|
||||||
|
|
||||||
|
@Pipe({
|
||||||
|
name: "hasProperty"
|
||||||
|
})
|
||||||
|
export class HasPropertyPipe implements PipeTransform {
|
||||||
|
|
||||||
|
transform(value: any, propertyName: string): unknown {
|
||||||
|
return propertyName in value;
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,11 @@
|
|||||||
<mat-card #card (click)="clickEvent.emit(this)" (dblclick)="dblClickEvent.emit(this)"
|
<mat-card #card (click)="clickEvent.emit(this)" (dblclick)="dblClickEvent.emit(this)"
|
||||||
[ngClass]="{'selected': entry.selected}">
|
[class.selected]="this.entry.selected | async">
|
||||||
<mat-card-content>
|
<mat-card-content>
|
||||||
<app-busy-indicator [busy]="this.loading">
|
<app-busy-indicator [busy]="this.loading">
|
||||||
<app-file-thumbnail *ngIf="!loading" [file]="this.entry.data" class=".entry-image"></app-file-thumbnail>
|
<app-file-thumbnail *ngIf="!loading"
|
||||||
|
[fileChanged]="this.fileChanged"
|
||||||
|
[file]="this.entry.data"
|
||||||
|
class=".entry-image"></app-file-thumbnail>
|
||||||
</app-busy-indicator>
|
</app-busy-indicator>
|
||||||
</mat-card-content>
|
</mat-card-content>
|
||||||
</mat-card>
|
</mat-card>
|
||||||
|
@ -1,48 +1,45 @@
|
|||||||
import {
|
import {ChangeDetectionStrategy, Component, Input, OnChanges, OnInit, SimpleChanges, ViewChild} from "@angular/core";
|
||||||
Component,
|
|
||||||
Input,
|
|
||||||
OnChanges,
|
|
||||||
OnInit,
|
|
||||||
SimpleChanges
|
|
||||||
} from "@angular/core";
|
|
||||||
import {File} from "../../../../../api/models/File";
|
import {File} from "../../../../../api/models/File";
|
||||||
import {FileService} from "../../../../services/file/file.service";
|
import {FileService} from "../../../../services/file/file.service";
|
||||||
import {FileMetadata} from "../../../../../api/api-types/files";
|
import {FileMetadata} from "../../../../../api/api-types/files";
|
||||||
|
import {BusyIndicatorComponent} from "../../app-common/busy-indicator/busy-indicator.component";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "app-file-metadata",
|
selector: "app-file-metadata",
|
||||||
templateUrl: "./file-metadata.component.html",
|
templateUrl: "./file-metadata.component.html",
|
||||||
styleUrls: ["./file-metadata.component.scss"]
|
styleUrls: ["./file-metadata.component.scss"],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
})
|
})
|
||||||
export class FileMetadataComponent implements OnInit, OnChanges {
|
export class FileMetadataComponent implements OnInit, OnChanges {
|
||||||
|
|
||||||
@Input() file!: File;
|
@Input() file!: File;
|
||||||
public fileMetadata: FileMetadata | undefined;
|
public fileMetadata: FileMetadata | undefined;
|
||||||
public loading = false;
|
|
||||||
|
@ViewChild(BusyIndicatorComponent) busyIndicator!: BusyIndicatorComponent;
|
||||||
|
|
||||||
constructor(private fileService: FileService) {
|
constructor(private fileService: FileService) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async ngOnInit() {
|
public async ngOnInit() {
|
||||||
this.loading = true;
|
await this.busyIndicator.wrapAsyncOperation(async () => {
|
||||||
this.fileMetadata = await this.fileService.getFileMetadata(this.file.id);
|
this.fileMetadata = await this.fileService.getFileMetadata(this.file.id);
|
||||||
this.loading = false;
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public async ngOnChanges(changes: SimpleChanges) {
|
public async ngOnChanges(changes: SimpleChanges) {
|
||||||
if (changes["file"] && (!this.fileMetadata || this.fileMetadata.file_id != this.file.id)) {
|
if (changes["file"] && (!this.fileMetadata || this.fileMetadata.file_id != this.file.id)) {
|
||||||
this.loading = true;
|
await this.busyIndicator.wrapAsyncOperation(async () => {
|
||||||
this.fileMetadata = await this.fileService.getFileMetadata(this.file.id);
|
this.fileMetadata = await this.fileService.getFileMetadata(this.file.id);
|
||||||
this.loading = false;
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async saveFileName(name: string) {
|
public async saveFileName(name: string) {
|
||||||
this.loading = true;
|
await this.busyIndicator.wrapAsyncOperation(async () => {
|
||||||
const newFile = await this.fileService.updateFileName(this.file.id, name);
|
const newFile = await this.fileService.updateFileName(this.file.id, name);
|
||||||
if (this.fileMetadata) {
|
if (this.fileMetadata) {
|
||||||
this.fileMetadata.name = newFile.name;
|
this.fileMetadata.name = newFile.name;
|
||||||
}
|
}
|
||||||
this.loading = false;
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
<span *ngIf="is('OrExpression')" class="or-expression">
|
<span *ngIf="this.orExpression" class="or-expression">
|
||||||
<ng-container *ngFor="let query of this.orExpression().OrExpression">
|
<ng-container *ngFor="let query of this.orExpression">
|
||||||
<app-property-query-item *ngIf="this.queryIs(query, 'Property')"
|
<app-property-query-item *ngIf="query | hasProperty: 'Property'"
|
||||||
[propertyQuery]="this.propertyQuery(query).Property"></app-property-query-item>
|
[propertyQuery]="query | getPropertyQuery"></app-property-query-item>
|
||||||
<app-tag-query-item *ngIf="this.queryIs(query, 'Tag')"
|
<app-tag-query-item *ngIf="query | hasProperty: 'Tag'"
|
||||||
[tagQuery]="this.tagQuery(query).Tag"></app-tag-query-item>
|
[tagQuery]="query | getTagQuery"></app-tag-query-item>
|
||||||
<span class="or-combinator"> OR </span>
|
<span class="or-combinator"> OR </span>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</span>
|
</span>
|
||||||
<span *ngIf="is('Query')" class="query">
|
<span *ngIf="this.query" class="query">
|
||||||
<app-property-query-item *ngIf="this.queryIs(this.query().Query, 'Property')"
|
<app-property-query-item *ngIf="this.query | hasProperty: 'Property'"
|
||||||
[propertyQuery]="this.propertyQuery(this.query().Query).Property"></app-property-query-item>
|
[propertyQuery]="this.query | getPropertyQuery"></app-property-query-item>
|
||||||
<app-tag-query-item *ngIf="this.queryIs(this.query().Query, 'Tag')"
|
<app-tag-query-item *ngIf="this.query | hasProperty: 'Tag'"
|
||||||
[tagQuery]="this.tagQuery(this.query().Query).Tag"></app-tag-query-item>
|
[tagQuery]="this.query | getTagQuery"></app-tag-query-item>
|
||||||
</span>
|
</span>
|
||||||
|
@ -1,47 +1,35 @@
|
|||||||
import {Component, Input} from "@angular/core";
|
import {ChangeDetectionStrategy, Component, Input, OnChanges, OnInit, SimpleChanges} from "@angular/core";
|
||||||
import {
|
import {FilterExpression, FilterQuery} from "../../../../../../api/api-types/files";
|
||||||
FilterExpression,
|
|
||||||
FilterExpressionOrExpression,
|
|
||||||
FilterExpressionQuery,
|
|
||||||
FilterQuery,
|
|
||||||
FilterQueryProperty,
|
|
||||||
FilterQueryTag
|
|
||||||
} from "../../../../../../api/api-types/files";
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "app-filter-expression-item",
|
selector: "app-filter-expression-item",
|
||||||
templateUrl: "./filter-expression-item.component.html",
|
templateUrl: "./filter-expression-item.component.html",
|
||||||
styleUrls: ["./filter-expression-item.component.scss"]
|
styleUrls: ["./filter-expression-item.component.scss"],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
})
|
})
|
||||||
export class FilterExpressionItemComponent {
|
export class FilterExpressionItemComponent implements OnInit, OnChanges {
|
||||||
|
|
||||||
|
|
||||||
@Input() filter!: FilterExpression;
|
@Input() filter!: FilterExpression;
|
||||||
|
public orExpression?: FilterQuery[];
|
||||||
|
public query?: FilterQuery;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public is(key: "OrExpression" | "Query"): boolean {
|
public ngOnInit(): void {
|
||||||
return key in this.filter;
|
this.parseQuery();
|
||||||
}
|
|
||||||
|
|
||||||
public orExpression(): FilterExpressionOrExpression {
|
|
||||||
return this.filter as FilterExpressionOrExpression;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public query(): FilterExpressionQuery {
|
public ngOnChanges(changes: SimpleChanges): void {
|
||||||
return this.filter as FilterExpressionQuery;
|
if (changes["filter"]) {
|
||||||
|
this.parseQuery();
|
||||||
}
|
}
|
||||||
|
|
||||||
public queryIs(query: FilterQuery, key: "Property" | "Tag"): boolean {
|
|
||||||
return key in query;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public propertyQuery(query: FilterQuery): FilterQueryProperty {
|
private parseQuery() {
|
||||||
return query as FilterQueryProperty;
|
if ("Query" in this.filter) {
|
||||||
|
this.query = this.filter.Query;
|
||||||
|
} else {
|
||||||
|
this.orExpression = this.filter.OrExpression;
|
||||||
}
|
}
|
||||||
|
|
||||||
public tagQuery(query: FilterQuery): FilterQueryTag {
|
|
||||||
return query as FilterQueryTag;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
import { GetPropertyQueryPipe } from './get-property-query.pipe';
|
||||||
|
|
||||||
|
describe('GetPropertyQueryPipe', () => {
|
||||||
|
it('create an instance', () => {
|
||||||
|
const pipe = new GetPropertyQueryPipe();
|
||||||
|
expect(pipe).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,13 @@
|
|||||||
|
import {Pipe, PipeTransform} from "@angular/core";
|
||||||
|
import {FilterQuery, FilterQueryProperty, PropertyQuery} from "../../../../../../api/api-types/files";
|
||||||
|
|
||||||
|
@Pipe({
|
||||||
|
name: "getPropertyQuery"
|
||||||
|
})
|
||||||
|
export class GetPropertyQueryPipe implements PipeTransform {
|
||||||
|
|
||||||
|
transform(value: FilterQuery): PropertyQuery {
|
||||||
|
return (value as FilterQueryProperty).Property;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
import { GetTagQueryPipe } from './get-tag-query.pipe';
|
||||||
|
|
||||||
|
describe('GetTagQueryPipe', () => {
|
||||||
|
it('create an instance', () => {
|
||||||
|
const pipe = new GetTagQueryPipe();
|
||||||
|
expect(pipe).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,12 @@
|
|||||||
|
import {Pipe, PipeTransform} from "@angular/core";
|
||||||
|
import {FilterQuery, FilterQueryTag, TagQuery} from "../../../../../../api/api-types/files";
|
||||||
|
|
||||||
|
@Pipe({
|
||||||
|
name: "getTagQuery"
|
||||||
|
})
|
||||||
|
export class GetTagQueryPipe implements PipeTransform {
|
||||||
|
|
||||||
|
transform(value: FilterQuery): TagQuery {
|
||||||
|
return (value as FilterQueryTag).Tag;
|
||||||
|
}
|
||||||
|
}
|
@ -1,12 +1,18 @@
|
|||||||
|
import {BehaviorSubject} from "rxjs";
|
||||||
|
|
||||||
export class Selectable<T> {
|
export class Selectable<T> {
|
||||||
constructor(public data: T, public selected: boolean) {
|
|
||||||
|
public selected: BehaviorSubject<boolean>;
|
||||||
|
|
||||||
|
constructor(public data: T, selected: boolean) {
|
||||||
|
this.selected = new BehaviorSubject<boolean>(selected);
|
||||||
}
|
}
|
||||||
|
|
||||||
public select() {
|
public select() {
|
||||||
this.selected = true;
|
this.selected.next(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public unselect() {
|
public unselect() {
|
||||||
this.selected = false;
|
this.selected.next(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue