feat(images): Show removed images and Return to library (#498)
- GET /images/output?mode=workspace&removed=1 lists only files a removal
mark hides; every workspace page carries removed_total.
- POST /images/removed/return {items | filter} starts a scan job,
"Return images to the library": the marks that still hide their file
go in one transaction, then exactly those files are scanned, so their
prompt links come back from their metadata. Tags, categories,
collections and favorites do not come back.
- The marks generation moves again after the commit, so a reader that
cached the marks mid-transaction reloads them.
- Images: Show removed images (N) heading toggle (D162), Removed chips,
a bar with only Return to library and Clear, Return to library in the
side panel; the view is never saved or restored.
This commit is contained in:
@@ -43,6 +43,7 @@ from .image_categories import DELETE_SQL as DELETE_CATEGORY_SQL
|
||||
from .image_removal_schema import (
|
||||
META_TABLE,
|
||||
TABLE,
|
||||
bump_generation,
|
||||
clear_marks,
|
||||
has_marks_table,
|
||||
mark_of,
|
||||
@@ -319,4 +320,29 @@ class ImageRemovalOperations:
|
||||
if not locators:
|
||||
return 0
|
||||
with self._pair_transaction() as conn:
|
||||
return clear_marks(conn, locators)
|
||||
removed = clear_marks(conn, locators)
|
||||
# #498: again after the commit, so a reader that cached the marks
|
||||
# between the in-transaction bump and the commit reloads them.
|
||||
bump_generation()
|
||||
return removed
|
||||
|
||||
def clear_hiding_marks(self, files) -> set:
|
||||
"""Delete the marks that still hide their file (#498, Return to library).
|
||||
|
||||
*files* are ``(locator, path)`` pairs. In one ``BEGIN IMMEDIATE``
|
||||
transaction each mark is read again and deleted only while the file at
|
||||
*path* still has its size and ``mtime_ns``. Returns the locators whose
|
||||
marks went.
|
||||
"""
|
||||
cleared = set()
|
||||
files = list(files)
|
||||
if not files:
|
||||
return cleared
|
||||
with self._pair_transaction() as conn:
|
||||
for locator, path in files:
|
||||
mark = mark_of(conn, locator)
|
||||
if mark is not None and mark_hides({locator: mark}, locator, path):
|
||||
cleared.add(locator)
|
||||
clear_marks(conn, sorted(cleared))
|
||||
bump_generation()
|
||||
return cleared
|
||||
|
||||
@@ -155,6 +155,11 @@ def _bump() -> None:
|
||||
_generation += 1
|
||||
|
||||
|
||||
def bump_generation() -> None:
|
||||
"""Move the generation after a commit (a cached read made before it reloads)."""
|
||||
_bump()
|
||||
|
||||
|
||||
def has_marks_table(conn: sqlite3.Connection) -> bool:
|
||||
return (
|
||||
conn.execute(
|
||||
|
||||
Reference in New Issue
Block a user