From a1794d3087e6cbd228f3641e7313815d8c59695f Mon Sep 17 00:00:00 2001 From: erdgeist Date: Thu, 20 Aug 2026 17:37:01 +0200 Subject: Surface redirects in nodes#show, the action log and when publishing --- app/helpers/admin_helper.rb | 8 ++++++++ app/models/node.rb | 2 +- app/models/node_action.rb | 6 ++++++ app/models/page.rb | 17 +++++++++++++---- app/views/nodes/edit.html.erb | 3 +-- app/views/nodes/show.html.erb | 37 +++++++++++++++++++++++++++++++++++++ app/views/revisions/diff.html.erb | 19 ++++++++++++++++++- config/locales/de.yml | 11 +++++++++++ config/locales/en.yml | 13 ++++++++++++- 9 files changed, 107 insertions(+), 9 deletions(-) diff --git a/app/helpers/admin_helper.rb b/app/helpers/admin_helper.rb index be20eb8b..b696c21c 100644 --- a/app/helpers/admin_helper.rb +++ b/app/helpers/admin_helper.rb @@ -38,4 +38,12 @@ module AdminHelper } }.to_json end + + def redirect_flag_hint page + target = page.redirect_target + return t("nodes.show.redirect_flag_broken") unless target + + target.internal? ? t("nodes.show.redirect_flag", :path => target.node.unique_name) + : t("nodes.show.redirect_flag_url", :url => target.url) + end end diff --git a/app/models/node.rb b/app/models/node.rb index 52e06d2d..ef981a97 100644 --- a/app/models/node.rb +++ b/app/models/node.rb @@ -243,7 +243,7 @@ class Node < ApplicationRecord end if self.draft.redirect_node_id.present? - target = Node.find_by(:id => self.draft.redirect_node_id) + target = self.draft.redirect_node unless target errors.add(:base, :redirect_target_missing) diff --git a/app/models/node_action.rb b/app/models/node_action.rb index aab1d238..a7036833 100644 --- a/app/models/node_action.rb +++ b/app/models/node_action.rb @@ -200,6 +200,12 @@ class NodeAction < ApplicationRecord old_url, new_url = old_page.external_url, new_page.external_url diff[:external_url] = { "from" => old_url, "to" => new_url } if old_url != new_url + old_redirect, new_redirect = old_page.redirect, new_page.redirect + diff[:redirect] = { "from" => old_redirect, "to" => new_redirect } if old_redirect != new_redirect + + old_target, new_target = old_page.redirect_node&.unique_name, new_page.redirect_node&.unique_name + diff[:redirect_target] = { "from" => old_target, "to" => new_target } if old_target != new_target + old_tags, new_tags = old_page.tag_list.sort, new_page.tag_list.sort diff[:tags] = { "from" => old_tags, "to" => new_tags } if old_tags != new_tags diff --git a/app/models/page.rb b/app/models/page.rb index 5d3cb0aa..91b7e975 100644 --- a/app/models/page.rb +++ b/app/models/page.rb @@ -36,6 +36,7 @@ class Page < ApplicationRecord belongs_to :parent_node, :class_name => "Node", :optional => true belongs_to :user, optional: true belongs_to :editor, :class_name => "User", optional: true + belongs_to :redirect_node, :class_name => "Node", :optional => true has_many :related_assets, :dependent => :destroy has_many :assets, -> { order("position ASC") }, :through => :related_assets @@ -289,7 +290,11 @@ class Page < ApplicationRecord changed: user_id != other.user_id }, tags: { added: tag_list.to_a - other.tag_list.to_a, removed: other.tag_list.to_a - tag_list.to_a }, template_name: { from: other.template_name, to: template_name, changed: template_name != other.template_name }, - assets: { added: assets.to_a - other.assets.to_a, removed: other.assets.to_a - assets.to_a } + assets: { added: assets.to_a - other.assets.to_a, removed: other.assets.to_a - assets.to_a }, + redirect: { from: other.redirect, to: redirect, + changed: redirect != other.redirect }, + redirect_node: { from: other.redirect_node, to: redirect_node, + changed: redirect_node_id != other.redirect_node_id } ) end @@ -326,9 +331,8 @@ class Page < ApplicationRecord return nil if redirect.blank? if redirect_node_id.present? - target = Node.find_by(:id => redirect_node_id) - return nil unless target&.head - return RedirectTarget.new(target, nil) + return nil unless redirect_node&.head + return RedirectTarget.new(redirect_node, nil) end return RedirectTarget.new(nil, external_url) if external_url.present? @@ -345,6 +349,11 @@ class Page < ApplicationRecord Node.where(:head_id => where(:redirect_node_id => node_id).select(:id)) end + def redirect_differs_from? other + mine, theirs = redirect_target, other&.redirect_target + mine&.url != theirs&.url || mine&.node != theirs&.node + end + # The address this page will have once published. def prospective_unique_name return nil if parent_node_id.nil? diff --git a/app/views/nodes/edit.html.erb b/app/views/nodes/edit.html.erb index f629985e..a40f3949 100644 --- a/app/views/nodes/edit.html.erb +++ b/app/views/nodes/edit.html.erb @@ -154,8 +154,7 @@
">
<%= icon("search", library: "tabler", "aria-hidden": true) %> - <%= text_field_tag :redirect_search_term, - Node.find_by(:id => @page.redirect_node_id)&.title, + <%= text_field_tag :redirect_search_term, @page.redirect_node&.title, :placeholder => "—", :class => "clearable_input" %>
diff --git a/app/views/nodes/show.html.erb b/app/views/nodes/show.html.erb index 24ac4084..d8c08eb1 100644 --- a/app/views/nodes/show.html.erb +++ b/app/views/nodes/show.html.erb @@ -9,14 +9,35 @@
<%= t(".head") %> + <% if @node.head&.redirect.present? %> + + <%= flag("arrow-ramp-right", + redirect_flag_hint(@node.head), + :tier => :attention) %> + + <% end %> <%= @node.head ? t(".head_line", :title => @node.head.title, :rev => @node.head.revision, :time => @node.head.updated_at) : t(".never_published") %>
<%= t(".draft") %> + <% if @node.draft&.redirect.present? %> + + <%= flag("arrow-ramp-right", + redirect_flag_hint(@node.draft), + :tier => :attention) %> + + <% end %> <%= @node.draft ? t(".draft_line", :title => @node.draft.title, :rev => @node.draft.revision, :time => @node.draft.updated_at) : t(".none") %>
<%= t(".autosave") %> + <% if @node.autosave&.redirect.present? %> + + <%= flag("arrow-ramp-right", + redirect_flag_hint(@node.autosave), + :tier => :attention) %> + + <% end %> <%= @node.autosave ? t(".autosave_line", :title => @node.autosave.title, :time => @node.autosave.updated_at) : t(".none") %>
@@ -56,6 +77,11 @@ <% confirm += " " + t(".confirm_publish_moves", :path => @node.prospective_unique_name) %> <% end %> + <% if @node.draft.redirect.present? && @node.head&.redirect.blank? %> + <% confirm += " " + t(".confirm_publish_redirects") %> + <% elsif @node.draft.redirect.present? && @node.draft.redirect_differs_from?(@node.head) %> + <% confirm += " " + t(".confirm_publish_redirect_changes") %> + <% end %> <%= button_to t(".publish"), publish_node_path(@node), method: :put, form: { data: { confirm: confirm }, class: 'button_to state_changing' } %> <% else %> @@ -246,6 +272,17 @@

<% end %> + <% if (redirect = @node.head&.redirect_target) %> +

+ <%= icon("arrow-right", library: "tabler", "aria-hidden": true) %> + <% if redirect.internal? %> + <%= t(".redirects_to", :path => redirect.node.unique_name) %> + <% else %> + <%= t(".redirects_to_url", :url => redirect.url) %> + <% end %> +

+ <% end %> +