From bc74482098a0ade2189c4ac2a562d1a71acef982 Mon Sep 17 00:00:00 2001 From: trivernis Date: Sat, 6 Nov 2021 12:43:39 +0100 Subject: [PATCH 1/3] Add UI to edit tags Signed-off-by: trivernis --- mediarepo-ui/src/app/app.module.ts | 2 + .../file-edit/file-edit.component.html | 48 +++++++++ .../file-edit/file-edit.component.scss | 70 ++++++++++++ .../file-edit/file-edit.component.spec.ts | 25 +++++ .../file-edit/file-edit.component.ts | 100 ++++++++++++++++++ .../file-search/file-search.component.ts | 2 +- .../tag-item/tag-item.component.scss | 2 + .../files-tab-sidebar.component.html | 3 + .../files-tab-sidebar.component.scss | 12 +-- .../files-tab-sidebar.component.ts | 8 +- 10 files changed, 261 insertions(+), 11 deletions(-) create mode 100644 mediarepo-ui/src/app/components/file-edit/file-edit.component.html create mode 100644 mediarepo-ui/src/app/components/file-edit/file-edit.component.scss create mode 100644 mediarepo-ui/src/app/components/file-edit/file-edit.component.spec.ts create mode 100644 mediarepo-ui/src/app/components/file-edit/file-edit.component.ts diff --git a/mediarepo-ui/src/app/app.module.ts b/mediarepo-ui/src/app/app.module.ts index ce93bac..f443a4e 100644 --- a/mediarepo-ui/src/app/app.module.ts +++ b/mediarepo-ui/src/app/app.module.ts @@ -48,6 +48,7 @@ import {ConfirmDialogComponent} from './components/confirm-dialog/confirm-dialog import {FilesTabSidebarComponent} from './pages/home/files-tab/files-tab-sidebar/files-tab-sidebar.component'; import {MatExpansionModule} from "@angular/material/expansion"; import {TagItemComponent} from './components/tag-item/tag-item.component'; +import { FileEditComponent } from './components/file-edit/file-edit.component'; @NgModule({ declarations: [ @@ -67,6 +68,7 @@ import {TagItemComponent} from './components/tag-item/tag-item.component'; ConfirmDialogComponent, FilesTabSidebarComponent, TagItemComponent, + FileEditComponent, ], imports: [ BrowserModule, 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 new file mode 100644 index 0000000..37352c2 --- /dev/null +++ b/mediarepo-ui/src/app/components/file-edit/file-edit.component.html @@ -0,0 +1,48 @@ +
+ +
+ +
+ + +
+
+
+ +
+
+ + {{modeSelect.value}} tag + + + + + + {{tag}} + + + + +
+ + Mode + + Toggle + Add + Remove + + +
+
diff --git a/mediarepo-ui/src/app/components/file-edit/file-edit.component.scss b/mediarepo-ui/src/app/components/file-edit/file-edit.component.scss new file mode 100644 index 0000000..92d6ccc --- /dev/null +++ b/mediarepo-ui/src/app/components/file-edit/file-edit.component.scss @@ -0,0 +1,70 @@ +.file-metadata, .tag-input { + width: 100%; + mat-form-field { + width: 100%; + } + + mat-form-field.form-field-mode { + width: 10em; + } + + mat-form-field.form-field-tag-input { + + } +} + +.file-edit-inner { + height: 100%; + width: 100%; + display: block; +} + +.tag-edit-list { + height: 100%; + width: 100%; + display: block; + overflow: hidden; +} + +cdk-virtual-scroll-viewport { + height: 100%; + width: 100%; + overflow-y: auto; + ::ng-deep .cdk-virtual-scroll-content-wrapper { + width: 100%; + } +} + +.editable-tag { + height: 50px; + width: 100%; + display: flex; + font-size: 1.2em; + transition-duration: 0.1s; + user-select: none; + overflow: hidden; + cursor: default; + + app-tag-item { + margin: auto auto auto 0.25em; + } + + .tag-remove-button { + margin-right: 1em; + height: 50px; + width: 50px; + } +} + +.tag-input-field { + display: flex; + flex-direction: row; + .add-tag-button { + width: 65px; + height: 65px; + } +} + +mat-divider { + width: 100%; +} diff --git a/mediarepo-ui/src/app/components/file-edit/file-edit.component.spec.ts b/mediarepo-ui/src/app/components/file-edit/file-edit.component.spec.ts new file mode 100644 index 0000000..51ab4bb --- /dev/null +++ b/mediarepo-ui/src/app/components/file-edit/file-edit.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { FileEditComponent } from './file-edit.component'; + +describe('FileEditComponent', () => { + let component: FileEditComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ FileEditComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(FileEditComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); 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 new file mode 100644 index 0000000..b11e6bf --- /dev/null +++ b/mediarepo-ui/src/app/components/file-edit/file-edit.component.ts @@ -0,0 +1,100 @@ +import {Component, Input, OnInit, ViewChild} from '@angular/core'; +import {FormControl} from "@angular/forms"; +import {File} from "../../models/File"; +import {Tag} from "../../models/Tag"; +import {CdkVirtualScrollViewport} from "@angular/cdk/scrolling"; +import {MatAutocompleteSelectedEvent} from "@angular/material/autocomplete"; +import {Observable} from "rxjs"; +import {map, startWith} from "rxjs/operators"; +import {TagService} from "../../services/tag/tag.service"; + +@Component({ + selector: 'app-file-edit', + templateUrl: './file-edit.component.html', + styleUrls: ['./file-edit.component.scss'] +}) +export class FileEditComponent implements OnInit { + + @Input() files: File[] = []; + @Input() tags: Tag[] = []; + + private allTags: Tag[] = []; + + public suggestionTags: Observable; + public tagInputForm = new FormControl(""); + public editMode: string = "Toggle"; + + @ViewChild("tagScroll") tagScroll!: CdkVirtualScrollViewport; + + constructor( + private tagService: TagService, + ) { + this.suggestionTags = this.tagInputForm.valueChanges.pipe(startWith(null), + map( + (tag: string | null) => tag ? this.filterSuggestionTag( + tag) : this.allTags.slice(0, 20).map(t => t.getNormalizedOutput()))); + } + + async ngOnInit() { + this.tagService.tags.subscribe(tags => this.allTags = tags); + await this.tagService.loadTags(); + } + + public async editTagByAutocomplete($event: MatAutocompleteSelectedEvent) { + const tag = $event.option.value.trim(); + await this.editTag(tag); + } + + private 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); + } + switch (this.editMode) { + case "Toggle": + await this.toggleTag(tagInstance); + break; + case "Add": + await this.addTag(tagInstance); + break; + case "Remove": + await this.removeTag(tagInstance); + break; + } + this.tagInputForm.setValue(""); + } + } + + async toggleTag(tag: Tag) { + + } + + async addTag(tag: Tag) { + if (this.tags.findIndex(t => t.getNormalizedOutput() === tag.getNormalizedOutput()) < 0) { + this.tags.push(tag); + this.tags = this.tags.sort( + (a, b) => a.getNormalizedOutput().localeCompare(b.getNormalizedOutput())); + this.tags = [...this.tags]; // angular pls detect it wtf + } + const index = this.tags.indexOf(tag); + index >= 0 && this.tagScroll.scrollToIndex(index); + } + + public async removeTag(tag: Tag) { + const index = this.tags.indexOf(tag); + if (index >= 0) { + this.tags.splice(index, 1); + this.tags = [...this.tags]; // so angular detects the change + } + } + + private filterSuggestionTag(tag: string) { + const allTags = this.allTags.map(t => t.getNormalizedOutput()); + return allTags.filter( + t => t.includes(tag)) + .slice(0, 20); + } +} diff --git a/mediarepo-ui/src/app/components/file-search/file-search.component.ts b/mediarepo-ui/src/app/components/file-search/file-search.component.ts index e58462a..19da0a3 100644 --- a/mediarepo-ui/src/app/components/file-search/file-search.component.ts +++ b/mediarepo-ui/src/app/components/file-search/file-search.component.ts @@ -135,7 +135,7 @@ export class FileSearchComponent implements AfterViewChecked, OnInit { return this.validTags.filter( t => t.includes(normalizedTag) && this.searchTags.findIndex( - s => s.name === t) < 0) + s => s.getNormalizedTag() === t) < 0) .map(t => negated ? "-" + t : t) .slice(0, 20); } diff --git a/mediarepo-ui/src/app/components/tag-item/tag-item.component.scss b/mediarepo-ui/src/app/components/tag-item/tag-item.component.scss index 5e91837..6911049 100644 --- a/mediarepo-ui/src/app/components/tag-item/tag-item.component.scss +++ b/mediarepo-ui/src/app/components/tag-item/tag-item.component.scss @@ -2,6 +2,8 @@ display: inline; width: 100%; padding: 0.25em; + word-break: break-all; + text-overflow: ellipsis; } .tag-item-namespace { 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 b5b3c49..a86bcb8 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 @@ -21,5 +21,8 @@ + + + diff --git a/mediarepo-ui/src/app/pages/home/files-tab/files-tab-sidebar/files-tab-sidebar.component.scss b/mediarepo-ui/src/app/pages/home/files-tab/files-tab-sidebar/files-tab-sidebar.component.scss index 30b9a87..fcdf3f8 100644 --- a/mediarepo-ui/src/app/pages/home/files-tab/files-tab-sidebar/files-tab-sidebar.component.scss +++ b/mediarepo-ui/src/app/pages/home/files-tab/files-tab-sidebar/files-tab-sidebar.component.scss @@ -8,7 +8,7 @@ app-file-search { overflow: hidden; } -mat-tab-group, mat-tab, .file-tag-list { +mat-tab-group, mat-tab, .file-tag-list, app-file-edit { height: 100%; width: 100%; } @@ -45,17 +45,13 @@ mat-selection-list { cursor: pointer; } -.file-tag-list-inner { - display: block; - height: 100%; - width: 100%; - overflow: hidden; -} - cdk-virtual-scroll-viewport { height: 100%; width: 100%; overflow-y: auto; + ::ng-deep .cdk-virtual-scroll-content-wrapper { + width: 100%; + } } mat-divider { diff --git a/mediarepo-ui/src/app/pages/home/files-tab/files-tab-sidebar/files-tab-sidebar.component.ts b/mediarepo-ui/src/app/pages/home/files-tab/files-tab-sidebar/files-tab-sidebar.component.ts index 69b2706..062c8c2 100644 --- a/mediarepo-ui/src/app/pages/home/files-tab/files-tab-sidebar/files-tab-sidebar.component.ts +++ b/mediarepo-ui/src/app/pages/home/files-tab/files-tab-sidebar/files-tab-sidebar.component.ts @@ -14,6 +14,7 @@ import {FileService} from "../../../../services/file/file.service"; import {File} from "../../../../models/File"; import {FileSearchComponent} from "../../../../components/file-search/file-search.component"; import {RepositoryService} from "../../../../services/repository/repository.service"; +import {FileEditComponent} from "../../../../components/file-edit/file-edit.component"; @Component({ selector: 'app-files-tab-sidebar', @@ -27,10 +28,12 @@ export class FilesTabSidebarComponent implements OnInit, OnChanges { @Output() searchEndEvent = new EventEmitter(); @ViewChild('filesearch') fileSearch!: FileSearchComponent; + @ViewChild("fileedit") fileEdit: FileEditComponent | undefined; public tagsOfFiles: Tag[] = []; public tags: Tag[] = []; public files: File[] = []; + public tagsOfSelection: Tag[] = []; constructor(private repoService: RepositoryService, private tagService: TagService, private fileService: FileService) { this.fileService.displayedFiles.subscribe(async files => { @@ -72,9 +75,10 @@ export class FilesTabSidebarComponent implements OnInit, OnChanges { } async showFileDetails(files: File[]) { - this.tags = await this.tagService.getTagsForFiles(files.map(f => f.hash)) - this.tags = this.tags.sort( + this.tagsOfSelection = await this.tagService.getTagsForFiles(files.map(f => f.hash)) + this.tagsOfSelection = this.tagsOfSelection.sort( (a, b) => a.getNormalizedOutput().localeCompare(b.getNormalizedOutput())); + this.tags = this.tagsOfSelection; } private async refreshFileSelection() { From a7327d6bc64d2599b7f8bf962f61042d62b14552 Mon Sep 17 00:00:00 2001 From: trivernis Date: Sat, 6 Nov 2021 13:33:02 +0100 Subject: [PATCH 2/3] Add logic to actually edit tags Signed-off-by: trivernis --- mediarepo-ui/src-tauri/Cargo.lock | 4 +- mediarepo-ui/src-tauri/Cargo.toml | 2 +- .../file-edit/file-edit.component.html | 2 +- .../file-edit/file-edit.component.ts | 76 +++++++++++++++++-- .../file-gallery-entry.component.ts | 2 +- .../file-grid-entry.component.ts | 2 +- .../files-tab-sidebar.component.html | 2 +- .../src/app/services/file/file.service.ts | 6 +- .../src/app/services/tag/tag.service.ts | 22 +++--- 9 files changed, 91 insertions(+), 27 deletions(-) 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 @@
- + 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)); + } } From c5cd1664bb34c4bce57798d22924bb07053b400b Mon Sep 17 00:00:00 2001 From: trivernis Date: Sat, 6 Nov 2021 13:59:17 +0100 Subject: [PATCH 3/3] Add functionality to name input field Signed-off-by: trivernis --- mediarepo-ui/src-tauri/Cargo.lock | 4 +-- mediarepo-ui/src-tauri/Cargo.toml | 2 +- .../file-edit/file-edit.component.html | 2 +- .../file-edit/file-edit.component.ts | 26 ++++++++++++++++++- .../file-grid-entry.component.html | 1 - .../src/app/services/file/file.service.ts | 4 +++ 6 files changed, 33 insertions(+), 6 deletions(-) diff --git a/mediarepo-ui/src-tauri/Cargo.lock b/mediarepo-ui/src-tauri/Cargo.lock index f5a784f..166699c 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.3.0" -source = "git+https://github.com/Trivernis/mediarepo-api.git?rev=6cd483a4a7d0a101f391b755b73fa253e70b4a29#6cd483a4a7d0a101f391b755b73fa253e70b4a29" +version = "0.4.1" +source = "git+https://github.com/Trivernis/mediarepo-api.git?rev=b123e69d92dfd384d37b9005c8e261c69fddfcc5#b123e69d92dfd384d37b9005c8e261c69fddfcc5" dependencies = [ "async-trait", "chrono", diff --git a/mediarepo-ui/src-tauri/Cargo.toml b/mediarepo-ui/src-tauri/Cargo.toml index 86590fe..59c9b50 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 = "6cd483a4a7d0a101f391b755b73fa253e70b4a29" +rev = "b123e69d92dfd384d37b9005c8e261c69fddfcc5" 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 e1c3b20..72f477b 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 @@ -3,7 +3,7 @@

