Skip to content

Commit

Permalink
Add Create Global Meetings Page
Browse files Browse the repository at this point in the history
  • Loading branch information
aaron-contreras committed Jun 16, 2023
1 parent 0098a49 commit 9a1d4a1
Show file tree
Hide file tree
Showing 15 changed files with 350 additions and 56 deletions.
4 changes: 4 additions & 0 deletions frontend/src/global_styles/content/_forms.sass
Original file line number Diff line number Diff line change
Expand Up @@ -629,6 +629,10 @@ input[readonly].-clickable
line-height: normal
padding: 3px 24px 3px 3px

&.-prompt-visible
font-style: italic
color: $spot-color-basic-gray-3

&[multiple]
background-image: none
padding-right: $form-padding
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* -- copyright
* OpenProject is an open source project management software.
* Copyright (C) 2023 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 { Controller } from '@hotwired/stimulus';

export default class SelectFieldWithPromptController extends Controller<HTMLSelectElement> {
connect() {
this.togglePromptStyling();
}

togglePromptStyling() {
if (this.promptSelected()) {
this.element.classList.add('-prompt-visible');
} else {
this.element.classList.remove('-prompt-visible');
}
}

private promptSelected() {
const options = Array.from(this.element.options);

return options.find((option) => option.value === '' && option.selected);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<li class="<%= li_css_class %>">
<a href="<%= dynamic_path %>"
id="<%= id %>"
title="<%= title %>"
arial-label="<%= aria_label %>"
class="<%= link_css_class %>">
<%= icon %>
<%= label %>
</a>
</li>
78 changes: 78 additions & 0 deletions modules/meeting/app/components/meetings/add_button_component.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# frozen_string_literal: true

# -- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2023 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 Meetings
class AddButtonComponent < ::RailsComponent
options :current_project

def render?
if current_project
User.current.allowed_to?(:create_meetings, current_project)
else
User.current.allowed_to_globally?(:create_meetings)
end
end

def li_css_class
'toolbar-item'
end

def dynamic_path
polymorphic_path([:new, current_project, :meeting])
end

def id
'add-meeting-button'
end

def title
I18n.t(:label_meeting_new)
end

def aria_label
I18n.t(:label_meeting_new)
end

def link_css_class
'button -alt-highlight'
end

def label
content_tag(:span,
I18n.t(:label_meeting),
class: 'button--text')
end

def icon
helpers.op_icon('button--icon icon-add')
end
end
end
30 changes: 23 additions & 7 deletions modules/meeting/app/controllers/meetings_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,12 @@ class MeetingsController < ApplicationController
before_action :build_meeting, only: %i[new create]
before_action :find_meeting, except: %i[index new create]
before_action :convert_params, only: %i[create update]
before_action :authorize, except: [:index]
before_action :authorize_global, only: :index
before_action :authorize, except: %i[index new]
before_action :authorize_global, only: %i[index new]

helper :watchers
helper :meeting_contents
include MeetingsHelper
include WatchersHelper
include PaginationHelper
include SortHelper
Expand Down Expand Up @@ -76,7 +77,9 @@ def create
end
end

def new; end
def new
render layout: 'no_menu' if global_create_context?
end

current_menu_item :new do
:meetings
Expand Down Expand Up @@ -123,14 +126,24 @@ def set_time_zone(&)

def build_meeting
@meeting = Meeting.new
if meeting_params.present?
convert_params
@meeting.participants.clear # Start with a clean set of participants
@meeting.participants_attributes = @converted_params.delete(:participants_attributes)
@meeting.attributes = @converted_params
end
@meeting.project = @project
@meeting.author = User.current
end

def project_id
params[:project_id] || params.dig(:meeting, :project_id)
end

def find_optional_project
return true unless params[:project_id]
return true if project_id.blank?

@project = Project.find(params[:project_id])
@project = Project.find(project_id)
authorize
rescue ActiveRecord::RecordNotFound
render_404
Expand Down Expand Up @@ -163,7 +176,10 @@ def convert_params
end

def meeting_params
params.require(:meeting).permit(:title, :location, :start_time, :duration, :start_date, :start_time_hour,
participants_attributes: %i[email name invited attended user user_id meeting id])
if params[:meeting].present?
params.require(:meeting).permit(:title, :location, :start_time,
:duration, :start_date, :start_time_hour,
participants_attributes: %i[email name invited attended user user_id meeting id])
end
end
end
22 changes: 22 additions & 0 deletions modules/meeting/app/helpers/meetings_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,26 @@ def render_journal_details(journal, header_label = :label_updated_time_by, _mode

content_tag('div', "#{header}#{details}".html_safe, id: "change-#{journal.id}", class: 'journal')
end

def global_create_context?
request.path == new_meeting_path
end

def new_form_refresh_url
if global_create_context?
new_meeting_path
else
new_project_meeting_path(@project)
end
end

def options_for_project_selection
Project.allowed_to(User.current, :create_meetings)
.filter { _1.module_enabled?('meetings') }
.map { [_1.name, _1.id] }
end

def project_select_initial_class_list
params.dig(:meeting, :project_id).blank? ? '-prompt-visible' : ''
end
end
22 changes: 21 additions & 1 deletion modules/meeting/app/views/meetings/_form.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,23 @@ See COPYRIGHT and LICENSE files for more details.
<%= f.text_field :title, :required => true, :size => 60, container_class: '-wide' %>
</div>

<% if global_create_context? %>
<div class="form--field -required">
<%= f.select :project_id,
options_for_project_selection,
{prompt: t(:project_selection_placeholder),
container_class: '-wide'},
class: project_select_initial_class_list,
required: true,
data: {
'application-target': 'dynamic',
controller: 'select-field-with-prompt',
action: 'change->select-field-with-prompt#togglePromptStyling ' \
'change->refresh-on-form-changes#triggerReload'
} %>
</div>
<% end %>

<div class="form--field">
<%= f.text_field :location, :size => 60, container_class: '-wide' %>
</div>
Expand Down Expand Up @@ -86,7 +103,8 @@ See COPYRIGHT and LICENSE files for more details.
</div>
</div>

<div class="form--field">
<% if @project %>
<div class="form--field">
<label class="form--label"><%=Meeting.human_attribute_name(:participants) %></label>
<div class="form--field-container">
<table class="form--matrix">
Expand Down Expand Up @@ -128,6 +146,8 @@ See COPYRIGHT and LICENSE files for more details.
</table>
</div>
</div>
<% end %>
<%= hidden_field_tag "copied_from_meeting_id", params[:copied_from_meeting_id] if params[:copied_from_meeting_id].present? %>
<%= hidden_field_tag "copied_meeting_agenda_text", params[:copied_meeting_agenda_text] if params[:copied_meeting_agenda_text].present? %>
</section>
13 changes: 1 addition & 12 deletions modules/meeting/app/views/meetings/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,7 @@ See COPYRIGHT and LICENSE files for more details.
<% html_title t(:label_meeting_plural) %>
<%= toolbar title: t(:label_meeting_plural) do %>
<% if authorize_for(:meetings, :new) %>
<li class="toolbar-item">
<a href="<%= polymorphic_path([:new , @project, :meeting]) %>"
id="add-meeting-button"
title="<%= I18n.t(:label_meeting_new) %>"
arial-label="<%= I18n.t(:label_meeting_new) %>"
class="button -alt-highlight">
<%= op_icon('button--icon icon-add') %>
<span class="button--text"><%= t(:label_meeting) %></span>
</a>
</li>
<% end %>
<%= render Meetings::AddButtonComponent.new(current_project: @project) %>
<% end %>
<% if @meetings.empty? -%>
Expand Down
4 changes: 2 additions & 2 deletions modules/meeting/app/views/meetings/new.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ See COPYRIGHT and LICENSE files for more details.
<% html_title t(:label_meeting_new) %>
<%= toolbar title: t(:label_meeting_new) %>
<%= labelled_tabular_form_for @meeting, :url => {:controller => '/meetings', :action => 'create', :project_id => @project}, :html => {:id => 'meeting-form'} do |f| -%>
<%= labelled_tabular_form_for @meeting, url: {:controller => '/meetings', :action => 'create', :project_id => @project}, :html => {:id => 'meeting-form', :data => { :controller => 'refresh-on-form-changes', 'refresh-on-form-changes-target': 'form', 'refresh-on-form-changes-refresh-url-value': new_form_refresh_url }} do |f| -%>
<%= render :partial => 'form', :locals => {:f => f} %>
<%= styled_button_tag t(:button_create), class: '-highlight' %>
<%= link_to t(:button_cancel), { :action => 'index', :project_id => @project },
class: 'button' %>
<% end if @project %>
<% end %>
4 changes: 4 additions & 0 deletions modules/meeting/config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ en:
participants: "Participants"
participants_attended: "Attendees"
participants_invited: "Invitees"
project: "Project"
start_time: "Time"
start_time_hour: "Starting time"
errors:
Expand Down Expand Up @@ -79,6 +80,7 @@ en:
label_time_zone: "Time zone"
label_start_date: "Start date"


meeting:
copied: "Copied from Meeting #%{id}"

Expand All @@ -99,6 +101,8 @@ en:

project_module_meetings: "Meetings"

project_selection_placeholder: "Select project"

text_duration_in_hours: "Duration in hours"
text_in_hours: "in hours"
text_meeting_agenda_for_meeting: 'agenda for the meeting "%{meeting}"'
Expand Down
20 changes: 16 additions & 4 deletions modules/meeting/spec/controllers/meetings_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,24 @@
end

describe 'html' do
before do
get 'new', params: { project_id: project.id }
context 'when requesting the global page' do
before do
get 'new'
end

it { expect(response).to be_successful }
it { expect(assigns(:meeting)).to eql meeting }
end

context 'when requesting the project-scoped page' do
before do
get 'new', params: { project_id: project.id }
end

it { expect(response).to be_successful }
it { expect(assigns(:meeting)).to eql meeting }
end

it { expect(response).to be_successful }
it { expect(assigns(:meeting)).to eql meeting }
end
end

Expand Down
4 changes: 2 additions & 2 deletions modules/meeting/spec/features/meetings_index_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,10 @@
context 'when the user is allowed to create meetings' do
let(:permissions) { %i(view_meetings create_meetings) }

it 'does not show a create button' do
it 'shows a create button' do
meetings_page.navigate_by_modules_menu

meetings_page.expect_no_create_new_button
meetings_page.expect_create_new_button
end
end
end
Expand Down
Loading

0 comments on commit 9a1d4a1

Please sign in to comment.