From 58a5e19669f9a51bcf0cbc095c027d055c1661e1 Mon Sep 17 00:00:00 2001 From: Kabiru Mwenja Date: Thu, 28 May 2026 12:05:24 +0300 Subject: [PATCH] bug/74156 Sort WP lists by project identifier, not project_id, in semantic mode (#23400) Sort WP lists by project identifier, not project_id, in semantic mode The semantic-mode "ID" sort grouped projects by project_id (insertion order) before the per-project sequence. Projects added after others landed below them in the list even when their identifier sorted alphabetically earlier. Sort by projects.identifier instead so the order matches the visible "-" column. The projects table is already joined for every work-package list query, so the new sort term costs no extra round-trip. --- .../work_packages/selects/property_select.rb | 8 +------ spec/models/query/results_sort_by_id_spec.rb | 24 +++++++++++++++++++ 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/app/models/queries/work_packages/selects/property_select.rb b/app/models/queries/work_packages/selects/property_select.rb index f2b40c6d76c..7802bf7ad59 100644 --- a/app/models/queries/work_packages/selects/property_select.rb +++ b/app/models/queries/work_packages/selects/property_select.rb @@ -37,15 +37,9 @@ class Queries::WorkPackages::Selects::PropertySelect < Queries::WorkPackages::Se self.property_selects = { id: { - # Sorting by "ID" follows the displayed identifier. In semantic mode, the - # visible ID is `-`, so the database - # primary key is the wrong sort key — a work package moved between projects - # keeps its PK but receives a new sequence in the target project. Order by - # (project_id, sequence_number) keeps each project's rows monotone in their - # visible numbering and is backed by an existing partial unique index. sortable: -> { if Setting::WorkPackageIdentifier.semantic? - ["#{WorkPackage.table_name}.project_id", "#{WorkPackage.table_name}.sequence_number"] + ["#{Project.table_name}.identifier", "#{WorkPackage.table_name}.sequence_number"] else "#{WorkPackage.table_name}.id" end diff --git a/spec/models/query/results_sort_by_id_spec.rb b/spec/models/query/results_sort_by_id_spec.rb index 2bf09803a06..f0babefc78b 100644 --- a/spec/models/query/results_sort_by_id_spec.rb +++ b/spec/models/query/results_sort_by_id_spec.rb @@ -106,6 +106,30 @@ RSpec.describe Query::Results, "sort by id" do end end + context "with rows from two projects whose identifiers invert the creation order" do + let(:np_project) { create(:project, identifier: "ABC") } + let!(:np_wp) do + wp = create(:work_package, project: np_project, subject: "First in ABC", skip_semantic_id_allocation: true) + wp.update_columns(sequence_number: 1, identifier: "ABC-1") + wp + end + + let(:query) do + build_stubbed(:query, + user:, + project: nil, + show_hierarchies: false, + sort_criteria: [%w[id asc]], + column_names: %i[id subject]) + end + + it "orders rows by the project identifier prefix, not by project_id" do + identifiers = described_class.new(query).work_packages.pluck(:identifier) + + expect(identifiers).to eq(%w[ABC-1 LARGE-1 LARGE-2 LARGE-3]) + end + end + context "with a non-ID primary sort and a tie" do before do WorkPackage.where(id: wps.map(&:id)).update_all(subject: "Same subject")