Skip to content

Commit

Permalink
Merge pull request #17738 from opf/wizard-configuration
Browse files Browse the repository at this point in the history
Refactor the step-by-step storage setup
  • Loading branch information
NobodysNightmare authored Feb 14, 2025
2 parents a727231 + 8fa4078 commit ad91f7e
Show file tree
Hide file tree
Showing 46 changed files with 978 additions and 402 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,22 @@ module Peripherals
register(:set_permissions, StorageInteraction::Nextcloud::SetPermissionsCommand)
end

namespace("components") do
namespace("forms") do
register(:automatically_managed_folders, ::Storages::Admin::Forms::AutomaticallyManagedProjectFoldersFormComponent)
register(:general_information, ::Storages::Admin::Forms::GeneralInfoFormComponent)
register(:oauth_application, ::Storages::Admin::OAuthApplicationInfoCopyComponent)
register(:oauth_client, ::Storages::Admin::Forms::OAuthClientFormComponent)
end

register(:setup_wizard, NextcloudStorageWizard)

register(:automatically_managed_folders, ::Storages::Admin::AutomaticallyManagedProjectFoldersInfoComponent)
register(:general_information, ::Storages::Admin::GeneralInfoComponent)
register(:oauth_application, ::Storages::Admin::OAuthApplicationInfoComponent)
register(:oauth_client, ::Storages::Admin::OAuthClientInfoComponent)
end

namespace("contracts") do
register(:storage, ::Storages::Storages::NextcloudContract)
end
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# 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 Storages
module Peripherals
class NextcloudStorageWizard < Wizard
step :general_information, completed_if: ->(storage) { storage.host.present? && storage.name.present? }

step :oauth_application,
section: :oauth_configuration,
completed_if: ->(storage) { storage.oauth_application.present? },
preparation: :prepare_oauth_application

step :oauth_client,
section: :oauth_configuration,
completed_if: ->(storage) { storage.oauth_client.present? },
preparation: ->(storage) { storage.build_oauth_client }

step :automatically_managed_folders,
completed_if: ->(storage) { !storage.automatic_management_unspecified? },
preparation: :prepare_storage_for_automatic_management_form

private

def prepare_oauth_application(storage)
create_result = ::Storages::OAuthApplications::CreateService.new(storage:, user:).call
storage.oauth_application = create_result.result if create_result.success?
end

def prepare_storage_for_automatic_management_form(storage)
::Storages::Storages::SetProviderFieldsAttributesService
.new(user:, model: storage, contract_class: EmptyContract)
.call
end
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,22 @@ module Peripherals
register(:set_permissions, StorageInteraction::OneDrive::SetPermissionsCommand)
end

namespace("components") do
namespace("forms") do
register(:access_management, ::Storages::Admin::Forms::AccessManagementFormComponent)
register(:general_information, ::Storages::Admin::Forms::GeneralInfoFormComponent)
register(:oauth_client, ::Storages::Admin::Forms::OAuthClientFormComponent)
register(:redirect_uri, ::Storages::Admin::Forms::RedirectUriFormComponent)
end

register(:setup_wizard, OneDriveStorageWizard)

register(:access_management, ::Storages::Admin::AccessManagementComponent)
register(:general_information, ::Storages::Admin::GeneralInfoComponent)
register(:oauth_client, ::Storages::Admin::OAuthClientInfoComponent)
register(:redirect_uri, ::Storages::Admin::RedirectUriComponent)
end

namespace("contracts") do
register(:storage, ::Storages::Storages::OneDriveContract)
end
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# 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 Storages
module Peripherals
class OneDriveStorageWizard < Wizard
step :general_information, completed_if: ->(storage) { storage.name.present? }

step :access_management,
section: :access_management_section,
completed_if: ->(storage) { !storage.automatic_management_unspecified? },
preparation: :prepare_storage_for_access_management_form

step :oauth_client,
section: :oauth_configuration,
completed_if: ->(storage) { storage.oauth_client.present? },
preparation: ->(storage) { storage.build_oauth_client }

step :redirect_uri,
section: :oauth_configuration,
completed_if: ->(storage) {
# Working around the fact that there is nothing changed on the storage after showing
# the redirect url. The redirect URL step only exists to show the oauth client's redirect
# URL to the user right after the client was created.
storage.oauth_client&.persisted? && storage.oauth_client.created_at < 10.seconds.ago
}

private

def prepare_storage_for_access_management_form(storage)
::Storages::Storages::SetProviderFieldsAttributesService
.new(user:, model: storage, contract_class: EmptyContract)
.call
end

def prepare_oauth_application(storage)
persist_service_result = ::Storages::OAuthApplications::CreateService.new(storage:, user:).call
storage.oauth_application = persist_service_result.result if persist_service_result.success?
end

def prepare_storage_for_automatic_management_form(storage)
::Storages::Storages::SetProviderFieldsAttributesService
.new(user:, model: storage, contract_class: EmptyContract)
.call
end
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,7 @@
#++
#
module Storages::Admin
class AccessManagementComponent < ApplicationComponent
include OpPrimer::ComponentHelpers
include OpTurbo::Streamable
include StorageViewInformation

alias_method :storage, :model

