Implement fetching

This commit is contained in:
Oliver Günther
2024-12-11 09:27:48 +01:00
parent 6022f18d2b
commit 9530ab5b81
12 changed files with 207 additions and 16 deletions
@@ -1,17 +1,32 @@
import { ApplicationController } from 'stimulus-use';
import { TurboRequestsService } from 'core-app/core/turbo/turbo-requests.service';
import { PathHelperService } from 'core-app/core/path-helper/path-helper.service';
export default class OpRecurringMeetingsFormController extends ApplicationController {
static targets = [
'frequency',
'interval',
];
private turboRequests:TurboRequestsService;
private pathHelper:PathHelperService;
declare readonly frequencyTarget:HTMLSelectElement;
declare readonly intervalTarget:HTMLInputElement;
async connect() {
const context = await window.OpenProject.getPluginContext();
this.turboRequests = context.services.turboRequests;
this.pathHelper = context.services.pathHelperService;
}
updateFrequencyText():void {
const frequency = this.frequencyTarget.value;
const interval = this.intervalTarget.value;
this.intervalTarget.placeholder = `Every ${frequency}`;
const data = new FormData(this.element as HTMLFormElement);
const urlSearchParams = new URLSearchParams();
['start_date', 'start_time_hour', 'frequency', 'interval'].forEach((name) => {
const key = `meeting[${name}]`;
urlSearchParams.append(key, data.get(key) as string);
});
void this
.turboRequests
.request(
`${this.pathHelper.staticBase}/recurring_meetings/update_schedule?${urlSearchParams.toString()}`,
{
headers: { Accept: 'text/vnd.turbo-stream.html' },
},
);
}
}
@@ -69,7 +69,11 @@
end
modal_body.with_row(mt: 1) do
render(Primer::Beta::Text.new(font_size: :small, color: :subtle)) { @meeting.human_frequency_schedule }
render(Primer::Beta::Text.new(
id: "recurring-meeting-frequency-schedule",
font_size: :small,
color: :subtle,
)) { @meeting.human_frequency_schedule }
end
modal_body.with_row(mt: 3) do
@@ -0,0 +1,40 @@
module RecurringMeetings
class ScheduleController < ApplicationController
before_action do
do_authorize :create_meetings, global: true
end
authorization_checked! :update_text
around_action :with_user_time_zone
before_action :build_meeting
def update_text
text = @recurring_meeting.human_frequency_schedule
respond_to do |format|
format.html { render plain: text }
format.turbo_stream do
render turbo_stream: turbo_stream.update("recurring-meeting-frequency-schedule",
plain: text)
end
end
end
private
def with_user_time_zone(&)
User.execute_as(User.current, &)
end
def build_meeting
@recurring_meeting = RecurringMeeting.new(schedule_params.compact_blank)
end
def schedule_params
params
.require(:meeting)
.permit(:start_date, :start_time_hour, :frequency, :interval)
end
def default_breadcrumb; end
end
end
@@ -39,7 +39,10 @@ class Meeting::TimeGroup < ApplicationForm
label: Meeting.human_attribute_name(:start_date),
leading_visual: { icon: :calendar },
required: true,
autofocus: false
autofocus: false,
data: {
action: "input->recurring-meetings--form#updateFrequencyText"
}
)
group.text_field(
@@ -50,7 +53,10 @@ class Meeting::TimeGroup < ApplicationForm
label: Meeting.human_attribute_name(:start_time),
leading_visual: { icon: :clock },
required: true,
caption: formatted_time_zone_offset
caption: formatted_time_zone_offset,
data: {
action: "input->recurring-meetings--form#updateFrequencyText"
}
)
end
end
@@ -33,7 +33,6 @@ class RecurringMeeting::Frequency < ApplicationForm
label: I18n.t("activerecord.attributes.recurring_meeting.frequency"),
data: {
target_name: "frequency",
"recurring-meetings--form-target": "frequency",
"show-when-value-selected-target": "cause",
action: "input->recurring-meetings--form#updateFrequencyText"
}
@@ -31,9 +31,10 @@ class RecurringMeeting::Interval < ApplicationForm
meeting_form.text_field(
name: :interval,
type: :number,
step: 1,
max: RecurringMeeting::MAX_INTERVAL,
label: I18n.t("activerecord.attributes.recurring_meeting.interval"),
data: {
"recurring-meetings--form-target": "interval",
action: "input->recurring-meetings--form#updateFrequencyText"
}
)
@@ -31,6 +31,8 @@ class RecurringMeeting::Iterations < ApplicationForm
meeting_form.text_field(
name: :iterations,
type: :number,
step: 1,
max: RecurringMeeting::MAX_ITERATIONS,
label: I18n.t("activerecord.attributes.recurring_meeting.iterations")
)
end
+3
View File
@@ -64,6 +64,9 @@ Rails.application.routes.draw do
post :delete_scheduled
post :template_completed
end
collection do
get :update_schedule, controller: "recurring_meetings/schedule", action: :update_text
end
end
resources :meetings do
@@ -40,17 +40,20 @@ module OpenProject::Meeting
bundled: true do
project_module :meetings do
permission :view_meetings,
{ meetings: %i[index show check_for_updates download_ics participants_dialog history],
{
meetings: %i[index show check_for_updates download_ics participants_dialog history],
meeting_agendas: %i[history show diff],
meeting_minutes: %i[history show diff],
"meetings/menus": %i[show],
work_package_meetings_tab: %i[index count],
recurring_meetings: %i[index show new create download_ics] },
recurring_meetings: %i[index show new create download_ics]
},
permissible_on: :project
permission :create_meetings,
{
meetings: %i[new create copy new_dialog],
recurring_meetings: %i[new create copy init template_completed],
"recurring_meetings/schedule": %i[update_text],
"meetings/menus": %i[show]
},
permissible_on: :project,
@@ -81,6 +81,8 @@ RSpec.describe "Recurring meetings creation",
meetings_page.set_duration "1.5"
meetings_page.set_end_date "2025-01-15"
expect(page).to have_text "Every week on Tuesday at 01:30 PM"
click_on "Create meeting"
wait_for_network_idle
expect_and_dismiss_flash(type: :success, message: "Successful creation.")
@@ -0,0 +1,115 @@
#-- 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.
#++
require "spec_helper"
require_relative "../../support/pages/recurring_meeting/show"
RSpec.describe "Recurring meetings schedule text",
:skip_csrf,
type: :rails_request do
include Redmine::I18n
shared_let(:project) { create(:project, enabled_module_names: %i[meetings]) }
shared_let(:user) do
create(:user,
preferences: { time_zone: "Europe/London" },
member_with_permissions: { project => %i[view_meetings create_meetings] })
end
let(:current_user) { user }
let(:start_time_hour) { "10:00" }
let(:start_date) { "2024-12-05" }
let(:frequency) { "daily" }
let(:interval) { "1" }
let(:params) do
{ meeting: { start_time_hour:, start_date:, frequency:, interval: } }
end
let(:format) { :html }
subject do
get update_schedule_recurring_meetings_path(params:, format:)
response
end
before do
login_as(current_user)
end
describe "setting schedule" do
it "returns the update text" do
expect(subject).to have_http_status(:ok)
expect(subject.body).to include("Daily at 10:00 AM")
end
context "when changing the frequency and interval" do
let(:frequency) { "weekly" }
let(:interval) { "2" }
it "returns the update text" do
expect(subject).to have_http_status(:ok)
expect(subject.body).to include("Every 2nd week on Thursday at 10:00 AM")
end
end
context "when changing the interval" do
let(:interval) { "2" }
it "returns the update text" do
expect(subject).to have_http_status(:ok)
expect(subject.body).to include("Every 2nd day at 10:00 AM")
end
end
context "when leaving the interval empty" do
let(:interval) { "" }
it "falls back to the default" do
expect(subject).to have_http_status(:ok)
expect(subject.body).to include("Daily at 10:00 AM")
end
end
context "when requesting with turbo" do
let(:format) { :turbo_stream }
it "returns an update turbo stream" do
expect(subject).to have_http_status(:ok)
expect(subject.body).to include("turbo-stream")
expect(subject.body).to include("Daily at 10:00 AM")
end
end
end
context "when user has no permissions to access" do
let(:current_user) { create(:user) }
it "does not allow to request it" do
expect(subject).to have_http_status(:forbidden)
end
end
end
@@ -58,6 +58,7 @@ module Pages::Meetings
def set_start_time(time)
input = page.find_by_id("meeting_start_time_hour")
page.execute_script("arguments[0].value = arguments[1]", input.native, time)
page.execute_script("arguments[0].dispatchEvent(new Event('input'))", input.native)
end
def set_end_date(date)