diff --git a/mediarepo-ui/src/api/api-types/requests.ts b/mediarepo-ui/src/api/api-types/requests.ts index e58e50c..f0bec62 100644 --- a/mediarepo-ui/src/api/api-types/requests.ts +++ b/mediarepo-ui/src/api/api-types/requests.ts @@ -110,7 +110,7 @@ export type RunJobRequest = { }; export type AddSortingPresetRequest = { - sort_keys: SortKeyData[] + sortKeys: SortKeyData[] }; export type DeleteSortingPresetRequest = { diff --git a/mediarepo-ui/src/api/models/SortKey.ts b/mediarepo-ui/src/api/models/SortKey.ts index 6ed1d57..bf85cb4 100644 --- a/mediarepo-ui/src/api/models/SortKey.ts +++ b/mediarepo-ui/src/api/models/SortKey.ts @@ -98,9 +98,13 @@ export class SortKey { public toString(): string { if (this.sortType == "Namespace") { - return `${this.sortType} '${this.namespaceName}' ${this.sortDirection}`; + return `${this.sortType} '${this.namespaceName}' ${this.getDirectionString()}`; } else { - return `${this.sortType} ${this.sortDirection}`; + return `${this.sortType} ${this.getDirectionString()}`; } } + + private getDirectionString(): string { + return this.sortDirection === "Ascending" ? "▲" : "▼"; + } } diff --git a/mediarepo-ui/src/api/models/SortingPreset.ts b/mediarepo-ui/src/api/models/SortingPreset.ts index 5fe3d28..1b0dc9b 100644 --- a/mediarepo-ui/src/api/models/SortingPreset.ts +++ b/mediarepo-ui/src/api/models/SortingPreset.ts @@ -37,6 +37,11 @@ export class SortingPreset { return preset; } + public setData(data: SortingPresetData) { + this._id = data.id; + this.keys = data.keys.map(mapNew(SortKey)); + } + public toString(): string { return this.sortKeys.join(", "); } diff --git a/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-button/sort-button.component.html b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-button/sort-button.component.html index 5bfa0a4..74c859c 100644 --- a/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-button/sort-button.component.html +++ b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-button/sort-button.component.html @@ -4,11 +4,5 @@ class="sort-button" mat-flat-button> Sort: - - {{key.sortType}} - {{key.namespaceName}} - - - | - + diff --git a/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-button/sort-button.component.scss b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-button/sort-button.component.scss index 1fad7f8..4448aea 100644 --- a/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-button/sort-button.component.scss +++ b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-button/sort-button.component.scss @@ -7,21 +7,3 @@ text-overflow: ellipsis; overflow: hidden; } - -.sort-key-direction { - font-size: 1.5em; - vertical-align: bottom; - margin-bottom: 0.6em; -} - -.sort-key-type { - color: $primary-lighter-50 -} - -.sort-key-namespace { - color: $accent-lighter-10; -} - -.sort-key:last-child .key-divider { - display: none; -} diff --git a/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-dialog/sort-dialog.component.html b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-dialog/sort-dialog.component.html index a350274..9d0c74b 100644 --- a/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-dialog/sort-dialog.component.html +++ b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-dialog/sort-dialog.component.html @@ -1,5 +1,19 @@ -

Sort Entries

+

+ Sort Entries +

