branch: externals/gnosis
commit 66117f79a455d71020b79f94fd06509309f10ac7
Author: Thanos Apollo <[email protected]>
Commit: Thanos Apollo <[email protected]>

    gnosis-dashboard: Bulk tag operations, fix tags view N+1 query.
    
    - Replace per-tag SELECT with single GROUP BY for tag counts
    - Add mark/unmark bindings (m/M/u/U) to tags mode
    - Bulk delete/suspend works on marked tags
    - Delete removes entries in-place without full refresh
    - Fix mark-all to use tabulated-list-entries generically
---
 gnosis-dashboard.el | 77 +++++++++++++++++++++++++++++++++++------------------
 1 file changed, 51 insertions(+), 26 deletions(-)

diff --git a/gnosis-dashboard.el b/gnosis-dashboard.el
index 3ee447fc36..191e41e8d0 100644
--- a/gnosis-dashboard.el
+++ b/gnosis-dashboard.el
@@ -742,34 +742,44 @@ GEN: load generation — no-op if stale."
     (forward-line (- current-line 1))))
 
 (defun gnosis-dashboard-delete-tag (&optional tag)
-  "Delete TAG from all themata."
+  "Delete TAG or marked tags from all themata."
   (interactive)
-  (let ((tag (or tag (tabulated-list-get-id))))
-    (when (y-or-n-p (format "Delete tag %s?"
-                           (propertize tag 'face 'font-lock-keyword-face)))
-      (gnosis--delete 'thema-tag `(= tag ,tag))
-      (gnosis-dashboard-output-tags))))
+  (let ((tags (or (and gnosis-dashboard--selected-ids
+                       (prog1 gnosis-dashboard--selected-ids
+                         (setq gnosis-dashboard--selected-ids nil)))
+                  (list (or tag (tabulated-list-get-id))))))
+    (when (y-or-n-p (format "Delete %d tag(s)?" (length tags)))
+      (dolist (tag tags)
+        (gnosis--delete 'thema-tag `(= tag ,tag)))
+      (remove-overlays nil nil 'gnosis-mark t)
+      (setq tabulated-list-entries
+            (cl-remove-if (lambda (entry) (member (car entry) tags))
+                          tabulated-list-entries))
+      (dolist (tag tags)
+        (gnosis-tl-delete-entry tag))
+      (gnosis-dashboard--set-header-line (length tabulated-list-entries)))))
 
 
 
 (defun gnosis-dashboard-suspend-tag (&optional tag)
-  "Suspend themata of TAG."
+  "Suspend themata of TAG or marked tags."
   (interactive)
-  (let* ((tag (or tag (tabulated-list-get-id)))
-        (themata (gnosis-get-tag-themata tag))
-        (suspend (if current-prefix-arg 0 1))
-        (confirm-msg (y-or-n-p
-                      (if (= suspend 0)
-                          "Unsuspend all themata for tag? "
-                        "Suspend all themata for tag?"))))
-    (when confirm-msg
+  (let* ((tags (or (and gnosis-dashboard--selected-ids
+                        (prog1 gnosis-dashboard--selected-ids
+                          (setq gnosis-dashboard--selected-ids nil)))
+                   (list (or tag (tabulated-list-get-id)))))
+         (themata (cl-remove-duplicates
+                   (cl-mapcan #'gnosis-get-tag-themata tags)))
+         (suspend (if current-prefix-arg 0 1))
+         (action (if (= suspend 0) "Unsuspend" "Suspend")))
+    (when (y-or-n-p (format "%s %d themata across %d tag(s)?"
+                            action (length themata) (length tags)))
       (gnosis-sqlite-execute-batch (gnosis--ensure-db)
         "UPDATE review_log SET suspend = ? WHERE id IN (%s)"
         themata
         (list suspend))
-      (if (= suspend 0)
-         (message "Unsuspended %s themata" (length themata))
-       (message "Suspended %s themata" (length themata))))))
+      (remove-overlays nil nil 'gnosis-mark t)
+      (message "%sed %d themata" action (length themata)))))
 
 (defun gnosis-dashboard-tag-view-themata (&optional tag)
   "View themata for TAG."
@@ -786,6 +796,11 @@ GEN: load generation — no-op if stale."
     ("RET" "View themata" gnosis-dashboard-tag-view-themata)
     ("q" "Back to dashboard" gnosis-dashboard)
     ("g" "Refresh" gnosis-dashboard-return :transient t)]
+   ["Mark"
+    ("m" "Toggle mark" gnosis-dashboard-mark-toggle :transient t)
+    ("M" "Mark all" gnosis-dashboard-mark-all :transient t)
+    ("u" "Unmark" gnosis-dashboard-mark-toggle :transient t)
+    ("U" "Unmark all" gnosis-dashboard-unmark-all :transient t)]
    ["Edit"
     ("e" "Rename tag" gnosis-dashboard-rename-tag :transient t)
     ("r" "Rename tag" gnosis-dashboard-rename-tag :transient t)
@@ -801,7 +816,11 @@ GEN: load generation — no-op if stale."
   "s" #'gnosis-dashboard-suspend-tag
   "r" #'gnosis-dashboard-rename-tag
   "d" #'gnosis-dashboard-delete-tag
-  "g" #'gnosis-dashboard-return)
+  "g" #'gnosis-dashboard-return
+  "m" #'gnosis-dashboard-mark-toggle
+  "M" #'gnosis-dashboard-mark-all
+  "u" #'gnosis-dashboard-mark-toggle
+  "U" #'gnosis-dashboard-unmark-all)
 
 (define-minor-mode gnosis-dashboard-tags-mode
   "Mode for dashboard output of tags."
@@ -810,7 +829,12 @@ GEN: load generation — no-op if stale."
 (defun gnosis-dashboard-output-tags (&optional tags)
   "Format gnosis dashboard with output of TAGS."
   (interactive)
-  (let ((tags (or tags (gnosis-get-tags--unique))))
+  (let* ((tag-counts (gnosis-sqlite-select (gnosis--ensure-db)
+                       "SELECT tag, COUNT(*) FROM thema_tag GROUP BY tag"))
+         (count-ht (let ((ht (make-hash-table :test 'equal :size (length 
tag-counts))))
+                     (dolist (row tag-counts ht)
+                       (puthash (car row) (cadr row) ht))))
+         (tags (or tags (mapcar #'car tag-counts))))
     (pop-to-buffer-same-window gnosis-dashboard-buffer-name)
     (gnosis-dashboard-enable-mode)
     ;; Disable other dashboard modes
@@ -825,9 +849,9 @@ GEN: load generation — no-op if stale."
     (setq-local gnosis-dashboard--base-header-line header-line-format)
     (setq tabulated-list-entries
           (cl-loop for tag in tags
-                   for output = (gnosis-dashboard-output-tag tag)
-                   collect (list (car output)
-                                 (vconcat output))))
+                   collect (list tag
+                                 (vector tag (number-to-string
+                                              (gethash tag count-ht 0))))))
     (tabulated-list-print t)
     (gnosis-dashboard--set-header-line (length tabulated-list-entries))))
 
@@ -945,9 +969,10 @@ GEN: load generation — no-op if stale."
       (let ((ov (make-overlay (point-min) (point-max))))
         (overlay-put ov 'face 'highlight)
         (overlay-put ov 'gnosis-mark t))
-      ;; Set selected IDs
-      (setq gnosis-dashboard--selected-ids gnosis-dashboard-thema-ids)
-      (message "Marked %d items" (count-lines (point-min) (point-max))))))
+      ;; Set selected IDs from all entries
+      (setq gnosis-dashboard--selected-ids
+            (mapcar #'car tabulated-list-entries))
+      (message "Marked %d items" (length gnosis-dashboard--selected-ids)))))
 
 
 (defun gnosis-dashboard-bulk-link ()

Reply via email to