diff --git a/app/components/oauth/applications/application_row_component.html.erb b/app/components/oauth/applications/application_row_component.html.erb
new file mode 100644
index 000000000000..5813d4cd4aab
--- /dev/null
+++ b/app/components/oauth/applications/application_row_component.html.erb
@@ -0,0 +1,40 @@
+<%=
+ component_wrapper do
+ flex_layout(align_items: :center, justify_content: :space_between) do |oauth_application_container|
+ oauth_application_container.with_column(flex_layout: true) do |application_information|
+ application_information.with_column(mr: 2) do
+ render(Primer::Beta::Link.new(href: oauth_application_path(@application), font_weight: :bold)) do
+ @application.name
+ end
+ end
+
+ application_information.with_column(mr: 2) do
+ render(Primer::Beta::Text.new(font_size: :small, color: :subtle)) do
+ if @application.builtin?
+ t("oauth.application.builtin")
+ else
+ t(:label_created_by, user: @application.owner)
+ end
+ end
+ end
+
+ unless @application.builtin?
+ application_information.with_column do
+ render(Primer::Beta::Label.new) do
+ @application.confidential? ? t("oauth.application.confidential") : t("oauth.application.non_confidential")
+ end
+ end
+ end
+ end
+
+ # Actions
+ oauth_application_container.with_column do
+ render(Primer::Alpha::ToggleSwitch.new(
+ src: toggle_oauth_application_path(@application),
+ csrf_token: form_authenticity_token,
+ checked: @application.enabled?
+ ))
+ end
+ end
+ end
+%>
diff --git a/app/components/oauth/applications/application_row_component.rb b/app/components/oauth/applications/application_row_component.rb
new file mode 100644
index 000000000000..8ee4387de717
--- /dev/null
+++ b/app/components/oauth/applications/application_row_component.rb
@@ -0,0 +1,43 @@
+#-- 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 OAuth
+ module Applications
+ class ApplicationRowComponent < ApplicationComponent
+ include ApplicationHelper
+ include OpPrimer::ComponentHelpers
+ include OpTurbo::Streamable
+
+ def initialize(application:)
+ @application = application
+
+ super
+ end
+ end
+ end
+end
diff --git a/app/components/oauth/applications/index_component.html.erb b/app/components/oauth/applications/index_component.html.erb
new file mode 100644
index 000000000000..020862cae064
--- /dev/null
+++ b/app/components/oauth/applications/index_component.html.erb
@@ -0,0 +1,49 @@
+<%=
+ component_wrapper do
+ flex_layout do |index_container|
+ index_container.with_row do
+ render(border_box_container(mb: 4)) do |component|
+ component.with_header(font_weight: :bold) do
+ render(Primer::Beta::Text.new) do
+ t("oauth.header.builtin_applications")
+ end
+ end
+
+ if @built_in_applications.empty?
+ component.with_row do
+ render(Primer::Beta::Text.new) do
+ t("oauth.empty_application_lists")
+ end
+ end
+ end
+
+ @built_in_applications.each do |application|
+ component.with_row { render(OAuth::Applications::ApplicationRowComponent.new(application:)) }
+ end
+ end
+ end
+
+ index_container.with_row do
+ render(border_box_container(mb: 4)) do |component|
+ component.with_header(font_weight: :bold) do
+ render(Primer::Beta::Text.new) do
+ t("oauth.header.other_applications")
+ end
+ end
+
+ if @other_applications.empty?
+ component.with_row do
+ render(Primer::Beta::Text.new) do
+ t("oauth.empty_application_lists")
+ end
+ end
+ end
+
+ @other_applications.each do |application|
+ component.with_row { render(OAuth::Applications::ApplicationRowComponent.new(application:)) }
+ end
+ end
+ end
+ end
+ end
+%>
diff --git a/app/components/oauth/applications/index_component.rb b/app/components/oauth/applications/index_component.rb
new file mode 100644
index 000000000000..81027eea51f3
--- /dev/null
+++ b/app/components/oauth/applications/index_component.rb
@@ -0,0 +1,44 @@
+#-- 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 OAuth
+ module Applications
+ class IndexComponent < ApplicationComponent
+ include ApplicationHelper
+ include OpPrimer::ComponentHelpers
+ include OpTurbo::Streamable
+
+ def initialize(oauth_applications:)
+ @built_in_applications = oauth_applications.select(&:builtin?)
+ @other_applications = oauth_applications.reject(&:builtin?)
+
+ super
+ end
+ end
+ end
+end
diff --git a/app/components/oauth/applications/row_component.rb b/app/components/oauth/applications/row_component.rb
deleted file mode 100644
index 2778023eca9f..000000000000
--- a/app/components/oauth/applications/row_component.rb
+++ /dev/null
@@ -1,114 +0,0 @@
-# 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 OAuth
- module Applications
- class RowComponent < ::RowComponent
- property :confidential
-
- def application
- model
- end
-
- def builtin
- checkmark(application.builtin?)
- end
-
- def enabled
- checkmark(application.enabled?)
- end
-
- def name
- if enabled
- link_to application.name, oauth_application_path(application)
- else
- render(Primer::Beta::Text.new(color: :muted)) { application.name }
- end
- end
-
- def owner
- link_to application.owner.name, user_path(application.owner)
- end
-
- def confidential
- if application.confidential?
- helpers.op_icon "icon icon-checkmark"
- end
- end
-
- def redirect_uri
- urls = application.redirect_uri.split("\n")
- safe_join urls, "
".html_safe
- end
-
- def client_credentials
- if user_id = application.client_credentials_user_id
- helpers.link_to_user User.find(user_id)
- else
- "-"
- end
- end
-
- def edit_link
- link_to(
- I18n.t(:button_edit),
- edit_oauth_application_path(application),
- class: "oauth-application--edit-link icon icon-edit"
- )
- end
-
- def button_links
- if application.builtin?
- [toggle_enabled_link]
- else
- [edit_link, helpers.delete_link(oauth_application_path(application))]
- end
- end
-
- def toggle_enabled_link
- if application.enabled?
- link_to(
- I18n.t(:button_deactivate),
- toggle_oauth_application_path(application),
- class: "oauth-application--edit-link icon icon-lock",
- method: :post
- )
- else
- link_to(
- I18n.t(:button_activate),
- toggle_oauth_application_path(application),
- class: "oauth-application--edit-link icon icon-unlock",
- method: :post
- )
- end
- end
- end
- end
-end
diff --git a/app/components/oauth/applications/table_component.rb b/app/components/oauth/applications/table_component.rb
deleted file mode 100644
index 85ef1ef6175a..000000000000
--- a/app/components/oauth/applications/table_component.rb
+++ /dev/null
@@ -1,78 +0,0 @@
-# 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 OAuth
- module Applications
- class TableComponent < ::TableComponent
- class << self
- def row_class
- ::OAuth::Applications::RowComponent
- end
- end
-
- def initial_sort
- %i[id asc]
- end
-
- def sortable?
- false
- end
-
- def columns
- headers.map(&:first)
- end
-
- def inline_create_link
- link_to new_oauth_application_path,
- aria: { label: t("oauth.application.new") },
- class: "wp-inline-create--add-link",
- title: t("oauth.application.new") do
- helpers.op_icon("icon icon-add")
- end
- end
-
- def empty_row_message
- I18n.t :no_results_title_text
- end
-
- def headers
- [
- ["name", { caption: ::Doorkeeper::Application.human_attribute_name(:name) }],
- ["owner", { caption: ::Doorkeeper::Application.human_attribute_name(:owner) }],
- ["builtin", { caption: ::Doorkeeper::Application.human_attribute_name(:builtin) }],
- ["enabled", { caption: ::Doorkeeper::Application.human_attribute_name(:enabled) }],
- ["client_credentials", { caption: I18n.t("oauth.client_credentials") }],
- ["redirect_uri", { caption: ::Doorkeeper::Application.human_attribute_name(:redirect_uri) }],
- ["confidential", { caption: ::Doorkeeper::Application.human_attribute_name(:confidential) }]
- ]
- end
- end
- end
-end
diff --git a/app/components/oauth/show_page_header_component.html.erb b/app/components/oauth/show_page_header_component.html.erb
index d340f870abcb..8bb3d06627e8 100644
--- a/app/components/oauth/show_page_header_component.html.erb
+++ b/app/components/oauth/show_page_header_component.html.erb
@@ -32,31 +32,33 @@ See COPYRIGHT and LICENSE files for more details.
header.with_title { h(@application.name) }
header.with_breadcrumbs(breadcrumb_items)
- header.with_action_button(tag: :a,
- mobile_icon: :pencil,
- mobile_label: t(:button_edit),
- size: :medium,
- href: edit_oauth_application_path(@application),
- aria: { label: I18n.t(:button_edit) },
- title: I18n.t(:button_edit)) do |button|
- button.with_leading_visual_icon(icon: :pencil)
- t(:button_edit)
- end
+ unless @application.builtin?
+ header.with_action_button(tag: :a,
+ mobile_icon: :pencil,
+ mobile_label: t(:button_edit),
+ size: :medium,
+ href: edit_oauth_application_path(@application),
+ aria: { label: I18n.t(:button_edit) },
+ title: I18n.t(:button_edit)) do |button|
+ button.with_leading_visual_icon(icon: :pencil)
+ t(:button_edit)
+ end
- header.with_action_button(tag: :a,
- scheme: :danger,
- mobile_icon: :trash,
- mobile_label: t(:button_delete),
- size: :medium,
- href: oauth_application_path(@application),
- aria: { label: I18n.t(:button_delete) },
- data: {
- confirm: I18n.t(:text_are_you_sure),
- method: :delete
- },
- title: I18n.t(:button_delete)) do |button|
- button.with_leading_visual_icon(icon: :trash)
- t(:button_delete)
+ header.with_action_button(tag: :a,
+ scheme: :danger,
+ mobile_icon: :trash,
+ mobile_label: t(:button_delete),
+ size: :medium,
+ href: oauth_application_path(@application),
+ aria: { label: I18n.t(:button_delete) },
+ data: {
+ confirm: I18n.t(:text_are_you_sure),
+ method: :delete
+ },
+ title: I18n.t(:button_delete)) do |button|
+ button.with_leading_visual_icon(icon: :trash)
+ t(:button_delete)
+ end
end
end
%>
diff --git a/app/contracts/oauth/applications/base_contract.rb b/app/contracts/oauth/applications/base_contract.rb
index 4016cfffb51c..fac8b49b1873 100644
--- a/app/contracts/oauth/applications/base_contract.rb
+++ b/app/contracts/oauth/applications/base_contract.rb
@@ -51,16 +51,14 @@ def self.model
private
def validate_admin_only
- unless user.active_admin?
- errors.add :base, :error_unauthorized
- end
+ errors.add :base, :error_unauthorized unless user.admin?
end
def validate_integration
- if (model.integration_id.nil? && model.integration_type.present?) ||
- (model.integration_id.present? && model.integration_type.nil?)
- errors.add :integration, :invalid
- end
+ both = model.integration_id.present? && model.integration_type.present?
+ none = model.integration_id.nil? && model.integration_type.nil?
+
+ errors.add :integration, :invalid unless both || none
end
def validate_client_credential_user
diff --git a/app/controllers/oauth/applications_controller.rb b/app/controllers/oauth/applications_controller.rb
index 113c86ae3f8c..0d32225d584b 100644
--- a/app/controllers/oauth/applications_controller.rb
+++ b/app/controllers/oauth/applications_controller.rb
@@ -53,13 +53,14 @@ def edit; end
def create
call = ::OAuth::Applications::CreateService.new(user: current_user)
.call(permitted_params.oauth_application)
+ result = call.result
if call.success?
flash[:notice] = t(:notice_successful_create)
- flash[:_application_secret] = call.result.plaintext_secret
- redirect_to action: :show, id: call.result.id
+ flash[:_application_secret] = result.plaintext_secret
+ redirect_to action: :show, id: result.id
else
- @application = call.result
+ @application = result
render action: :new
end
end
diff --git a/app/models/user.rb b/app/models/user.rb
index ef48d89c298d..23e85c02b3bf 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -413,10 +413,6 @@ def wants_comments_in_reverse_order?
pref.comments_in_reverse_order?
end
- def active_admin?
- admin? && active?
- end
-
def self.find_by_rss_key(key)
return nil unless Setting.feeds_enabled?
diff --git a/app/seeders/oauth_applications_seeder.rb b/app/seeders/oauth_applications_seeder.rb
index aee146695513..b8f88606db18 100644
--- a/app/seeders/oauth_applications_seeder.rb
+++ b/app/seeders/oauth_applications_seeder.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2024 the OpenProject GmbH
@@ -26,6 +28,8 @@
# See COPYRIGHT and LICENSE files for more details.
#++
class OAuthApplicationsSeeder < Seeder
+ OPENPROJECT_MOBILE_APP_UID = "DgJZ7Rat23xHZbcq_nxPg5RUuxljonLCN7V7N7GoBAA"
+
def seed_data!
call = create_app
unless call.success?
@@ -37,11 +41,11 @@ def seed_data!
end
def applicable?
- Doorkeeper::Application.where(builtin: true).empty?
+ Doorkeeper::Application.find_by(id: OPENPROJECT_MOBILE_APP_UID).nil?
end
def not_applicable_message
- "No need to seed oauth appplications as they are already present."
+ "No need to seed oauth applications as they are already present."
end
def create_app
@@ -53,7 +57,7 @@ def create_app
redirect_uri: "openprojectapp://oauth-callback",
builtin: true,
confidential: false,
- uid: "DgJZ7Rat23xHZbcq_nxPg5RUuxljonLCN7V7N7GoBAA"
+ uid: OPENPROJECT_MOBILE_APP_UID
)
end
end
diff --git a/app/views/oauth/applications/index.html.erb b/app/views/oauth/applications/index.html.erb
index 3f290aa417bf..c9dc6f66d2ae 100644
--- a/app/views/oauth/applications/index.html.erb
+++ b/app/views/oauth/applications/index.html.erb
@@ -24,8 +24,8 @@ 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.
-
++#%>
+
<% html_title t(:label_administration), t("oauth.application.plural") -%>
<%=
@@ -50,4 +50,4 @@ See COPYRIGHT and LICENSE files for more details.
end
%>
-<%= render ::OAuth::Applications::TableComponent.new(rows: @applications) %>
+<%= render ::OAuth::Applications::IndexComponent.new(oauth_applications: @applications) %>
diff --git a/app/views/oauth/applications/show.html.erb b/app/views/oauth/applications/show.html.erb
index bcd963c864e3..c2f07ed2595d 100644
--- a/app/views/oauth/applications/show.html.erb
+++ b/app/views/oauth/applications/show.html.erb
@@ -31,28 +31,6 @@ See COPYRIGHT and LICENSE files for more details.
<%= render OAuth::ShowPageHeaderComponent.new(application: @application) %>
-<%= toolbar title: "#{t('oauth.application.singular')} - #{h(@application.name)}",
- title_class: 'no-padding-bottom' do %>
- <% unless @application.builtin? %>
-