+ + Preset + + + + {{preset.toString()}} + + +
@@ -58,6 +72,22 @@
- + + + + +
diff --git a/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-dialog/sort-dialog.component.scss b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-dialog/sort-dialog.component.scss index 03a3540..81d185d 100644 --- a/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-dialog/sort-dialog.component.scss +++ b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-dialog/sort-dialog.component.scss @@ -18,12 +18,17 @@ mat-form-field, .filler, .drag-handle { } .dialog-actions { - display: flex; - flex-direction: row-reverse; width: 100%; + display: block; button { margin-left: 1em; + float: right; + } + + button.button-left { + float: left; + margin-right: 1em; } } @@ -57,3 +62,9 @@ mat-form-field, .filler, .drag-handle { background-color: darken(dimgrey, 20); border-radius: 1em; } + +.preset-selection { + width: calc(100% - 2em); + display: block; + font-size: 1em; +} diff --git a/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-dialog/sort-dialog.component.ts b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-dialog/sort-dialog.component.ts index 76b65d7..fb9fdfc 100644 --- a/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-dialog/sort-dialog.component.ts +++ b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-dialog/sort-dialog.component.ts @@ -1,4 +1,4 @@ -import {ChangeDetectionStrategy, Component, Inject} from "@angular/core"; +import {ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, OnInit} from "@angular/core"; import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog"; import {SortKey} from "../../../../../../api/models/SortKey"; import {CdkDragDrop, moveItemInArray} from "@angular/cdk/drag-drop"; @@ -6,6 +6,8 @@ import {Namespace} from "../../../../../../api/models/Namespace"; import {TagService} from "../../../../../services/tag/tag.service"; import {compareSearchResults} from "../../../../../utils/compare-utils"; import {SortingPreset} from "../../../../../../api/models/SortingPreset"; +import {PresetService} from "../../../../../services/preset/preset.service"; +import {LoggingService} from "../../../../../services/logging/logging.service"; @Component({ selector: "app-sort-dialog", @@ -13,22 +15,36 @@ import {SortingPreset} from "../../../../../../api/models/SortingPreset"; styleUrls: ["./sort-dialog.component.scss"], changeDetection: ChangeDetectionStrategy.OnPush, }) -export class SortDialogComponent { +export class SortDialogComponent implements OnInit { public sortingPreset: SortingPreset = SortingPreset.fromValues(-1, []); + public availablePresets: SortingPreset[] = []; public suggestedNamespaces: Namespace[] = []; + public emptyPreset = SortingPreset.fromValues(-1, []); - private previousId: number = -1; + public previousId: number = -1; private namespaces: Namespace[] = []; - constructor(public tagService: TagService, public dialogRef: MatDialogRef, @Inject( - MAT_DIALOG_DATA) data: any) { + constructor( + public logger: LoggingService, + public tagService: TagService, + public presetService: PresetService, + public changeDetector: ChangeDetectorRef, + public dialogRef: MatDialogRef, + @Inject( + MAT_DIALOG_DATA) data: any + ) { this.sortingPreset = data.sortingPreset; + this.previousId = this.sortingPreset.id; console.debug(this.sortingPreset); tagService.namespaces.subscribe( namespaces => this.namespaces = namespaces); } + public async ngOnInit() { + this.availablePresets = await this.presetService.getAllSortingPresets(); + } + addNewSortKey() { const sortKey = SortKey.fromValues("FileName", "Ascending", undefined); this.handlePresetChange(); @@ -68,4 +84,43 @@ export class SortDialogComponent { this.sortingPreset.id = -1; } } + + public async savePreset() { + await this.deletePreset(); + await this.saveNewPreset(); + } + + public async saveNewPreset() { + let newPreset = await this.logger.try(() => this.presetService.addSortingPreset(this.sortingPreset.sortKeys)); + if (newPreset) { + this.sortingPreset.setData(newPreset.rawData); + this.previousId = this.sortingPreset.id; + this.availablePresets.push(new SortingPreset(JSON.parse(JSON.stringify(newPreset.rawData)))); + this.changeDetector.detectChanges(); + } + } + + public async deletePreset() { + if (this.previousId >= 0) { + const index = this.availablePresets.findIndex(p => p.id == this.previousId); + if (index >= 0) { + this.availablePresets.splice(index, 1); + this.changeDetector.detectChanges(); + } + try { + await this.presetService.deleteSortingPreset(this.previousId); + } catch (err: any) { + this.logger.warn(`Could not delete previous preset: ${err.message}`); + } + } + } + + public selectPreset(presetId: number): void { + const preset = this.availablePresets.find(p => p.id == presetId); + + if (preset) { + this.sortingPreset.setData(JSON.parse(JSON.stringify(preset.rawData))); + this.previousId = preset.id; + } + } } diff --git a/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-preset-item/sort-preset-item.component.html b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-preset-item/sort-preset-item.component.html new file mode 100644 index 0000000..7300b4e --- /dev/null +++ b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-preset-item/sort-preset-item.component.html @@ -0,0 +1,7 @@ + + {{key.sortType}} + {{key.namespaceName}} + + + | + diff --git a/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-preset-item/sort-preset-item.component.scss b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-preset-item/sort-preset-item.component.scss new file mode 100644 index 0000000..667f8ea --- /dev/null +++ b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-preset-item/sort-preset-item.component.scss @@ -0,0 +1,20 @@ +@import "src/colors"; + + +.sort-key-direction { + font-size: 1.5em; + vertical-align: bottom; + margin-bottom: 0.6em; +} + +.sort-key-type { + color: $primary-lighter-50 +} + +.sort-key-namespace { + color: $accent-lighter-10; +} + +.sort-key:last-child .key-divider { + display: none; +} diff --git a/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-preset-item/sort-preset-item.component.spec.ts b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-preset-item/sort-preset-item.component.spec.ts new file mode 100644 index 0000000..1756cd3 --- /dev/null +++ b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-preset-item/sort-preset-item.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SortPresetItemComponent } from './sort-preset-item.component'; + +describe('SortPresetItemComponent', () => { + let component: SortPresetItemComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ SortPresetItemComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(SortPresetItemComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-preset-item/sort-preset-item.component.ts b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-preset-item/sort-preset-item.component.ts new file mode 100644 index 0000000..7e18532 --- /dev/null +++ b/mediarepo-ui/src/app/components/shared/sidebar/file-search/sort-preset-item/sort-preset-item.component.ts @@ -0,0 +1,16 @@ +import {ChangeDetectionStrategy, Component, Input} from "@angular/core"; +import {SortingPreset} from "../../../../../../api/models/SortingPreset"; + +@Component({ + selector: "app-sort-preset-item", + templateUrl: "./sort-preset-item.component.html", + styleUrls: ["./sort-preset-item.component.scss"], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class SortPresetItemComponent { + + @Input() preset!: SortingPreset; + + constructor() { + } +} diff --git a/mediarepo-ui/src/app/components/shared/sidebar/sidebar.module.ts b/mediarepo-ui/src/app/components/shared/sidebar/sidebar.module.ts index 57b8de1..211fb91 100644 --- a/mediarepo-ui/src/app/components/shared/sidebar/sidebar.module.ts +++ b/mediarepo-ui/src/app/components/shared/sidebar/sidebar.module.ts @@ -52,6 +52,7 @@ import {GetTagQueryPipe} from "./file-search/filter-pipes/get-tag-query.pipe"; import {GetPropertyQueryPipe} from "./file-search/filter-pipes/get-property-query.pipe"; import {SortButtonComponent} from "./file-search/sort-button/sort-button.component"; import {MatTooltipModule} from "@angular/material/tooltip"; +import { SortPresetItemComponent } from './file-search/sort-preset-item/sort-preset-item.component'; @NgModule({ @@ -71,6 +72,7 @@ import {MatTooltipModule} from "@angular/material/tooltip"; GetTagQueryPipe, GetPropertyQueryPipe, SortButtonComponent, + SortPresetItemComponent, ], exports: [ TagEditComponent, diff --git a/mediarepo-ui/src/app/services/preset/preset.service.ts b/mediarepo-ui/src/app/services/preset/preset.service.ts index 32fb28b..1b41688 100644 --- a/mediarepo-ui/src/app/services/preset/preset.service.ts +++ b/mediarepo-ui/src/app/services/preset/preset.service.ts @@ -2,6 +2,7 @@ import {Injectable} from "@angular/core"; import {SortingPreset} from "../../../api/models/SortingPreset"; import {MediarepoApi} from "../../../api/Api"; import {mapMany, mapNew} from "../../../api/models/adaptors"; +import {SortKey} from "../../../api/models/SortKey"; @Injectable({ providedIn: "root" @@ -14,4 +15,12 @@ export class PresetService { public async getAllSortingPresets(): Promise { return MediarepoApi.getAllSortingPresets().then(mapMany(mapNew(SortingPreset))); } + + public async addSortingPreset(keys: SortKey[]): Promise { + return MediarepoApi.addSortingPreset({ sortKeys: keys.map(k => k.rawData) }).then(mapNew(SortingPreset)); + } + + public async deleteSortingPreset(id: number): Promise { + return MediarepoApi.deleteSortingPreset({ id }); + } }