[57812] Added model and migration for custom field of type hierarchy (#16805)

* Added model and migration for custom field of type hierarchy
* Added feature flag for custom field of type hierarchy
* moved feature flag to drop down options

---------

Co-authored-by: Eric Schubert <e.schubert@openproject.com>
This commit is contained in:
Andreas Pfohl
2024-09-26 14:42:13 +02:00
committed by GitHub
parent c787d5995e
commit 4e80bd3064
9 changed files with 145 additions and 8 deletions
+5
View File
@@ -194,10 +194,15 @@ module CustomFieldsHelper
# Return an array of custom field formats which can be used in select_tag
def custom_field_formats_for_select(custom_field)
hierarchy_if_deactivated = lambda do |format|
format.name == "hierarchy" && !OpenProject::FeatureDecisions.custom_field_of_type_hierarchy_active?
end
OpenProject::CustomFieldFormat
.all_for_field(custom_field)
.sort_by(&:order)
.reject { |format| format.label.nil? }
.reject(&hierarchy_if_deactivated)
.map do |custom_field_format|
[label_for_custom_field_format(custom_field_format.name), custom_field_format.name]
end
+5
View File
@@ -41,6 +41,11 @@ class CustomField < ApplicationRecord
inverse_of: "custom_field"
accepts_nested_attributes_for :custom_options
has_one :hierarchy_root,
class_name: "CustomField::Hierarchy::Item",
dependent: :delete, # todo: cascade into children with service
inverse_of: "custom_field"
acts_as_list scope: [:type]
validates :field_format, presence: true
+36
View File
@@ -0,0 +1,36 @@
# frozen_string_literal: true
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++
class CustomField::Hierarchy::Item < ApplicationRecord
self.table_name = "hierarchical_items"
belongs_to :custom_field
has_closure_tree order: "sort_order", numeric_order: true
end
@@ -0,0 +1,52 @@
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++
class CustomValue::HierarchyStrategy < CustomValue::ARObjectStrategy
def validate_type_of_value
raise NotImplementedError
end
def typed_value
raise NotImplementedError
end
private
def ar_class
CustomField::Hierarchy::Item
end
def ar_object(value)
option = CustomField::Hierarchy::Item.find_by(id: value.to_s)
if option.nil?
"#{value} #{I18n.t(:label_not_found)}"
else
option.value
end
end
end
+7 -4
View File
@@ -61,15 +61,13 @@ OpenProject::CustomFieldFormat.map do |fields|
formatter: "CustomValue::BoolStrategy")
fields.register OpenProject::CustomFieldFormat.new("user",
label: Proc.new { User.model_name.human },
only: %w(WorkPackage TimeEntry
Version Project),
only: %w(WorkPackage TimeEntry Version Project),
edit_as: "list",
order: 9,
formatter: "CustomValue::UserStrategy")
fields.register OpenProject::CustomFieldFormat.new("version",
label: Proc.new { Version.model_name.human },
only: %w(WorkPackage TimeEntry
Version Project),
only: %w(WorkPackage TimeEntry Version Project),
edit_as: "list",
order: 10,
formatter: "CustomValue::VersionStrategy")
@@ -79,4 +77,9 @@ OpenProject::CustomFieldFormat.map do |fields|
label: nil,
order: 11,
formatter: "CustomValue::EmptyStrategy")
fields.register OpenProject::CustomFieldFormat.new("hierarchy",
label: :label_hierarchy,
order: 12,
formatter: "CustomValue::HierarchyStrategy")
end
+3
View File
@@ -40,3 +40,6 @@ require_relative "../../lib_static/open_project/feature_decisions"
# end
OpenProject::FeatureDecisions.add :built_in_oauth_applications,
description: "Allows the display and use of built-in OAuth applications."
OpenProject::FeatureDecisions.add :custom_field_of_type_hierarchy,
description: "Allows the use of the custom field type 'Hierarchy'."
+1
View File
@@ -2268,6 +2268,7 @@ en:
label_here: here
label_hide: "Hide"
label_history: "History"
label_hierarchy: "Hierarchy"
label_hierarchy_leaf: "Hierarchy leaf"
label_home: "Home"
label_subject_or_id: "Subject or ID"
@@ -0,0 +1,29 @@
class CreateHierarchicalItems < ActiveRecord::Migration[7.1]
def change
create_table :hierarchical_items do |t|
t.integer :parent_id
t.integer :sort_order
t.string :label
t.string :short
t.boolean :is_deleted, default: false, null: false
t.timestamps
end
add_reference "hierarchical_items", :custom_field, foreign_key: true
# auto-generated by closure_tree
create_table :hierarchical_item_hierarchies, id: false do |t|
t.integer :ancestor_id, null: false
t.integer :descendant_id, null: false
t.integer :generations, null: false
end
add_index :hierarchical_item_hierarchies, %i[ancestor_id descendant_id generations],
unique: true,
name: "item_anc_desc_idx"
add_index :hierarchical_item_hierarchies, [:descendant_id],
name: "item_desc_idx"
end
end
@@ -41,21 +41,24 @@ module API
"bool" => "Boolean",
"user" => "User",
"version" => "Version",
"list" => "CustomOption"
"list" => "CustomOption",
"hierarchy" => "CustomField::Hierarchy::Item"
}.freeze
LINK_FORMATS = %w(list user version).freeze
LINK_FORMATS = %w(list user version hierarchy).freeze
NAMESPACE_MAP = {
"user" => ["users", "groups", "placeholder_users"],
"version" => "versions",
"list" => "custom_options"
"list" => "custom_options",
"hierarchy" => "hierarchical_items"
}.freeze
REPRESENTER_MAP = {
"user" => "::API::V3::Principals::PrincipalRepresenterFactory",
"version" => "::API::V3::Versions::VersionRepresenter",
"list" => "::API::V3::CustomOptions::CustomOptionRepresenter"
"list" => "::API::V3::CustomOptions::CustomOptionRepresenter",
"hierarchy" => "::API::V3::HierarchyItems::HierarchyItemRepresenter"
}.freeze
class << self