class AccessManagementComponent < StorageInfoComponent
def self.wrapper_key = :access_management_section

private
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,7 @@
#++
#
module Storages::Admin
class AutomaticallyManagedProjectFoldersInfoComponent < ApplicationComponent
include OpPrimer::ComponentHelpers
include OpTurbo::Streamable
include StorageViewInformation

alias_method :storage, :model
class AutomaticallyManagedProjectFoldersInfoComponent < StorageInfoComponent

def self.wrapper_key = :automatically_managed_project_folders_section

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
render(Primer::Beta::Text.new(tag: :div, test_selector: 'storage-access-management-form')) do
primer_form_with(
model:,
url: admin_settings_storage_access_management_path(storage),
method: form_method
url: form_url,
method: form_method,
data: { turbo_frame: "page-content" }
) do |form|
flex_layout do |access_management_row|
access_management_row.with_row(mb: 3) do
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,14 @@
#++
#
module Storages::Admin::Forms
class AccessManagementFormComponent < ApplicationComponent
include OpPrimer::ComponentHelpers
include OpTurbo::Streamable

alias_method :storage, :model

class AccessManagementFormComponent < StorageFormComponent
def self.wrapper_key = :access_management_section

def form_url
query = { continue_wizard: storage.id } if in_wizard
admin_settings_storage_access_management_path(storage, query)
end

private

def form_method
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,16 @@
#++
#
module Storages::Admin::Forms
class AutomaticallyManagedProjectFoldersFormComponent < ApplicationComponent
include OpPrimer::ComponentHelpers
include OpTurbo::Streamable

alias_method :storage, :model

class AutomaticallyManagedProjectFoldersFormComponent < StorageFormComponent
def self.wrapper_key = :automatically_managed_project_folders_section

def form_method
options[:form_method] || default_form_method
end

def form_url
options[:form_url] || default_form_url
query = { continue_wizard: storage.id } if in_wizard
admin_settings_storage_automatically_managed_project_folders_path(storage, query)
end

def submit_button_options
Expand Down Expand Up @@ -82,9 +78,5 @@ def default_form_method
def new_record?
storage.automatic_management_new_record?
end

def default_form_url
admin_settings_storage_automatically_managed_project_folders_path(storage)
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
url: form_url,
method: form_method,
data: {
"turbo-frame": "page-content",
controller: "storages--automatically-managed-project-folders-form",
'application-target': "dynamic",
'storages--automatically-managed-project-folders-form-provider-type-value': storage.provider_type,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,21 @@
#++
#
module Storages::Admin::Forms
class GeneralInfoFormComponent < ApplicationComponent
include OpPrimer::ComponentHelpers
include OpTurbo::Streamable

alias_method :storage, :model
class GeneralInfoFormComponent < StorageFormComponent
def self.wrapper_key = :storage_general_info_section

options form_method: :post,
submit_button_disabled: false

def self.wrapper_key = :storage_general_info_section

def form_url
options[:form_url] || default_form_url
query = { continue_wizard: storage.id } if in_wizard

case form_method
when :get, :post
admin_settings_storages_path(query)
when :patch, :put
admin_settings_storage_path(storage, query)
end
end

def submit_button_options
Expand All @@ -60,15 +62,6 @@ def cancel_button_options

private

def default_form_url
case form_method
when :get, :post
admin_settings_storages_path
when :patch, :put
admin_settings_storage_path(storage)
end
end

def cancel_button_path
options.fetch(:cancel_button_path) do
if storage.persisted?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
render(Primer::Beta::Text.new(tag: :div, test_selector: 'storage-oauth-client-form')) do
primer_form_with(
model: oauth_client,
url: admin_settings_storage_oauth_client_path(storage),
method: form_method
url: form_url,
method: form_method,
data: data_attributes
) do |form|
flex_layout do |oauth_client_row|
oauth_client_row.with_row(mb: 3) do
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,14 @@
#++
#
module Storages::Admin::Forms
class OAuthClientFormComponent < ApplicationComponent
include OpPrimer::ComponentHelpers
include OpTurbo::Streamable

attr_reader :storage
alias_method :oauth_client, :model
class OAuthClientFormComponent < StorageFormComponent
def self.wrapper_key = :storage_oauth_client_section

def initialize(oauth_client:, storage:, **)
super(oauth_client, **)
@storage = storage
def form_url
query = { continue_wizard: storage.id } if in_wizard
admin_settings_storage_oauth_client_path(storage, query)
end

def self.wrapper_key = :storage_oauth_client_section

def form_method
options[:form_method] || default_form_method
end
Expand All @@ -58,6 +52,10 @@ def storage_provider_credentials_instructions

private

def oauth_client
options[:oauth_client] || storage.oauth_client
end

def one_drive_integration_link(target: "_blank")
href = ::OpenProject::Static::Links[:storage_docs][:one_drive_oauth_application][:href]
render(Primer::Beta::Link.new(href:, target:)) { I18n.t("storages.instructions.one_drive.application_link_text") }
Expand All @@ -75,5 +73,9 @@ def first_time_configuration?
def default_form_method
first_time_configuration? ? :post : :patch
end

def data_attributes
{ turbo_frame: "page-content" }
end
end
end
Loading

0 comments on commit ad91f7e

Please sign in to comment.