Edit File

Name - +
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 b64a0dc..a826229 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,5 +1,5 @@ import { - Component, + Component, ElementRef, Input, OnChanges, OnInit, @@ -14,6 +14,7 @@ import {MatAutocompleteSelectedEvent} from "@angular/material/autocomplete"; import {Observable} from "rxjs"; import {map, startWith} from "rxjs/operators"; import {TagService} from "../../services/tag/tag.service"; +import {FileService} from "../../services/file/file.service"; @Component({ selector: 'app-file-edit', @@ -33,9 +34,11 @@ export class FileEditComponent implements OnInit, OnChanges { public editMode: string = "Toggle"; @ViewChild("tagScroll") tagScroll!: CdkVirtualScrollViewport; + @ViewChild("fileNameInput") fileNameInput!: ElementRef; constructor( private tagService: TagService, + private fileService: FileService, ) { this.suggestionTags = this.tagInputForm.valueChanges.pipe(startWith(null), map( @@ -47,11 +50,26 @@ export class FileEditComponent implements OnInit, OnChanges { this.tagService.tags.subscribe(tags => this.allTags = tags); await this.tagService.loadTags(); await this.loadFileTags(); + this.resetFileNameInput(); } async ngOnChanges(changes: SimpleChanges) { if (changes["files"]) { await this.loadFileTags() + this.resetFileNameInput(); + } + } + + public async changeFileName(value: string) { + const name = value.trim(); + + if (name.length > 0) { + const file = this.files[0]; + console.log("Updating name to", name); + const responseFile = await this.fileService.updateFileName(file, name); + console.log("Updated name"); + file.name = responseFile.name; + this.resetFileNameInput(); } } @@ -145,6 +163,12 @@ export class FileEditComponent implements OnInit, OnChanges { this.mapFileTagsToTagList(); } + private resetFileNameInput() { + if (this.files.length === 1) { + this.fileNameInput.nativeElement.value = this.files[0].name ?? ""; + } + } + private mapFileTagsToTagList() { let tags: Tag[] = []; for (const file of this.files) { diff --git a/mediarepo-ui/src/app/components/file-grid/file-grid-entry/file-grid-entry.component.html b/mediarepo-ui/src/app/components/file-grid/file-grid-entry/file-grid-entry.component.html index 294df4d..be65748 100644 --- a/mediarepo-ui/src/app/components/file-grid/file-grid-entry/file-grid-entry.component.html +++ b/mediarepo-ui/src/app/components/file-grid/file-grid-entry/file-grid-entry.component.html @@ -1,6 +1,5 @@ - {{gridEntry.file?.name}} diff --git a/mediarepo-ui/src/app/services/file/file.service.ts b/mediarepo-ui/src/app/services/file/file.service.ts index 46b514f..f58805f 100644 --- a/mediarepo-ui/src/app/services/file/file.service.ts +++ b/mediarepo-ui/src/app/services/file/file.service.ts @@ -45,4 +45,8 @@ export class FileService { return await invoke("plugin:mediarepo|get_file_thumbnails", {id: file.id}); } + + public async updateFileName(file: File, name: string): Promise { + return await invoke("plugin:mediarepo|update_file_name", {id: file.id, name}) + } }