diff options
| author | erdgeist <erdgeist@erdgeist.org> | 2026-07-27 02:53:21 +0200 |
|---|---|---|
| committer | erdgeist <erdgeist@erdgeist.org> | 2026-07-27 02:53:21 +0200 |
| commit | 180b5feba092db1339f7bb3217e91f0b22239bc5 (patch) | |
| tree | ed2912eb568639d027e2d54bc4f28c7a9406f7e0 /app | |
| parent | 102c33264fd1463cd88aa8245413e7b331dd9632 (diff) | |
Surface held locks in the dashboard's work-in-progress widget
A lock with no draft or autosave behind it was invisible to
everyone including its holder, until the next editor collided
with it. work_in_progress now admits those nodes, and the
widget names the holder rather than the last editor on any
locked row.
Also flips the ordering to stalest-first, so a backlog reads as a queue
rather than a feed, and gives the heading a real total: the count came
from the already-limited relation and could never exceed five.
Diffstat (limited to 'app')
| -rw-r--r-- | app/controllers/admin_controller.rb | 4 | ||||
| -rw-r--r-- | app/controllers/nodes_controller.rb | 2 | ||||
| -rw-r--r-- | app/models/node.rb | 11 | ||||
| -rw-r--r-- | app/views/admin/index.html.erb | 10 |
4 files changed, 19 insertions, 8 deletions
diff --git a/app/controllers/admin_controller.rb b/app/controllers/admin_controller.rb index d9cf1be6..2b35fd20 100644 --- a/app/controllers/admin_controller.rb +++ b/app/controllers/admin_controller.rb | |||
| @@ -5,7 +5,9 @@ class AdminController < ApplicationController | |||
| 5 | before_action :login_required | 5 | before_action :login_required |
| 6 | 6 | ||
| 7 | def index | 7 | def index |
| 8 | @drafts = Node.drafts_and_autosaves(current_user_id: current_user.id).limit(5) | 8 | scope = Node.work_in_progress(current_user_id: current_user.id) |
| 9 | @drafts_total = scope.reorder(nil).count | ||
| 10 | @drafts = scope.includes(:head, :draft, :lock_owner).limit(5) | ||
| 9 | @actions = NodeAction.order(:occurred_at => :desc, :id => :desc).limit(5) | 11 | @actions = NodeAction.order(:occurred_at => :desc, :id => :desc).limit(5) |
| 10 | end | 12 | end |
| 11 | 13 | ||
diff --git a/app/controllers/nodes_controller.rb b/app/controllers/nodes_controller.rb index 50b30881..2a2cde33 100644 --- a/app/controllers/nodes_controller.rb +++ b/app/controllers/nodes_controller.rb | |||
| @@ -231,7 +231,7 @@ class NodesController < ApplicationController | |||
| 231 | 231 | ||
| 232 | # Filter functions for admin views | 232 | # Filter functions for admin views |
| 233 | def drafts | 233 | def drafts |
| 234 | @nodes = index_matching(Node.drafts_and_autosaves) | 234 | @nodes = index_matching(Node.work_in_progress) |
| 235 | end | 235 | end |
| 236 | 236 | ||
| 237 | def mine | 237 | def mine |
diff --git a/app/models/node.rb b/app/models/node.rb index 02502f6c..1e61f9fe 100644 --- a/app/models/node.rb +++ b/app/models/node.rb | |||
| @@ -593,12 +593,15 @@ class Node < ApplicationRecord | |||
| 593 | .distinct | 593 | .distinct |
| 594 | end | 594 | end |
| 595 | 595 | ||
| 596 | def self.drafts_and_autosaves(current_user_id: nil) | 596 | # Nodes carrying unfinished work: a draft, an autosave, or a lock with |
| 597 | scope = where("draft_id IS NOT NULL OR autosave_id IS NOT NULL").not_in_trash | 597 | # neither behind it |
| 598 | return scope.order("updated_at DESC") unless current_user_id | 598 | def self.work_in_progress(current_user_id: nil) |
| 599 | scope = where("draft_id IS NOT NULL OR autosave_id IS NOT NULL OR locking_user_id IS NOT NULL") | ||
| 600 | .not_in_trash | ||
| 601 | return scope.order("nodes.updated_at ASC") unless current_user_id | ||
| 599 | 602 | ||
| 600 | scope.order( | 603 | scope.order( |
| 601 | Arel.sql(sanitize_sql_array(["CASE WHEN locking_user_id = ? THEN 0 ELSE 1 END, updated_at DESC", current_user_id])) | 604 | Arel.sql(sanitize_sql_array(["CASE WHEN locking_user_id = ? THEN 0 ELSE 1 END, nodes.updated_at ASC", current_user_id])) |
| 602 | ) | 605 | ) |
| 603 | end | 606 | end |
| 604 | 607 | ||
diff --git a/app/views/admin/index.html.erb b/app/views/admin/index.html.erb index 25bdbdc6..984858e5 100644 --- a/app/views/admin/index.html.erb +++ b/app/views/admin/index.html.erb | |||
| @@ -23,7 +23,7 @@ | |||
| 23 | 23 | ||
| 24 | <div id="dashboard_widgets"> | 24 | <div id="dashboard_widgets"> |
| 25 | <div class="dashboard_widget"> | 25 | <div class="dashboard_widget"> |
| 26 | <h3><%= t(".drafts_widget") %></h3> | 26 | <h3><%= t(".drafts_widget", :total => @drafts_total) %></h3> |
| 27 | <ul> | 27 | <ul> |
| 28 | <% @drafts.each do |node| %> | 28 | <% @drafts.each do |node| %> |
| 29 | <li> | 29 | <li> |
| @@ -32,7 +32,13 @@ | |||
| 32 | <span class="field_hint"><%= link_to_path("#{node.unique_name} ↗", node.unique_name) %></span> | 32 | <span class="field_hint"><%= link_to_path("#{node.unique_name} ↗", node.unique_name) %></span> |
| 33 | </div> | 33 | </div> |
| 34 | <span class="dashboard_widget_meta"> | 34 | <span class="dashboard_widget_meta"> |
| 35 | <% if (editor = node_last_editor(node)) %><%= editor %>, <% end %><%= relative_time_phrase(node.updated_at) %> | 35 | <% if node.locked? %> |
| 36 | <%= icon("lock", library: "tabler", "aria-label": t(".held_by")) %> | ||
| 37 | <%= node.lock_owner.login %>, | ||
| 38 | <% elsif (editor = node_last_editor(node)) %> | ||
| 39 | <%= editor %>, | ||
| 40 | <% end %> | ||
| 41 | <%= relative_time_phrase(node.updated_at) %> | ||
| 36 | </span> | 42 | </span> |
| 37 | </li> | 43 | </li> |
| 38 | <% end %> | 44 | <% end %> |
