From 901ad3cc69004b1df9b8b24d5debac611daa944b Mon Sep 17 00:00:00 2001
From: RafaUC
Date: Tue, 26 Aug 2025 00:57:11 -0600
Subject: [PATCH 1/6] Fixes: Dispose clientfiles when clearing fileList. -
Delete files of inexistent locations in database.
---
src/frontend/stores/FileStore.ts | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/src/frontend/stores/FileStore.ts b/src/frontend/stores/FileStore.ts
index d4de18e4..21cab28d 100644
--- a/src/frontend/stores/FileStore.ts
+++ b/src/frontend/stores/FileStore.ts
@@ -698,6 +698,9 @@ class FileStore {
// Removes all items from fileList
@action.bound clearFileList(): void {
+ for (const file of this.fileList) {
+ file?.dispose();
+ }
this.numLoadedFiles = 0;
this.fileDimensions.clear();
this.fileList.clear();
@@ -761,6 +764,7 @@ class FileStore {
getLocation(location: ID): ClientLocation {
const loc = this.rootStore.locationStore.get(location);
if (!loc) {
+ this.backend.removeLocation(location);
throw new Error(
`Location of file was not found! This should never happen! Location ${location}`,
);
From 063115212a77943d353916969693d995f4717a53 Mon Sep 17 00:00:00 2001
From: RafaUC
Date: Tue, 26 Aug 2025 17:15:33 -0600
Subject: [PATCH 2/6] Feature: Allow automatic tagging of files using a local
AI tagging service.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- Added the "Tag Selected Using AI Tagging Service" to the files contextual menu.
- Added its endpoint configuration to Settings > Background Processes.
Custom and minimalistic implementation inspired/based on cmeka's implementation: https://github.com/cmeka/OneFolder/commit/b0d7e12
---
common/promise.ts | 1 +
resources/style/controls/input.scss | 25 +++
resources/style/controls/notifications.scss | 2 +
.../containers/ContentView/menu-items.tsx | 6 +
.../Settings/BackgroundProcesses.tsx | 60 ++++++-
src/frontend/entities/File.ts | 4 +
src/frontend/stores/FileStore.ts | 169 +++++++++++++++++-
src/frontend/stores/UiStore.ts | 10 ++
8 files changed, 273 insertions(+), 4 deletions(-)
diff --git a/common/promise.ts b/common/promise.ts
index 383ce083..b6dea6d3 100644
--- a/common/promise.ts
+++ b/common/promise.ts
@@ -56,6 +56,7 @@ export function promiseAllLimit(
if (cancel?.()) {
rejected = true;
console.log('CANCELLING!');
+ reject(new Error('Promise chain cancelled'));
return;
}
diff --git a/resources/style/controls/input.scss b/resources/style/controls/input.scss
index b9275dc2..89e962b4 100644
--- a/resources/style/controls/input.scss
+++ b/resources/style/controls/input.scss
@@ -26,6 +26,7 @@
}
}
+.split-input-wrapper,
.input {
height: 28px;
background: var(--input-color);
@@ -101,3 +102,27 @@ textarea.input {
}
}
}
+
+.split-input-wrapper {
+ display: flex;
+ flex-grow: 1;
+ flex-wrap: wrap;
+ overflow-x: hidden;
+ align-items: center;
+ user-select: text;
+ padding-left: 0.25rem;
+
+ > * {
+ user-select: text;
+ padding: 0;
+ margin: 0;
+ line-height: 1.75em;
+ }
+
+ input {
+ flex-grow: 1;
+ border: none;
+ background: transparent;
+ box-sizing: content-box;
+ }
+}
diff --git a/resources/style/controls/notifications.scss b/resources/style/controls/notifications.scss
index 51aec407..e37b0b22 100644
--- a/resources/style/controls/notifications.scss
+++ b/resources/style/controls/notifications.scss
@@ -55,10 +55,12 @@
min-height: 1rem;
max-height: 5rem;
margin: 0.25rem;
+ word-break: break-word;
}
button {
color: white;
+ min-width: auto;
&:hover {
background: rgba(255, 255, 255, 0.15);
diff --git a/src/frontend/containers/ContentView/menu-items.tsx b/src/frontend/containers/ContentView/menu-items.tsx
index 5801aad1..63ca5d29 100644
--- a/src/frontend/containers/ContentView/menu-items.tsx
+++ b/src/frontend/containers/ContentView/menu-items.tsx
@@ -97,6 +97,12 @@ export const FileViewerMenuItems = ({ file }: { file: ClientFile }) => {
text="Open Tag Selector"
icon={IconSet.TAG}
/>
+
+
+ You can also import/export tags from selected files through the "Tagging" options in
+ the file context menu.
+
>
),
},
diff --git a/src/frontend/containers/Settings/BackgroundProcesses.tsx b/src/frontend/containers/Settings/BackgroundProcesses.tsx
index 70c3f6d7..545fe9d7 100644
--- a/src/frontend/containers/Settings/BackgroundProcesses.tsx
+++ b/src/frontend/containers/Settings/BackgroundProcesses.tsx
@@ -121,6 +121,12 @@ const TaggingServiceConfig = observer(() => {
{' '}
must be running.
+
+ {'The endpoint must accept a JSON request with the format:'}
+ {'{ file: } '}
+ {'and respond with a JSON in the format:'}
+ {'{ tags: [{ name: }, { name: }, ...] }'}
+
{prehost}
From 2f2cee64bd26d6e0ce4949cfb1495729c49142c2 Mon Sep 17 00:00:00 2001
From: RafaUC
Date: Sat, 13 Sep 2025 02:37:03 -0600
Subject: [PATCH 6/6] Change the nomenclature for tagging service related texts
to avoid assuming it is AI based, since more implementations are possible.
---
.../containers/ContentView/menu-items.tsx | 2 +-
src/frontend/containers/HelpCenter.tsx | 11 ++++----
.../Settings/BackgroundProcesses.tsx | 28 +++++++++++++++----
src/frontend/stores/FileStore.ts | 2 +-
4 files changed, 30 insertions(+), 13 deletions(-)
diff --git a/src/frontend/containers/ContentView/menu-items.tsx b/src/frontend/containers/ContentView/menu-items.tsx
index 63ca5d29..4e069fc8 100644
--- a/src/frontend/containers/ContentView/menu-items.tsx
+++ b/src/frontend/containers/ContentView/menu-items.tsx
@@ -99,7 +99,7 @@ export const FileViewerMenuItems = ({ file }: { file: ClientFile }) => {
/>
diff --git a/src/frontend/containers/HelpCenter.tsx b/src/frontend/containers/HelpCenter.tsx
index 0c0a7ea4..dcf37cc1 100644
--- a/src/frontend/containers/HelpCenter.tsx
+++ b/src/frontend/containers/HelpCenter.tsx
@@ -318,14 +318,15 @@ const PAGE_DATA: () => IPageData[] = () => [
content: (
<>
- You can set an endpoint to a locally hosted AI tagging service of your preference,
- allowing the app to send requests and automatically tag files. You can also configure
- the number of concurrent requests made to the service simultaneously. For more
- information, see the "Background Processes" section in the settings window.
+ You can set an endpoint to a locally hosted AI tagging service or any custom tagging
+ implementation, allowing the app to send requests and automatically tag files with the
+ service response. You can also configure the number of concurrent requests made to the
+ service simultaneously. For more information, see the "Background Processes" section
+ in the settings window.
To automatically tag selected files, use the
- {' "Tagging... > Tag Selected Using AI Tagging Service" '}
+ {' "Tagging... > Auto Tag Selected Using Tagging Service" '}
option in the file context menu.
A tagging service such as{' '}
media-tag-service
{' '}
- must be running.
+ or any custom tagging endpoint must be running.
- {'The endpoint must accept a JSON request with the format:'}
- {'{ file: } '}
- {'and respond with a JSON in the format:'}
- {'{ tags: [{ name: }, { name: }, ...] }'}
+
+ {'The endpoint must accept a JSON request with the format:'}
+
diff --git a/src/frontend/stores/FileStore.ts b/src/frontend/stores/FileStore.ts
index 8994363c..5c7af178 100644
--- a/src/frontend/stores/FileStore.ts
+++ b/src/frontend/stores/FileStore.ts
@@ -426,7 +426,7 @@ class FileStore {
if (successCount === 0) {
const message = taggingServiceURL
? 'Could not get tags from the tagging service: is it not running, or is the API/URL misconfigured?'
- : 'No Local Tagging Service API configured, go to: Settings > Background Processes > Local AI Tagging API URL';
+ : 'No Local Tagging Service API configured, go to: Settings > Background Processes > Local Tagging Service API URL';
AppToaster.show(
{
type: 'error',