@@ -5,9 +5,11 @@ use super::output::DeleteTagOutput;
55use crate :: {
66 context:: CoreContext ,
77 infra:: action:: { error:: ActionError , LibraryAction } ,
8+ infra:: db:: entities:: { entry, tag, user_metadata, user_metadata_tag} ,
89 library:: Library ,
910 ops:: tags:: TagManager ,
1011} ;
12+ use sea_orm:: { ColumnTrait , EntityTrait , QueryFilter } ;
1113use serde:: { Deserialize , Serialize } ;
1214use std:: sync:: Arc ;
1315
@@ -31,8 +33,66 @@ impl LibraryAction for DeleteTagAction {
3133 _context : Arc < CoreContext > ,
3234 ) -> Result < Self :: Output , ActionError > {
3335 let db = library. db ( ) ;
34- let manager = TagManager :: new ( Arc :: new ( db. conn ( ) . clone ( ) ) ) ;
36+ let conn = db. conn ( ) ;
3537
38+ // Collect affected entry UUIDs BEFORE deleting (same pattern as unapply/action.rs)
39+ let affected_entry_uuids = {
40+ let tag_model = tag:: Entity :: find ( )
41+ . filter ( tag:: Column :: Uuid . eq ( self . input . tag_id ) )
42+ . one ( conn)
43+ . await
44+ . map_err ( |e| ActionError :: Internal ( format ! ( "DB error: {}" , e) ) ) ?;
45+
46+ let mut uuids = Vec :: new ( ) ;
47+ if let Some ( tag_model) = tag_model {
48+ let umt_records = user_metadata_tag:: Entity :: find ( )
49+ . filter ( user_metadata_tag:: Column :: TagId . eq ( tag_model. id ) )
50+ . all ( conn)
51+ . await
52+ . map_err ( |e| ActionError :: Internal ( format ! ( "DB error: {}" , e) ) ) ?;
53+
54+ let um_ids: Vec < i32 > = umt_records. iter ( ) . map ( |r| r. user_metadata_id ) . collect ( ) ;
55+ if !um_ids. is_empty ( ) {
56+ let um_records = user_metadata:: Entity :: find ( )
57+ . filter ( user_metadata:: Column :: Id . is_in ( um_ids) )
58+ . all ( conn)
59+ . await
60+ . map_err ( |e| ActionError :: Internal ( format ! ( "DB error: {}" , e) ) ) ?;
61+
62+ // Entry-scoped metadata → direct entry UUIDs
63+ uuids. extend ( um_records. iter ( ) . filter_map ( |um| um. entry_uuid ) ) ;
64+
65+ // Content-scoped metadata → find all entries with that content
66+ let ci_uuids: Vec < uuid:: Uuid > = um_records
67+ . iter ( )
68+ . filter_map ( |um| um. content_identity_uuid )
69+ . collect ( ) ;
70+ if !ci_uuids. is_empty ( ) {
71+ let cis = crate :: infra:: db:: entities:: content_identity:: Entity :: find ( )
72+ . filter (
73+ crate :: infra:: db:: entities:: content_identity:: Column :: Uuid
74+ . is_in ( ci_uuids. into_iter ( ) . map ( Some ) ) ,
75+ )
76+ . all ( conn)
77+ . await
78+ . map_err ( |e| ActionError :: Internal ( format ! ( "DB error: {}" , e) ) ) ?;
79+ let ci_ids: Vec < i32 > = cis. iter ( ) . map ( |ci| ci. id ) . collect ( ) ;
80+ if !ci_ids. is_empty ( ) {
81+ let entries = entry:: Entity :: find ( )
82+ . filter ( entry:: Column :: ContentId . is_in ( ci_ids. into_iter ( ) . map ( Some ) ) )
83+ . all ( conn)
84+ . await
85+ . map_err ( |e| ActionError :: Internal ( format ! ( "DB error: {}" , e) ) ) ?;
86+ uuids. extend ( entries. iter ( ) . filter_map ( |e| e. uuid ) ) ;
87+ }
88+ }
89+ }
90+ }
91+ uuids
92+ } ;
93+
94+ // Delete the tag and all its relationships (atomic transaction)
95+ let manager = TagManager :: new ( Arc :: new ( conn. clone ( ) ) ) ;
3696 manager
3797 . delete_tag ( self . input . tag_id )
3898 . await
@@ -44,18 +104,29 @@ impl LibraryAction for DeleteTagAction {
44104 // tags will reappear on other devices after sync. Tracked for a dedicated
45105 // sync-deletion PR.
46106
47- // Emit resource event so frontend refreshes tag lists
48107 let resource_manager = crate :: domain:: ResourceManager :: new (
49- Arc :: new ( db . conn ( ) . clone ( ) ) ,
108+ Arc :: new ( conn. clone ( ) ) ,
50109 _context. events . clone ( ) ,
51110 ) ;
111+
112+ // Emit "tag" event so sidebar refreshes
52113 if let Err ( e) = resource_manager
53114 . emit_resource_events ( "tag" , vec ! [ self . input. tag_id] )
54115 . await
55116 {
56117 tracing:: warn!( "Failed to emit tag resource event after deletion: {}" , e) ;
57118 }
58119
120+ // Emit "file" events so explorer grid updates (removes tag dots)
121+ if !affected_entry_uuids. is_empty ( ) {
122+ if let Err ( e) = resource_manager
123+ . emit_resource_events ( "file" , affected_entry_uuids)
124+ . await
125+ {
126+ tracing:: warn!( "Failed to emit file resource events after tag deletion: {}" , e) ;
127+ }
128+ }
129+
59130 Ok ( DeleteTagOutput { deleted : true } )
60131 }
61132
0 commit comments