Create a update handler registry to be able to update different models from the inplaceEditField component

This commit is contained in:
Henriette Darge
2026-01-21 11:01:01 +01:00
parent bd88659079
commit 13664c2fe8
9 changed files with 268 additions and 19 deletions
@@ -13,12 +13,19 @@
<!-- end-->
<!-- end--> %>
<div id="<%= target_id %>">
<%= primer_form_with(model:, url: polymorphic_path(model), method: :patch, data: { turbo_stream: true }) do |form|
<%= component_wrapper(tag: :div) do %>
<%= primer_form_with(
model:,
url: inplace_edit_field_update_path(model: model.class.name, id: model.id, attribute:),
method: :patch,
data: { turbo_stream: true }
) do |form|
render_field_component = ->(f) { render field_component(f) } # The render_inline_form method looses context and thus does not know about the `field_component` method
system_arguments = @system_arguments
render_inline_form(form) do |f|
f.hidden name: "system_arguments_json", value: system_arguments.to_json
render_field_component.call(f)
end
end %>
</div>
<% end %>
@@ -31,6 +31,8 @@
module OpenProject
module Common
class InplaceEditFieldComponent < ViewComponent::Base
include OpTurbo::Streamable
attr_reader :model, :attribute
def initialize(model:, attribute:, **system_arguments)
@@ -41,13 +43,9 @@ module OpenProject
end
def field_component(form)
klass = OpenProject::InplaceFieldRegistry.fetch(attribute)
klass = OpenProject::InplaceEdit::FieldRegistry.fetch(attribute)
klass.new(form:, attribute:, model:, **@system_arguments)
end
def target_id
"#{model.model_name.singular}_#{model.id}_#{attribute}"
end
end
end
end
@@ -0,0 +1,98 @@
# 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 InplaceEditFieldsController < ApplicationController
include OpTurbo::ComponentStream
before_action :find_model
before_action :set_attribute
no_authorization_required! :update
def update
handler = OpenProject::InplaceEdit::UpdateRegistry.fetch(@model)
success = handler.call(
model: @model,
attribute: @attribute,
params: permitted_params,
user: current_user
)
if success
render_success_flash_message_via_turbo_stream(
message: I18n.t(:notice_successful_update)
)
end
replace_via_turbo_stream(
component:,
status: success ? :ok : :unprocessable_entity
)
respond_with_turbo_streams
end
private
def find_model
@model =
params[:model]
.constantize
.find(params[:id])
rescue NameError, ActiveRecord::RecordNotFound
head :not_found
end
def set_attribute
@attribute = params[:attribute].to_sym
end
def permitted_params
params
.expect(@model.model_name.param_key => [@attribute])
end
def component
OpenProject::Common::InplaceEditFieldComponent.new(
model: @model,
attribute: @attribute,
**system_arguments.to_h.symbolize_keys
)
end
def system_arguments
arguments = params.to_unsafe_h
.values
.filter_map { |v| v["system_arguments_json"] }
.first
JSON.parse(arguments)
end
end
+8 -2
View File
@@ -29,6 +29,12 @@
#++
Rails.application.config.to_prepare do
require_relative "../../lib/open_project/inplace_edit/registry"
OpenProject::InplaceFieldRegistry.register(:description, OpenProject::Common::InplaceEditFields::TextInputComponent)
# Register the edit fields per attribute
require_relative "../../lib/open_project/inplace_edit/field_registry"
OpenProject::InplaceEdit::FieldRegistry.register(:description, OpenProject::Common::InplaceEditFields::TextInputComponent)
# Register the update handler per model
require_relative "../../lib/open_project/inplace_edit/handlers/default_update"
require_relative "../../lib/open_project/inplace_edit/handlers/project_update"
OpenProject::InplaceEdit::UpdateRegistry.register(Project, OpenProject::InplaceEdit::Handlers::ProjectUpdate)
end
+5
View File
@@ -1056,6 +1056,11 @@ Rails.application.routes.draw do
delete "Groups/:id", to: "groups#destroy"
end
scope "inplace_edit_fields/:model/:id/:attribute", as: "inplace_edit_field" do
post :update, controller: "inplace_edit_fields", action: :update
patch :update, controller: "inplace_edit_fields", action: :update
end
if OpenProject::Configuration.lookbook_enabled?
mount Primer::ViewComponents::Engine, at: "/"
mount Lookbook::Engine, at: "/lookbook"
@@ -0,0 +1,47 @@
# 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.
#++
module OpenProject
module InplaceEdit
class FieldRegistry
@registry = {}
class << self
def register(attribute_name, field_component)
@registry[attribute_name.to_s] = field_component
end
def fetch(attribute_name)
@registry.fetch(attribute_name.to_s) { Common::InplaceEditFields::TextInputComponent }
end
end
end
end
end
@@ -0,0 +1,41 @@
# 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.
#++
module OpenProject
module InplaceEdit
module Handlers
class DefaultUpdate
def self.call(model:, attribute:, params:, user:)
model.update!(params.slice(attribute))
end
end
end
end
end
@@ -29,16 +29,16 @@
#++
module OpenProject
class InplaceFieldRegistry
@registry = {}
module InplaceEdit
module Handlers
class ProjectUpdate
def self.call(model:, attribute:, params:, user:)
call = ::Projects::UpdateService
.new(model:, user:)
.call(params)
class << self
def register(attribute_name, field_component)
@registry[attribute_name.to_s] = field_component
end
def fetch(attribute_name)
@registry.fetch(attribute_name.to_s) { Common::InplaceEditFields::TextInputComponent }
call.success?
end
end
end
end
@@ -0,0 +1,47 @@
# 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.
#++
module OpenProject
module InplaceEdit
class UpdateRegistry
@registry = {}
class << self
def register(model_class, handler)
@registry[model_class.name] = handler
end
def fetch(model)
@registry.fetch(model.class.name, OpenProject::InplaceEdit::Handlers::DefaultUpdate)
end
end
end
end
end