diff options
| author | erdgeist <erdgeist@erdgeist.org> | 2026-07-12 23:42:43 +0200 |
|---|---|---|
| committer | erdgeist <erdgeist@erdgeist.org> | 2026-07-12 23:42:43 +0200 |
| commit | b271648f89cba7cafafa1b73b1658b1c1bc0e4b0 (patch) | |
| tree | 567302b1aa6add08b46e0be028a0972f76c52abc | |
| parent | cf93acb8ad44ba9cd486e8f6457d9fd9fbc041cc (diff) | |
Rebuild the admin dashboard: icon nav, search, signposts, widgets
Replaces the old admin#index wizard -- accreted over years, never
designed as a whole -- with the dashboard settled on this session:
a three-icon nav (dashboard/search/log out, no locale selector), a
nodes-first search bar, four task signposts, and two symmetric
widgets (drafts/autosaves, recent changes) with a quiet housekeeping
row beneath them.
Node.recently_changed now filters and orders by the head page's own
updated_at instead of the node's blanket timestamp, so a lock/unlock
cycle with no actual publish no longer surfaces here, and the
original publisher is no longer misattributed to someone else's
housekeeping action. This also restores the "published" qualifier on
each entry, which the query previously couldn't guarantee was true.
@mynodes and its dedicated "My Work" table are retired along with the
old wizard -- "Continue my work" is a link to the existing, already-
correct NodesController#mine instead of a second, duplicate query.
Its one dedicated test (dedup across multiple revisions by the same
user) is ported to nodes_controller_test.rb, since mine already
carries the same .distinct protection the old query did; it just had
no test of its own until now.
| -rw-r--r-- | app/controllers/admin_controller.rb | 21 | ||||
| -rw-r--r-- | app/helpers/nodes_helper.rb | 12 | ||||
| -rw-r--r-- | app/models/node.rb | 6 | ||||
| -rw-r--r-- | app/views/admin/_menu.html.erb | 14 | ||||
| -rw-r--r-- | app/views/admin/index.html.erb | 210 | ||||
| -rw-r--r-- | test/controllers/admin_controller_test.rb | 20 | ||||
| -rw-r--r-- | test/controllers/nodes_controller_test.rb | 20 | ||||
| -rw-r--r-- | test/models/node_test.rb | 24 |
8 files changed, 134 insertions, 193 deletions
diff --git a/app/controllers/admin_controller.rb b/app/controllers/admin_controller.rb index 8445997..37fd78b 100644 --- a/app/controllers/admin_controller.rb +++ b/app/controllers/admin_controller.rb | |||
| @@ -5,25 +5,8 @@ class AdminController < ApplicationController | |||
| 5 | before_action :login_required | 5 | before_action :login_required |
| 6 | 6 | ||
| 7 | def index | 7 | def index |
| 8 | @drafts = Node.where("draft_id IS NOT NULL OR autosave_id IS NOT NULL") | 8 | @drafts = Node.drafts_and_autosaves(current_user_id: current_user.id).limit(5) |
| 9 | .limit(50).order("updated_at desc") | 9 | @recent_changes = Node.recently_changed.limit(5) |
| 10 | |||
| 11 | @drafts_count = Node.where("draft_id IS NOT NULL OR autosave_id IS NOT NULL").count | ||
| 12 | |||
| 13 | @recent_changes = Node.where( | ||
| 14 | "updated_at < ? AND updated_at > ? AND parent_id IS NOT NULL", | ||
| 15 | Time.now, Time.now - 14.days | ||
| 16 | ).limit(50).order("updated_at desc") | ||
| 17 | |||
| 18 | ordered_with_level = Node.root.self_and_descendants_ordered_with_level | ||
| 19 | @sitemap_depth = {} | ||
| 20 | ordered_with_level.each { |node, level| @sitemap_depth[node.id] = level } | ||
| 21 | @sitemap = ordered_with_level.map(&:first).reject(&:update?) | ||
| 22 | |||
| 23 | @mynodes = Node.joins(:pages) | ||
| 24 | .where("pages.user_id = ? or pages.editor_id = ?", current_user, current_user) | ||
| 25 | .order("updated_at desc") | ||
| 26 | .distinct.first(50) | ||
| 27 | end | 10 | end |
| 28 | 11 | ||
| 29 | def conventions | 12 | def conventions |
diff --git a/app/helpers/nodes_helper.rb b/app/helpers/nodes_helper.rb index 1268b63..5884c8c 100644 --- a/app/helpers/nodes_helper.rb +++ b/app/helpers/nodes_helper.rb | |||
| @@ -28,6 +28,18 @@ module NodesHelper | |||
| 28 | User.all.map {|u| [u.login, u.id]} | 28 | User.all.map {|u| [u.login, u.id]} |
| 29 | end | 29 | end |
| 30 | 30 | ||
| 31 | def node_last_editor(node) | ||
| 32 | editor = node.draft&.editor || node.head&.editor | ||
| 33 | return nil unless editor | ||
| 34 | editor == current_user ? t("editor_self") : editor.login | ||
| 35 | end | ||
| 36 | |||
| 37 | def node_head_editor(node) | ||
| 38 | editor = node.head&.editor | ||
| 39 | return nil unless editor | ||
| 40 | editor == current_user ? t("publisher_self") : editor.login | ||
| 41 | end | ||
| 42 | |||
| 31 | DEFAULT_EVENT_TAG_BY_PAGE_TAG = { | 43 | DEFAULT_EVENT_TAG_BY_PAGE_TAG = { |
| 32 | 'erfa-detail' => 'open-day', | 44 | 'erfa-detail' => 'open-day', |
| 33 | 'chaostreff-detail' => 'open-day' | 45 | 'chaostreff-detail' => 'open-day' |
diff --git a/app/models/node.rb b/app/models/node.rb index aa2f7f3..1d0a089 100644 --- a/app/models/node.rb +++ b/app/models/node.rb | |||
| @@ -377,10 +377,10 @@ class Node < ApplicationRecord | |||
| 377 | end | 377 | end |
| 378 | 378 | ||
| 379 | def self.recently_changed | 379 | def self.recently_changed |
| 380 | where( | 380 | includes(:head).where( |
| 381 | "nodes.updated_at < ? AND nodes.updated_at > ? AND nodes.parent_id IS NOT NULL", | 381 | "pages.updated_at < ? AND pages.updated_at > ? AND nodes.parent_id IS NOT NULL", |
| 382 | Time.now, Time.now - 14.days | 382 | Time.now, Time.now - 14.days |
| 383 | ) | 383 | ).order("pages.updated_at desc").references(:head) |
| 384 | end | 384 | end |
| 385 | 385 | ||
| 386 | protected | 386 | protected |
diff --git a/app/views/admin/_menu.html.erb b/app/views/admin/_menu.html.erb index 4302987..970429d 100644 --- a/app/views/admin/_menu.html.erb +++ b/app/views/admin/_menu.html.erb | |||
| @@ -1,9 +1,5 @@ | |||
| 1 | <%= language_selector %> | 1 | <%= link_to icon("home", library: "tabler", "aria-hidden": true), admin_path, "aria-label": "Dashboard" %> |
| 2 | <%= button_to 'Logout', logout_path, method: :delete %> | 2 | <a href="#" onclick="admin_search.display_toggle(); return false;" aria-label="Search"><%= icon("search", library: "tabler", "aria-hidden": true) %></a> |
| 3 | <%= link_to 'Overview', admin_path %> | 3 | <%= button_to logout_path, method: :delete, aria: { label: "Log out" } do %> |
| 4 | <a href="#" onclick="admin_search.display_toggle(); return false;">search</a> | 4 | <%= icon("logout", library: "tabler", "aria-hidden": true) %> |
| 5 | <%= link_to 'Nodes', nodes_path, selected?('nodes') %> | 5 | <% end %> |
| 6 | <%= link_to 'Assets', assets_path, selected?('assets') %> | ||
| 7 | <%= link_to 'Events', events_path, selected?('events') %> | ||
| 8 | <%= link_to 'User', users_path, selected?('users') %> | ||
| 9 | <%= link_to 'Navigation', menu_items_path, selected?('menu_items') %> | ||
diff --git a/app/views/admin/index.html.erb b/app/views/admin/index.html.erb index c67ccb3..bdb555e 100644 --- a/app/views/admin/index.html.erb +++ b/app/views/admin/index.html.erb | |||
| @@ -1,155 +1,81 @@ | |||
| 1 | <div id="admin_wizard"> | 1 | <h1>cccms dashboard</h1> |
| 2 | <h2>Quick links</h2> | 2 | <div id="dashboard_search"> |
| 3 | <div class="admin_wizard_button"><%= link_to 'Create post or page', new_node_path, :only_path => false %></div> | 3 | <%= form_tag admin_search_path, method: :get do %> |
| 4 | <div class="admin_wizard_button"><a href="#" id="admin_wizard_my_work" class="button">Continue my work</a></div> | 4 | <%= text_field_tag :search_term, nil, id: "dashboard_search_term", placeholder: "Search nodes and tags…", autocomplete: "off" %> |
| 5 | <div class="admin_wizard_button"><a href="#" id="admin_wizard_create_page" class="button">Add a page in the page tree</a></div> | 5 | <% end %> |
| 6 | <div class="admin_wizard_button"><%= link_to("Upload a new asset", new_asset_path, :only_path => false) %></div> | 6 | <div id="dashboard_search_results" class="search_results"></div> |
| 7 | </div> | 7 | </div> |
| 8 | 8 | ||
| 9 | <p id="overview_toggle"> | 9 | <div id="dashboard_signposts" class="button_row"> |
| 10 | <a href="#" id="recent_changes_toggle" class="button">recent changes</a> | 10 | <%= link_to new_node_path, class: "action_button" do %> |
| 11 | <a href="#" id="my_work_toggle" class="button">my work</a> | 11 | <%= icon("plus", library: "tabler", "aria-hidden": true) %> Create post |
| 12 | <a href="#" id="current_drafts_toggle" class="button">current drafts (<%= @drafts_count %>)</a> | 12 | <% end %> |
| 13 | <a href="#" id="admin_sitemap_toggle" class="button">site map</a> | 13 | <%= link_to chapters_nodes_path, class: "action_button" do %> |
| 14 | </p> | 14 | <%= icon("map-pin", library: "tabler", "aria-hidden": true) %> Find a chapter |
| 15 | <% end %> | ||
| 16 | <%= link_to new_asset_path, class: "action_button" do %> | ||
| 17 | <%= icon("upload", library: "tabler", "aria-hidden": true) %> Upload asset | ||
| 18 | <% end %> | ||
| 19 | <%= link_to sitemap_nodes_path, class: "action_button" do %> | ||
| 20 | <%= icon("list-tree", library: "tabler", "aria-hidden": true) %> Add a page in the page tree | ||
| 21 | <% end %> | ||
| 22 | </div> | ||
| 15 | 23 | ||
| 16 | <div id="recent_changes_table"> | 24 | <div id="dashboard_widgets"> |
| 17 | 25 | <div class="dashboard_widget"> | |
| 18 | <h2>Recent Changes</h2> | 26 | <h3>Drafts and autosaves</h3> |
| 27 | <ul> | ||
| 28 | <% @drafts.each do |node| %> | ||
| 29 | <li> | ||
| 30 | <div> | ||
| 31 | <%= link_to title_for_node(node), node_path(node) %> | ||
| 32 | <span class="field_hint"><%= link_to_path("#{node.unique_name} ↗", node.unique_name) %></span> | ||
| 33 | </div> | ||
| 34 | <span class="dashboard_widget_meta"> | ||
| 35 | <% if (editor = node_last_editor(node)) %><%= editor %>, <% end %><%= relative_time_phrase(node.updated_at) %> | ||
| 36 | </span> | ||
| 37 | </li> | ||
| 38 | <% end %> | ||
| 39 | </ul> | ||
| 40 | <%= link_to "See all drafts →", drafts_nodes_path %> | ||
| 41 | </div> | ||
| 19 | 42 | ||
| 20 | <table class="node_table"> | 43 | <div class="dashboard_widget"> |
| 21 | <tr class="header"> | 44 | <h3>Recent changes</h3> |
| 22 | <th class="node_id">ID</th> | 45 | <ul> |
| 23 | <th class="title">Title</th> | ||
| 24 | <th class="actions">Actions</th> | ||
| 25 | <th class="editor">Locked by</th> | ||
| 26 | <th class="revision">Rev.</th> | ||
| 27 | </tr> | ||
| 28 | <% @recent_changes.each do |node| %> | 46 | <% @recent_changes.each do |node| %> |
| 29 | <tr class="<%= cycle("even", "odd") %>"> | 47 | <li> |
| 30 | <td class="node_id"><%= node.id %></td> | 48 | <div> |
| 31 | <td class="title"> | 49 | <%= link_to title_for_node(node), node_path(node) %> |
| 32 | <h4><%= link_to title_for_node(node), node_path(node) %></h4> | 50 | <span class="field_hint"><%= link_to_path("#{node.unique_name} ↗", node.unique_name) %></span> |
| 33 | <p><%= link_to_path(node.unique_name, node.unique_name) %></p> | 51 | </div> |
| 34 | </td> | 52 | <span class="dashboard_widget_meta"> |
| 35 | <td class="actions"> | 53 | <%= (editor = node_head_editor(node)) ? t("published_by", editor: editor) : t("published") %>, <%= relative_time_phrase(node.head.updated_at) %> |
| 36 | <%= link_to 'show', node_path(node) %> | 54 | </span> |
| 37 | <%= link_to 'Revisions', node_revisions_path(node) %> | 55 | </li> |
| 38 | </td> | ||
| 39 | <td> | ||
| 40 | <%= node.lock_owner.login if node.lock_owner %> | ||
| 41 | </td> | ||
| 42 | <td> | ||
| 43 | <%= link_to ( node.draft ? node.draft.revision : (node.head ? node.head.revision : "EMPTY" ) ), node_revisions_path(node) %> | ||
| 44 | </td> | ||
| 45 | </tr> | ||
| 46 | <% end %> | 56 | <% end %> |
| 47 | </table> | 57 | </ul> |
| 58 | <%= link_to "See all recent changes →", recent_nodes_path %> | ||
| 59 | </div> | ||
| 48 | </div> | 60 | </div> |
| 49 | 61 | ||
| 50 | <div id="my_work_table"> | 62 | <div id="dashboard_housekeeping"> |
| 51 | 63 | <h3>Housekeeping</h3> | |
| 52 | <h2>My Work</h2> | 64 | <div class="button_row"> |
| 53 | 65 | <%= link_to nodes_path, class: "action_button" do %> | |
| 54 | <table class="node_table"> | 66 | <%= icon("list", library: "tabler", "aria-hidden": true) %> Nodes |
| 55 | <tr class="header"> | ||
| 56 | <th class="node_id">ID</th> | ||
| 57 | <th class="title">Title</th> | ||
| 58 | <th class="actions">Actions</th> | ||
| 59 | <th class="editor">Locked by</th> | ||
| 60 | <th class="revision">Rev.</th> | ||
| 61 | </tr> | ||
| 62 | <% @mynodes.each do |node| %> | ||
| 63 | <tr class="<%= cycle("even", "odd") %>"> | ||
| 64 | <td class="node_id"><%= node.id %></td> | ||
| 65 | <td class="title"> | ||
| 66 | <h4><%= link_to title_for_node(node), node_path(node) %></h4> | ||
| 67 | <p><%= link_to_path(node.unique_name, node.unique_name) %></p> | ||
| 68 | </td> | ||
| 69 | <td class="actions"> | ||
| 70 | <%= link_to 'show', node_path(node) %> | ||
| 71 | <%= link_to 'Revisions', node_revisions_path(node) %> | ||
| 72 | </td> | ||
| 73 | <td> | ||
| 74 | <%= node.lock_owner.login if node.lock_owner %> | ||
| 75 | </td> | ||
| 76 | <td> | ||
| 77 | <%= link_to ( node.draft ? node.draft.revision : (node.head ? node.head.revision : "EMPTY" ) ), node_revisions_path(node) %> | ||
| 78 | </td> | ||
| 79 | </tr> | ||
| 80 | <% end %> | 67 | <% end %> |
| 81 | </table> | 68 | <%= link_to events_path, class: "action_button" do %> |
| 82 | </div> | 69 | <%= icon("calendar", library: "tabler", "aria-hidden": true) %> Events |
| 83 | |||
| 84 | <div id="current_drafts_table"> | ||
| 85 | |||
| 86 | <h2>Current Drafts & Autosaves (<%= @drafts_count %>)</h2> | ||
| 87 | |||
| 88 | <table class="node_table"> | ||
| 89 | <tr class="header"> | ||
| 90 | <th class="node_id">ID</th> | ||
| 91 | <th class="title">Title</th> | ||
| 92 | <th class="actions">Actions</th> | ||
| 93 | <th class="editor">Locked by</th> | ||
| 94 | <th class="revision">Rev.</th> | ||
| 95 | <th class="autosave">Autosave</th> | ||
| 96 | </tr> | ||
| 97 | <% @drafts.each do |node| %> | ||
| 98 | <tr class="<%= cycle("even", "odd") %>"> | ||
| 99 | <td class="node_id"><%= node.id %></td> | ||
| 100 | <td class="title"> | ||
| 101 | <h4><%= link_to title_for_node(node), node_path(node) %></h4> | ||
| 102 | <p><%= link_to_path(node.unique_name, node.unique_name) %></p> | ||
| 103 | </td> | ||
| 104 | <td class="actions"> | ||
| 105 | <%= link_to 'show', node_path(node) %> | ||
| 106 | <%= link_to 'Revisions', node_revisions_path(node) %> | ||
| 107 | <% if pair = node.available_layer_pairs.last %> | ||
| 108 | <%= link_to 'diff', diff_node_revisions_path(node, start_revision: pair.first, end_revision: pair.last) %> | ||
| 109 | <% end %> | ||
| 110 | </td> | ||
| 111 | <td> | ||
| 112 | <%= node.lock_owner.login if node.lock_owner %> | ||
| 113 | </td> | ||
| 114 | <td> | ||
| 115 | <%= link_to ( node.draft ? node.draft.revision : (node.head ? node.head.revision : "EMPTY" ) ), node_revisions_path(node) %> | ||
| 116 | </td> | ||
| 117 | <td class="autosave"> | ||
| 118 | <%= node.autosave ? "unsaved changes" : "" %> | ||
| 119 | </td> | ||
| 120 | </tr> | ||
| 121 | <% end %> | 70 | <% end %> |
| 122 | </table> | 71 | <%= link_to assets_path, class: "action_button" do %> |
| 123 | </div> | 72 | <%= icon("folder", library: "tabler", "aria-hidden": true) %> Assets |
| 124 | 73 | <% end %> | |
| 125 | <div id="admin_sitemap_table"> | 74 | <%= link_to users_path, class: "action_button" do %> |
| 126 | 75 | <%= icon("users", library: "tabler", "aria-hidden": true) %> Users | |
| 127 | <h2>Sitemap</h2> | ||
| 128 | |||
| 129 | <table class="node_table"> | ||
| 130 | <tr class="header"> | ||
| 131 | <th class="node_id">ID</th> | ||
| 132 | <th class="title">Title</th> | ||
| 133 | <th class="actions">Actions</th> | ||
| 134 | <th class="editor">Locked by</th> | ||
| 135 | </tr> | ||
| 136 | <% @sitemap.each do |node| %> | ||
| 137 | <% if !node.nil? %> | ||
| 138 | <tr class="<%= cycle("even", "odd") %>"> | ||
| 139 | <td class="node_id" style="padding-left: <%= @sitemap_depth[node.id] * 30 %>px;"><%= node.id %></td> | ||
| 140 | <td class="title" style="padding-left: <%= @sitemap_depth[node.id] * 30 %>px;"> | ||
| 141 | <h4><%= link_to title_for_node(node), node_path(node) %></h4> | ||
| 142 | <p><%= link_to_path(node.unique_name, node.unique_name) %></p> | ||
| 143 | </td> | ||
| 144 | <td class="actions"> | ||
| 145 | <%= link_to 'create subpage', new_node_path(:parent_id => node.id) %> | ||
| 146 | <%= link_to 'Revisions', node_revisions_path(node) %> | ||
| 147 | </td> | ||
| 148 | <td> | ||
| 149 | <%= node.lock_owner.login if node.lock_owner %> | ||
| 150 | </td> | ||
| 151 | </tr> | ||
| 152 | <% end %> | 76 | <% end %> |
| 77 | <%= link_to menu_items_path, class: "action_button" do %> | ||
| 78 | <%= icon("menu-2", library: "tabler", "aria-hidden": true) %> Navigation | ||
| 153 | <% end %> | 79 | <% end %> |
| 154 | </table> | 80 | </div> |
| 155 | </div> | 81 | </div> |
diff --git a/test/controllers/admin_controller_test.rb b/test/controllers/admin_controller_test.rb index 9beaf58..00a51e2 100644 --- a/test/controllers/admin_controller_test.rb +++ b/test/controllers/admin_controller_test.rb | |||
| @@ -15,26 +15,6 @@ class AdminControllerTest < ActionController::TestCase | |||
| 15 | assert_includes assigns(:drafts), node | 15 | assert_includes assigns(:drafts), node |
| 16 | end | 16 | end |
| 17 | 17 | ||
| 18 | test "my work list shows each matching node only once, even with several revisions by the same user" do | ||
| 19 | login_as :quentin | ||
| 20 | user = User.find_by_login("quentin") | ||
| 21 | node = Node.root.children.create!(:slug => "dedup_test") | ||
| 22 | node.lock_for_editing!(user) | ||
| 23 | node.autosave!({:title => "v1"}, user) | ||
| 24 | node.save_draft!(user) | ||
| 25 | node.publish_draft! | ||
| 26 | node.lock_for_editing!(user) | ||
| 27 | node.autosave!({:title => "v2"}, user) | ||
| 28 | node.save_draft!(user) | ||
| 29 | node.publish_draft! | ||
| 30 | # three pages now exist on this node, all touched by quentin -- | ||
| 31 | # without DISTINCT, the join would return this node three times | ||
| 32 | |||
| 33 | get :index | ||
| 34 | matches = assigns(:mynodes).select { |n| n.id == node.id } | ||
| 35 | assert_equal 1, matches.length | ||
| 36 | end | ||
| 37 | |||
| 38 | test "dashboard_search returns matching tags and nodes grouped separately" do | 18 | test "dashboard_search returns matching tags and nodes grouped separately" do |
| 39 | node = Node.root.children.create!(:slug => "dashboard_search_test") | 19 | node = Node.root.children.create!(:slug => "dashboard_search_test") |
| 40 | node.find_or_create_draft(User.find_by_login("aaron")) | 20 | node.find_or_create_draft(User.find_by_login("aaron")) |
diff --git a/test/controllers/nodes_controller_test.rb b/test/controllers/nodes_controller_test.rb index b43d2de..81e3f45 100644 --- a/test/controllers/nodes_controller_test.rb +++ b/test/controllers/nodes_controller_test.rb | |||
| @@ -521,6 +521,26 @@ class NodesControllerTest < ActionController::TestCase | |||
| 521 | assert_response :success | 521 | assert_response :success |
| 522 | end | 522 | end |
| 523 | 523 | ||
| 524 | test "mine shows each matching node only once, even with several revisions by the same user" do | ||
| 525 | login_as :quentin | ||
| 526 | user = User.find_by_login("quentin") | ||
| 527 | node = Node.root.children.create!(:slug => "dedup_test") | ||
| 528 | node.lock_for_editing!(user) | ||
| 529 | node.autosave!({:title => "v1"}, user) | ||
| 530 | node.save_draft!(user) | ||
| 531 | node.publish_draft! | ||
| 532 | node.lock_for_editing!(user) | ||
| 533 | node.autosave!({:title => "v2"}, user) | ||
| 534 | node.save_draft!(user) | ||
| 535 | node.publish_draft! | ||
| 536 | # three pages now exist on this node, all touched by quentin -- | ||
| 537 | # without DISTINCT, the join would return this node three times | ||
| 538 | |||
| 539 | get :mine | ||
| 540 | matches = assigns(:nodes).select { |n| n.id == node.id } | ||
| 541 | assert_equal 1, matches.length | ||
| 542 | end | ||
| 543 | |||
| 524 | test "chapters combined with a search term does not raise an ambiguous column error" do | 544 | test "chapters combined with a search term does not raise an ambiguous column error" do |
| 525 | login_as :quentin | 545 | login_as :quentin |
| 526 | get :chapters, params: { :q => "Zombies" } | 546 | get :chapters, params: { :q => "Zombies" } |
diff --git a/test/models/node_test.rb b/test/models/node_test.rb index de540f8..0bce222 100644 --- a/test/models/node_test.rb +++ b/test/models/node_test.rb | |||
| @@ -561,4 +561,28 @@ class NodeTest < ActiveSupport::TestCase | |||
| 561 | result = Node.drafts_and_autosaves(current_user_id: @user1.id).to_a | 561 | result = Node.drafts_and_autosaves(current_user_id: @user1.id).to_a |
| 562 | assert result.index(mine) < result.index(someone_elses_newer) | 562 | assert result.index(mine) < result.index(someone_elses_newer) |
| 563 | end | 563 | end |
| 564 | |||
| 565 | test "recently_changed includes a node whose head was recently published" do | ||
| 566 | node = Node.root.children.create!(:slug => "recent_changed_published") | ||
| 567 | node.find_or_create_draft(@user1) | ||
| 568 | node.autosave!({:title => "v1"}, @user1) | ||
| 569 | node.save_draft!(@user1) | ||
| 570 | node.publish_draft! | ||
| 571 | |||
| 572 | assert_includes Node.recently_changed, node | ||
| 573 | end | ||
| 574 | |||
| 575 | test "recently_changed excludes a node only touched by locking or unlocking after an old publish" do | ||
| 576 | node = Node.root.children.create!(:slug => "recent_changed_lock_only") | ||
| 577 | node.find_or_create_draft(@user1) | ||
| 578 | node.autosave!({:title => "v1"}, @user1) | ||
| 579 | node.save_draft!(@user1) | ||
| 580 | node.publish_draft! | ||
| 581 | node.head.update_column(:updated_at, 20.days.ago) | ||
| 582 | |||
| 583 | node.lock_for_editing!(@user1) | ||
| 584 | node.unlock! | ||
| 585 | |||
| 586 | assert_not_includes Node.recently_changed, node | ||
| 587 | end | ||
| 564 | end | 588 | end |
