Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions config/initializers/mime_types.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,4 @@

Mime::Type.register "application/pdf", :pdf unless Mime::Type.lookup_by_extension(:pdf)
Mime::Type.register "image/png", :png unless Mime::Type.lookup_by_extension(:png)
Mime::Type.register "text/fragment+html", :html_fragment
32 changes: 32 additions & 0 deletions frontend/src/app/shared/helpers/dom-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,38 @@

export const getNodeIndex = (element:Element) => Array.from(element.parentNode!.children).indexOf(element);

/**
* Toggles whether an HTMLInputElement or HTMLFieldSetElement is enabled using `disabled` property.
*
* @param element the element to be toggled.
* @param value force enabled (optional): `true` to enable the element/`false` to disable the element.
*/
export function toggleEnabled(element:HTMLElement, value?:boolean) {
if (
element instanceof HTMLInputElement ||
element instanceof HTMLSelectElement ||
element instanceof HTMLTextAreaElement ||
element instanceof HTMLButtonElement ||
element instanceof HTMLFieldSetElement
) {
if (typeof value === 'undefined') {
element.disabled = !element.disabled;
} else {
element.disabled = !value;
}
}

if (element instanceof HTMLFieldSetElement) {
Array.from(element.elements).forEach((child) => {
toggleEnabled(child as HTMLElement, !element.disabled);
});
}
}

export const enableElement = (element:HTMLElement) => toggleEnabled(element, true);

export const disableElement = (element:HTMLElement) => toggleEnabled(element, false);

/**
* Toggles the visibility of an HTMLElement using `hidden` property.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* -- 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.
* ++
*/

import { toggleEnabled } from 'core-app/shared/helpers/dom-helpers';
import { ApplicationController } from 'stimulus-use';

