diff --git a/mediarepo-ui/src-tauri/Cargo.lock b/mediarepo-ui/src-tauri/Cargo.lock
index 26b0139..f5a784f 100644
--- a/mediarepo-ui/src-tauri/Cargo.lock
+++ b/mediarepo-ui/src-tauri/Cargo.lock
@@ -1580,8 +1580,8 @@ checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
[[package]]
name = "mediarepo-api"
-version = "0.2.0"
-source = "git+https://github.com/Trivernis/mediarepo-api.git?rev=a86cd413637562987a3940a664b923fd7e726cef#a86cd413637562987a3940a664b923fd7e726cef"
+version = "0.3.0"
+source = "git+https://github.com/Trivernis/mediarepo-api.git?rev=6cd483a4a7d0a101f391b755b73fa253e70b4a29#6cd483a4a7d0a101f391b755b73fa253e70b4a29"
dependencies = [
"async-trait",
"chrono",
diff --git a/mediarepo-ui/src-tauri/Cargo.toml b/mediarepo-ui/src-tauri/Cargo.toml
index 34e8fb6..86590fe 100644
--- a/mediarepo-ui/src-tauri/Cargo.toml
+++ b/mediarepo-ui/src-tauri/Cargo.toml
@@ -30,7 +30,7 @@ features = ["env-filter"]
[dependencies.mediarepo-api]
git = "https://github.com/Trivernis/mediarepo-api.git"
-rev = "a86cd413637562987a3940a664b923fd7e726cef"
+rev = "6cd483a4a7d0a101f391b755b73fa253e70b4a29"
features = ["tauri-plugin"]
[features]
diff --git a/mediarepo-ui/src/app/components/file-edit/file-edit.component.html b/mediarepo-ui/src/app/components/file-edit/file-edit.component.html
index 37352c2..e1c3b20 100644
--- a/mediarepo-ui/src/app/components/file-edit/file-edit.component.html
+++ b/mediarepo-ui/src/app/components/file-edit/file-edit.component.html
@@ -21,7 +21,7 @@
{{modeSelect.value}} tag
-
+
diff --git a/mediarepo-ui/src/app/components/file-edit/file-edit.component.ts b/mediarepo-ui/src/app/components/file-edit/file-edit.component.ts
index b11e6bf..b64a0dc 100644
--- a/mediarepo-ui/src/app/components/file-edit/file-edit.component.ts
+++ b/mediarepo-ui/src/app/components/file-edit/file-edit.component.ts
@@ -1,4 +1,11 @@
-import {Component, Input, OnInit, ViewChild} from '@angular/core';
+import {
+ Component,
+ Input,
+ OnChanges,
+ OnInit,
+ SimpleChanges,
+ ViewChild
+} from '@angular/core';
import {FormControl} from "@angular/forms";
import {File} from "../../models/File";
import {Tag} from "../../models/Tag";
@@ -13,12 +20,13 @@ import {TagService} from "../../services/tag/tag.service";
templateUrl: './file-edit.component.html',
styleUrls: ['./file-edit.component.scss']
})
-export class FileEditComponent implements OnInit {
+export class FileEditComponent implements OnInit, OnChanges {
@Input() files: File[] = [];
- @Input() tags: Tag[] = [];
+ public tags: Tag[] = [];
private allTags: Tag[] = [];
+ private fileTags: {[key: number]: Tag[]} = {};
public suggestionTags: Observable;
public tagInputForm = new FormControl("");
@@ -38,6 +46,13 @@ export class FileEditComponent implements OnInit {
async ngOnInit() {
this.tagService.tags.subscribe(tags => this.allTags = tags);
await this.tagService.loadTags();
+ await this.loadFileTags();
+ }
+
+ async ngOnChanges(changes: SimpleChanges) {
+ if (changes["files"]) {
+ await this.loadFileTags()
+ }
}
public async editTagByAutocomplete($event: MatAutocompleteSelectedEvent) {
@@ -45,13 +60,13 @@ export class FileEditComponent implements OnInit {
await this.editTag(tag);
}
- private async editTag(tag: string): Promise {
+ public async editTag(tag: string): Promise {
if (tag.length > 0) {
let tagInstance = this.allTags.find(t => t.getNormalizedOutput() === tag);
if (!tagInstance) {
- // TODO: Create tag
- tagInstance = new Tag(0, "", undefined);
+ tagInstance = (await this.tagService.createTags([tag]))[0];
+ this.allTags.push(tagInstance);
}
switch (this.editMode) {
case "Toggle":
@@ -69,10 +84,29 @@ export class FileEditComponent implements OnInit {
}
async toggleTag(tag: Tag) {
-
+ for (const file of this.files) {
+ const fileTags = this.fileTags[file.id];
+ let addedTags = [];
+ let removedTags = [];
+ if (fileTags.findIndex(i => i.id === tag.id) < 0) {
+ addedTags.push(tag.id);
+ } else {
+ removedTags.push(tag.id);
+ }
+ this.fileTags[file.id] = await this.tagService.changeFileTags(file.id, addedTags, removedTags);
+ }
+ this.mapFileTagsToTagList();
+ const index = this.tags.indexOf(tag);
+ index >= 0 && this.tagScroll.scrollToIndex(index);
}
async addTag(tag: Tag) {
+ for (const file of this.files) {
+ if (this.fileTags[file.id].findIndex(t => t.id === tag.id) < 0) {
+ this.fileTags[file.id] = await this.tagService.changeFileTags(file.id,
+ [tag.id], []);
+ }
+ }
if (this.tags.findIndex(t => t.getNormalizedOutput() === tag.getNormalizedOutput()) < 0) {
this.tags.push(tag);
this.tags = this.tags.sort(
@@ -84,6 +118,12 @@ export class FileEditComponent implements OnInit {
}
public async removeTag(tag: Tag) {
+ for (const file of this.files) {
+ if (this.fileTags[file.id].findIndex(t => t.id === tag.id) >= 0) {
+ this.fileTags[file.id] = await this.tagService.changeFileTags(file.id,
+ [], [tag.id]);
+ }
+ }
const index = this.tags.indexOf(tag);
if (index >= 0) {
this.tags.splice(index, 1);
@@ -97,4 +137,26 @@ export class FileEditComponent implements OnInit {
t => t.includes(tag))
.slice(0, 20);
}
+
+ private async loadFileTags() {
+ for (const file of this.files) {
+ this.fileTags[file.id] = await this.tagService.getTagsForFiles([file.hash]);
+ }
+ this.mapFileTagsToTagList();
+ }
+
+ private mapFileTagsToTagList() {
+ let tags: Tag[] = [];
+ for (const file of this.files) {
+ const fileTags = this.fileTags[file.id];
+ tags.push(...fileTags.filter(t => tags.findIndex(tag => tag.id === t.id) < 0));
+ }
+ this.tags = tags.sort((a, b) => a.getNormalizedOutput().localeCompare(b.getNormalizedOutput()));
+ }
+
+ public async handleTagInputKeydown($event: KeyboardEvent) {
+ if ($event.key === "Enter") {
+ await this.editTag(this.tagInputForm.value);
+ }
+ }
}
diff --git a/mediarepo-ui/src/app/components/file-gallery/file-gallery-entry/file-gallery-entry.component.ts b/mediarepo-ui/src/app/components/file-gallery/file-gallery-entry/file-gallery-entry.component.ts
index 72f74a2..f987f69 100644
--- a/mediarepo-ui/src/app/components/file-gallery/file-gallery-entry/file-gallery-entry.component.ts
+++ b/mediarepo-ui/src/app/components/file-gallery/file-gallery-entry/file-gallery-entry.component.ts
@@ -47,7 +47,7 @@ export class FileGalleryEntryComponent implements OnInit, OnChanges {
async loadImage() {
try {
const hash = this.file.data.hash;
- const thumbnails = await this.fileService.getThumbnails(hash);
+ const thumbnails = await this.fileService.getThumbnails(this.file.data);
let thumbnail = thumbnails.find(
t => (t.height > 250 || t.width > 250) && (t.height < 500 && t.width < 500));
thumbnail = thumbnail ?? thumbnails[0];
diff --git a/mediarepo-ui/src/app/components/file-grid/file-grid-entry/file-grid-entry.component.ts b/mediarepo-ui/src/app/components/file-grid/file-grid-entry/file-grid-entry.component.ts
index e8673ec..a4ba048 100644
--- a/mediarepo-ui/src/app/components/file-grid/file-grid-entry/file-grid-entry.component.ts
+++ b/mediarepo-ui/src/app/components/file-grid/file-grid-entry/file-grid-entry.component.ts
@@ -47,7 +47,7 @@ export class FileGridEntryComponent implements OnInit, OnChanges {
async loadImage() {
try {
const thumbnails = await this.fileService.getThumbnails(
- this.gridEntry.file.hash);
+ this.gridEntry.file);
let thumbnail = thumbnails.find(
t => (t.height > 250 || t.width > 250) && (t.height < 500 && t.width < 500));
thumbnail = thumbnail ?? thumbnails[0];
diff --git a/mediarepo-ui/src/app/pages/home/files-tab/files-tab-sidebar/files-tab-sidebar.component.html b/mediarepo-ui/src/app/pages/home/files-tab/files-tab-sidebar/files-tab-sidebar.component.html
index a86bcb8..e837b8f 100644
--- a/mediarepo-ui/src/app/pages/home/files-tab/files-tab-sidebar/files-tab-sidebar.component.html
+++ b/mediarepo-ui/src/app/pages/home/files-tab/files-tab-sidebar/files-tab-sidebar.component.html
@@ -22,7 +22,7 @@
0">
-
+
diff --git a/mediarepo-ui/src/app/services/file/file.service.ts b/mediarepo-ui/src/app/services/file/file.service.ts
index dc406b1..46b514f 100644
--- a/mediarepo-ui/src/app/services/file/file.service.ts
+++ b/mediarepo-ui/src/app/services/file/file.service.ts
@@ -31,7 +31,7 @@ export class FileService {
public async readFile(file: File): Promise {
const once_uri = await invoke("plugin:mediarepo|read_file_by_hash",
- {hash: file.hash, mimeType: file.mime_type});
+ {id: file.id, hash: file.hash, mimeType: file.mime_type});
return this.sanitizer.bypassSecurityTrustResourceUrl(once_uri);
}
@@ -41,8 +41,8 @@ export class FileService {
return this.sanitizer.bypassSecurityTrustResourceUrl(once_uri);
}
- public async getThumbnails(hash: string): Promise {
+ public async getThumbnails(file: File): Promise {
return await invoke("plugin:mediarepo|get_file_thumbnails",
- {hash});
+ {id: file.id});
}
}
diff --git a/mediarepo-ui/src/app/services/tag/tag.service.ts b/mediarepo-ui/src/app/services/tag/tag.service.ts
index 2edde2a..a8f566a 100644
--- a/mediarepo-ui/src/app/services/tag/tag.service.ts
+++ b/mediarepo-ui/src/app/services/tag/tag.service.ts
@@ -2,6 +2,7 @@ import {Injectable} from '@angular/core';
import {invoke} from "@tauri-apps/api/tauri";
import {Tag} from "../../models/Tag";
import {BehaviorSubject} from "rxjs";
+import {File} from "../../models/File";
@Injectable({
providedIn: 'root'
@@ -18,21 +19,22 @@ export class TagService {
this.tags.next(tags.map(t => new Tag(t.id, t.name, t.namespace)));
}
- public async getTagsForFile(hash: string): Promise {
- const tags = await invoke("plugin:mediarepo|get_tags_for_file",
- {hash});
- return tags.map(t => new Tag(t.id, t.name, t.namespace));
- }
-
public async getTagsForFiles(hashes: string[]): Promise {
let tags: Tag[] = []
- if (hashes.length === 1) {
- tags = await invoke("plugin:mediarepo|get_tags_for_file",
- {hash: hashes[0]});
- } else if (hashes.length > 0) {
+ if (hashes.length > 0) {
tags = await invoke("plugin:mediarepo|get_tags_for_files",
{hashes});
}
return tags.map(t => new Tag(t.id, t.name, t.namespace));
}
+
+ public async createTags(tags: string[]): Promise {
+ const resultTags = await invoke("plugin:mediarepo|create_tags", {tags});
+ return resultTags.map(t => new Tag(t.id, t.name, t.namespace));
+ }
+
+ public async changeFileTags(fileId: number, addedTags: number[], removedTags: number[]): Promise {
+ const tags = await invoke("plugin:mediarepo|change_file_tags", {id: fileId, addedTags, removedTags});
+ return tags.map(t => new Tag(t.id, t.name, t.namespace));
+ }
}