mirror of
https://github.com/opf/openproject.git
synced 2026-06-14 03:30:14 +00:00
Rename semanticId to displayId, make always present
Replace the conditional `semanticId` API field with `displayId` which is always present in work package responses. In semantic mode it returns the project-based identifier (e.g. "PROJ-42"), in classic mode it returns the numeric ID as a string. This gives API consumers (frontend, mobile) a single field to read without conditional logic. - Add `WorkPackage#display_id` method that encapsulates the mode check - Update both representers (JSON and SQL) to render `displayId` unconditionally - Update OpenAPI schema documentation
This commit is contained in:
@@ -76,6 +76,13 @@ module WorkPackage::SemanticIdentifier
|
||||
end
|
||||
end
|
||||
|
||||
# Returns the user-facing identifier for this work package.
|
||||
# In semantic mode: the project-based identifier (e.g. "PROJ-42")
|
||||
# In classic mode: the numeric database ID
|
||||
def display_id
|
||||
Setting::WorkPackageIdentifier.semantic_mode_active? ? identifier : id
|
||||
end
|
||||
|
||||
# Allocates the next semantic identifier in the current project and assigns it to the WP.
|
||||
# Also writes alias rows for every identifier the project has ever used (including "ghost" aliases).
|
||||
#
|
||||
|
||||
@@ -12,11 +12,12 @@ allOf:
|
||||
description: Work package id
|
||||
readOnly: true
|
||||
minimum: 1
|
||||
semanticId:
|
||||
displayId:
|
||||
type: string
|
||||
description: |-
|
||||
The project-based semantic identifier for the work package (e.g. PROJ-42).
|
||||
Only present when semantic mode is enabled.
|
||||
The user-facing identifier for the work package.
|
||||
In semantic mode: the project-based identifier (e.g. "PROJ-42").
|
||||
In classic mode: the numeric ID as a string (e.g. "123").
|
||||
readOnly: true
|
||||
lockVersion:
|
||||
type: integer
|
||||
|
||||
@@ -345,11 +345,10 @@ module API
|
||||
property :id,
|
||||
render_nil: true
|
||||
|
||||
property :semantic_id,
|
||||
as: :semanticId,
|
||||
property :display_id,
|
||||
as: :displayId,
|
||||
render_nil: true,
|
||||
getter: ->(*) { identifier },
|
||||
if: ->(*) { Setting::WorkPackageIdentifier.semantic_mode_active? }
|
||||
getter: ->(*) { display_id&.to_s }
|
||||
|
||||
property :lock_version,
|
||||
render_nil: true,
|
||||
|
||||
@@ -76,9 +76,10 @@ module API
|
||||
|
||||
property :id
|
||||
|
||||
property :semanticId,
|
||||
representation: ->(*) { "identifier" },
|
||||
render_if: ->(*) { Setting::WorkPackageIdentifier.semantic_mode_active? ? "TRUE" : "FALSE" }
|
||||
property :displayId,
|
||||
representation: ->(*) {
|
||||
Setting::WorkPackageIdentifier.semantic_mode_active? ? "identifier" : "id::text"
|
||||
}
|
||||
|
||||
property :subject
|
||||
|
||||
|
||||
@@ -160,16 +160,15 @@ RSpec.describe API::V3::WorkPackages::WorkPackageRepresenter do
|
||||
let(:value) { work_package.id }
|
||||
end
|
||||
|
||||
describe "semanticId" do
|
||||
describe "displayId" do
|
||||
context "when semantic work package ids are active",
|
||||
with_flag: { semantic_work_package_ids: true },
|
||||
with_settings: { work_packages_identifier: "semantic" } do
|
||||
it { is_expected.to be_json_eql(work_package.identifier.to_json).at_path("semanticId") }
|
||||
it { is_expected.to be_json_eql(work_package.identifier.to_json).at_path("displayId") }
|
||||
end
|
||||
|
||||
context "when semantic_work_package_ids feature flag is inactive",
|
||||
with_flag: { semantic_work_package_ids: false } do
|
||||
it { is_expected.not_to have_json_path("semanticId") }
|
||||
context "when semantic work package ids are not active" do
|
||||
it { is_expected.to be_json_eql(work_package.id.to_s.to_json).at_path("displayId") }
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -72,6 +72,7 @@ RSpec.describe API::V3::WorkPackages::WorkPackageSqlRepresenter, "rendering" do
|
||||
{
|
||||
_type: "WorkPackage",
|
||||
id: rendered_work_package.id,
|
||||
displayId: rendered_work_package.id.to_s,
|
||||
subject: rendered_work_package.subject,
|
||||
dueDate: rendered_work_package.due_date,
|
||||
startDate: rendered_work_package.start_date,
|
||||
@@ -118,6 +119,7 @@ RSpec.describe API::V3::WorkPackages::WorkPackageSqlRepresenter, "rendering" do
|
||||
{
|
||||
_type: "WorkPackage",
|
||||
id: rendered_work_package.id,
|
||||
displayId: rendered_work_package.id.to_s,
|
||||
subject: rendered_work_package.subject,
|
||||
date: rendered_work_package.start_date,
|
||||
_links: {
|
||||
@@ -156,20 +158,21 @@ RSpec.describe API::V3::WorkPackages::WorkPackageSqlRepresenter, "rendering" do
|
||||
end
|
||||
end
|
||||
|
||||
context "when semantic work package ids are active",
|
||||
with_flag: { semantic_work_package_ids: true },
|
||||
with_settings: { work_packages_identifier: "semantic" } do
|
||||
let(:project) { create(:project, identifier: "PROJ", types: [type]) }
|
||||
describe "displayId" do
|
||||
context "when semantic work package ids are active",
|
||||
with_flag: { semantic_work_package_ids: true },
|
||||
with_settings: { work_packages_identifier: "semantic" } do
|
||||
let(:project) { create(:project, identifier: "PROJ", types: [type]) }
|
||||
|
||||
it "includes semanticId" do
|
||||
expect(json).to be_json_eql("PROJ-1".to_json).at_path("semanticId")
|
||||
it "returns the semantic identifier" do
|
||||
expect(json).to be_json_eql("PROJ-1".to_json).at_path("displayId")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "when semantic_work_package_ids feature flag is inactive",
|
||||
with_flag: { semantic_work_package_ids: false } do
|
||||
it "does not include semanticId" do
|
||||
expect(json).not_to have_json_path("semanticId")
|
||||
context "when semantic work package ids are not active" do
|
||||
it "returns the numeric id as a string" do
|
||||
expect(json).to be_json_eql(rendered_work_package.id.to_s.to_json).at_path("displayId")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -136,6 +136,23 @@ RSpec.describe WorkPackage::SemanticIdentifier do
|
||||
end
|
||||
end
|
||||
|
||||
describe "#display_id" do
|
||||
context "when semantic mode is active",
|
||||
with_flag: { semantic_work_package_ids: true },
|
||||
with_settings: { work_packages_identifier: "semantic" } do
|
||||
it "returns the semantic identifier" do
|
||||
expect(work_package.display_id).to eq("MYPROJ-1")
|
||||
end
|
||||
end
|
||||
|
||||
context "when semantic mode is not active",
|
||||
with_flag: { semantic_work_package_ids: false } do
|
||||
it "returns the numeric id" do
|
||||
expect(work_package.display_id).to eq(work_package.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#allocate_and_register_semantic_id" do
|
||||
let(:project) { create(:project, identifier: "PROJ", wp_sequence_counter: 0) }
|
||||
let(:target_project) { create(:project, identifier: "OTHER", wp_sequence_counter: 0) }
|
||||
|
||||
Reference in New Issue
Block a user