export default class OpDisableWhenValueSelectedController extends ApplicationController {
static targets = ['cause', 'effect'];

declare readonly effectTargets:(HTMLInputElement|HTMLFieldSetElement)[];

private boundListener = this.toggleDisabled.bind(this);

causeTargetConnected(target:HTMLElement) {
target.addEventListener('change', this.boundListener);
}

causeTargetDisconnected(target:HTMLElement) {
target.removeEventListener('change', this.boundListener);
}

private toggleDisabled(evt:InputEvent):void {
const input = evt.target as HTMLInputElement;
const targetName = input.dataset.targetName;

this
.effectTargets
.filter((el) => targetName === el.dataset.targetName)
.forEach((el) => {
const disabled = this.willDisable(el, input.value);
toggleEnabled(el, !disabled);
});
}

private willDisable(el:HTMLElement, value:string):boolean {
if (el.dataset.notValue) {
return el.dataset.notValue === value;
}

return !(el.dataset.value === value);
}
}
2 changes: 2 additions & 0 deletions frontend/src/stimulus/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import { Application } from '@hotwired/stimulus';
import { BeforeunloadController } from './controllers/beforeunload.controller';
import ExternalLinksController from './controllers/external-links.controller';
import DisableWhenClickedController from 'core-stimulus/controllers/disable-when-clicked.controller';
import DisableWhenValueSelectedController from 'core-stimulus/controllers/disable-when-value-selected.controller';
import HighlightTargetElementController from 'core-stimulus/controllers/highlight-target-element.controller';
import SelectAutosizeController from 'core-stimulus/controllers/select-autosize.controller';
import OpZenModeController from 'core-stimulus/controllers/zen-mode.controller';
Expand All @@ -51,6 +52,7 @@ OpenProjectStimulusApplication.preregister('application', OpApplicationControlle
OpenProjectStimulusApplication.preregister('async-dialog', AsyncDialogController);
OpenProjectStimulusApplication.preregister('disable-when-checked', OpDisableWhenCheckedController);
OpenProjectStimulusApplication.preregister('disable-when-clicked', DisableWhenClickedController);
OpenProjectStimulusApplication.preregister('disable-when-value-selected', DisableWhenValueSelectedController);
OpenProjectStimulusApplication.preregister('flash', FlashController);
OpenProjectStimulusApplication.preregister('menus--main', MainMenuController);
OpenProjectStimulusApplication.preregister('require-password-confirmation', RequirePasswordConfirmationController);
Expand Down
4 changes: 4 additions & 0 deletions lib/primer/open_project/forms/dsl/input_methods.rb
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ def select_panel(**, &)
add_input SelectPanelInput.new(builder:, form:, **decorate_options(**), &)
end

def select_tree_panel(**, &)
add_input SelectTreePanelInput.new(builder:, form:, **decorate_options(**), &)
end

def decorate_options(include_help_text: true, help_text_options: {}, **options)
if include_help_text && supports_help_texts?(form.model)
attribute_name = help_text_options[:attribute_name] || options[:name]
Expand Down
66 changes: 66 additions & 0 deletions lib/primer/open_project/forms/dsl/select_tree_panel_input.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# 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 Primer
module OpenProject
module Forms
module Dsl
# :nodoc:
class SelectTreePanelInput < Primer::Forms::Dsl::Input
attr_reader :name, :label, :block

def initialize(name:, label:, **system_arguments, &block)
@name = name
@label = label
@block = block

super(**system_arguments)
end

def to_component
SelectTreePanel.new(input: self)
end

# :nocov:
def type
:select_tree_panel
end
# :nocov:

# :nocov:
def focusable?
true
end
# :nocov:
end
end
end
end
end
6 changes: 6 additions & 0 deletions lib/primer/open_project/forms/select_tree_panel.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<%= render(FormControl.new(input: @input)) do %>
<%= render(Primer::Alpha::SelectPanel.new(**@input.input_arguments)) do |menu| %>
<% menu.with_show_button("aria-describedby": @label_id) { "Select..." } %>
<% @input.block&.call(menu) %>
<% end %>
<% end %>
59 changes: 59 additions & 0 deletions lib/primer/open_project/forms/select_tree_panel.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# 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 Primer
module OpenProject
module Forms
# :nodoc:
class SelectTreePanel < Primer::Forms::BaseComponent
delegate :builder, :form, to: :@input

def initialize(input:)
super()

@input = input
@input.label_arguments[:id] = label_id

@input.input_arguments[:form_arguments] = {
name: @input.name,
builder: builder
}

@input.input_arguments[:select_variant] ||= :single
@input.input_arguments[:dynamic_label] = true unless @input.input_arguments.key(:dynamic_label)
end

def label_id
@label_id ||= "label-#{@input.base_id}"
end
end
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ def index

def show; end

def edit; end

def new
@webhook = webhook_class.new_default
end

def edit; end

def create
service = ::Webhooks::Outgoing::UpdateWebhookService.new(webhook_class.new_default, current_user:)
action = service.call(attributes: permitted_webhooks_params)
Expand Down Expand Up @@ -54,6 +54,13 @@ def destroy
redirect_to action: :index, status: :see_other
end

def enabled_projects_menu
@available_projects = ::Project.pluck(:name, :id)
@webhook = params[:webhook_id].present? ? webhook_class.find(params[:webhook_id]) : webhook_class.new_default

render layout: false
end

private

def find_webhook
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# 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 Webhooks
module Outgoing
class EnabledEventsForm < ApplicationForm
delegate :event_names, to: :model

form do |f|
# Primer, unlike Rails' check_box helper, does not render this auxilary hidden field for us.
f.hidden name: "webhook[events][]", value: "", scope_name_to_model: false

f.check_box_group(
name: :events,
label: I18n.t(:"webhooks.outgoing.form.events.title"),
data: { controller: "checkable" },
id: "enabled_events_fieldset"
) do |group|
available_events.each do |label, value|
group.check_box(
label:,
value:,
checked: event_names.include?(value),
data: { checkable_target: "checkbox" }
)
end
end
end

private

def available_events
OpenProject::Webhooks::EventResources
.available_events_map
.flat_map do |resource_label, events|
events.map do |key, label|

Check notice on line 64 in modules/webhooks/app/forms/webhooks/outgoing/enabled_events_form.rb

View workflow job for this annotation

GitHub Actions / rubocop

[rubocop] modules/webhooks/app/forms/webhooks/outgoing/enabled_events_form.rb#L64 <Layout/IndentationWidth>

Use 2 (not 0) spaces for indentation.
Raw output
modules/webhooks/app/forms/webhooks/outgoing/enabled_events_form.rb:64:11: C: Layout/IndentationWidth: Use 2 (not 0) spaces for indentation.
["#{resource_label}: #{label}", key]
end
end
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<%= render(::OpenProject::Common::CheckAllComponent.new) %>
Loading
Loading