mirror of
https://github.com/opf/openproject.git
synced 2026-06-14 03:30:14 +00:00
[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:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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'."
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user