Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Recurring meetings #15620

Merged
merged 133 commits into from
Dec 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
133 commits
Select commit Hold shift + click to select a range
d2b9e6f
Prepare basic recurring meeting setup
oliverguenther Apr 26, 2024
4886368
Add proof of concept to create schedules
mrmir May 28, 2024
fa27978
Add feature flag
oliverguenther Oct 1, 2024
fd1323d
Rework menu
oliverguenther Oct 1, 2024
1339c0b
Pass request to meetings menu
oliverguenther Oct 1, 2024
91276b2
Add filter menu for recurring meetings
oliverguenther Oct 2, 2024
006002e
Start primerized create form
oliverguenther Oct 2, 2024
c11e5d4
Add recurring meetings to dropdown and dialog
oliverguenther Nov 10, 2024
d02b49b
Add schedule
oliverguenther Nov 10, 2024
b3985d1
Add frequency/iterations form
oliverguenther Nov 11, 2024
367b5a3
Add services
oliverguenther Nov 11, 2024
115f110
Recurring meetings menu entry
oliverguenther Nov 11, 2024
2229ae4
Fix setting project
oliverguenther Nov 11, 2024
101a52c
Template
oliverguenther Nov 12, 2024
23e0aef
add bi-weekly
oliverguenther Nov 12, 2024
ef132e2
Merge branch 'dev' into feature/recurring-meetings
oliverguenther Nov 13, 2024
c69210e
Add template sideinfo
oliverguenther Nov 13, 2024
6e822aa
Skip mails when adding participants
oliverguenther Nov 13, 2024
f158787
exclude templated meetings
oliverguenther Nov 13, 2024
70461c0
Add header for templates
oliverguenther Nov 13, 2024
228586c
Prevent deletion of meeting template
oliverguenther Nov 13, 2024
03f1193
Fix breadcrumb
oliverguenther Nov 13, 2024
25cca0e
WIP Add show table and initialization
mrmir Nov 13, 2024
6cc9cc1
Change icon for calendar
oliverguenther Nov 13, 2024
085b5d2
remove unused template
oliverguenther Nov 13, 2024
01f2b80
add template has_one
oliverguenther Nov 13, 2024
9e79f44
meeting form
oliverguenther Nov 14, 2024
c8031d4
Fix creation of recurring
oliverguenther Nov 15, 2024
8e81a34
working edit
oliverguenther Nov 15, 2024
3f4af24
specify end time
oliverguenther Nov 15, 2024
294424e
Add header actions
mrmir Nov 19, 2024
fc7dd18
Add initial recurring meeting frequency label
mrmir Nov 20, 2024
a33ed25
Add index page
mrmir Nov 20, 2024
004d8c0
Add soft delete and restore for occurrences
mrmir Nov 20, 2024
01274c4
Refine implementation of scheduled meetings using skeletons
oliverguenther Nov 21, 2024
4937ee1
Add template link
oliverguenther Nov 21, 2024
0039894
Paginate
oliverguenther Nov 21, 2024
16cfc23
Move init of meeting to recurring
oliverguenther Nov 21, 2024
9e549f7
Add schedule in words
mrmir Nov 22, 2024
a7ee620
Add show series action item
oliverguenther Nov 22, 2024
577b306
Implement changed show page of occurrence
oliverguenther Nov 22, 2024
ba7c051
Add interval, fewer frequencies
oliverguenther Nov 22, 2024
6e84e37
Add interval to schedule
oliverguenther Nov 22, 2024
fd060ff
Try to add non working days
oliverguenther Nov 22, 2024
fe84501
Update meetings index to display recurring occurrences correctly
mrmir Nov 22, 2024
c15a148
Update schedule in words
mrmir Nov 22, 2024
cb3c5b6
Fix exception rule
oliverguenther Nov 23, 2024
ba927df
Fix occurrence for working days
oliverguenther Nov 23, 2024
1e3083d
Hide interval when selecting working_days
oliverguenther Nov 23, 2024
4b22d3a
Document show-when-value-selected
oliverguenther Nov 23, 2024
b709bfe
Set interval to 1 when changing to working_days
oliverguenther Nov 23, 2024
cfb91a9
Fix dialog
oliverguenther Nov 25, 2024
5740702
Merge branch 'dev' into feature/recurring-meetings
oliverguenther Nov 25, 2024
b47d2ab
Adapt to mobile table
oliverguenther Nov 25, 2024
d730211
Update type filter
mrmir Nov 25, 2024
7195fb3
Rename TypeFilter -> RecurringFilter
oliverguenther Nov 26, 2024
91f28b2
Start date group
oliverguenther Nov 26, 2024
454c846
Combined Filter component
oliverguenther Nov 26, 2024
9c7a4eb
Updated menu
oliverguenther Nov 26, 2024
50b873e
Merge branch 'dev' into feature/recurring-meetings
oliverguenther Nov 26, 2024
8145ff0
Update label created by me
oliverguenther Nov 26, 2024
ea01f5f
Add validation on end_date > start_date
oliverguenther Nov 27, 2024
68a360c
Implement sorting through query
oliverguenther Nov 27, 2024
67063d0
Render all meeting series in the sidebar
oliverguenther Nov 27, 2024
ac73ea3
Select my meetings only when href passed
oliverguenther Nov 27, 2024
932ff90
WIP Add initial specs
mrmir Nov 27, 2024
e3f20c7
Fix date validation
oliverguenther Nov 28, 2024
d5aa2b9
Use the correct date formatter in the subtitle
mrmir Nov 28, 2024
5a72451
Add spec for date validation
oliverguenther Nov 28, 2024
e3029d5
Change label to View template
oliverguenther Nov 28, 2024
b659bc2
Add edit series button
oliverguenther Nov 28, 2024
12e098d
Fix deletion of recurring meetings
oliverguenther Nov 28, 2024
4249e15
Correctly hide form for end_after options
oliverguenther Nov 28, 2024
709e024
Update copy behaviour to never allow recurring copies
mrmir Nov 28, 2024
b3de8d0
Fix location value in form
mrmir Nov 28, 2024
28b134a
Fix meeting details form
oliverguenther Nov 28, 2024
a23b034
Add scheduled meetings table
oliverguenther Nov 28, 2024
61422d7
Replace destroy/restore with actual destroy
oliverguenther Nov 29, 2024
015c413
Uniqueness
oliverguenther Nov 29, 2024
fd39c4d
Delete with schedule
oliverguenther Nov 29, 2024
5b17417
Switch to start_time
oliverguenther Nov 29, 2024
17f8a8b
Use start_time in schedule
oliverguenther Nov 29, 2024
91a8672
Add helper for time formatting to the current user
oliverguenther Nov 29, 2024
8ff6d78
fixup! Delete with schedule
oliverguenther Nov 29, 2024
31e0e46
Move update_start_time to concern
oliverguenther Nov 29, 2024
41f82e2
Delete cancelled meetings when changing schedule
oliverguenther Nov 29, 2024
01e062f
Allow passing dates directly
oliverguenther Nov 29, 2024
baf964d
Remove cancelled occurrences when changing schedules
oliverguenther Nov 29, 2024
c62cf70
Limit count_rule until end_date
mrmir Nov 29, 2024
a657f79
Show changed start times for occurrences
mrmir Nov 29, 2024
40741d1
Indent case
oliverguenther Dec 2, 2024
fbd5ff7
Fix destroy path to include project
oliverguenther Dec 2, 2024
2dc1c14
Fix past meetings
oliverguenther Dec 2, 2024
b1a8bed
Schedule first occurrence on creation
oliverguenther Dec 2, 2024
2ea44f9
Merge branch 'dev' into feature/recurring-meetings
oliverguenther Dec 2, 2024
47e1093
Linting
oliverguenther Dec 2, 2024
101c42e
fixup! Linting
oliverguenther Dec 2, 2024
83ff834
Autoschedule job
oliverguenther Dec 2, 2024
2068087
Add more schedule tests
oliverguenther Dec 2, 2024
c9275c7
Fix project-based destroy
oliverguenther Dec 2, 2024
a8f2a69
Redirect to template, not show
oliverguenther Dec 2, 2024
b26d144
Don't cache user time zone in request store
oliverguenther Dec 2, 2024
9067c5e
Fix forgotten invited where
oliverguenther Dec 2, 2024
af113dd
fixup! Linting
oliverguenther Dec 2, 2024
252566b
Remove default meeting order
oliverguenther Dec 2, 2024
6815382
Fix meetings index spec with new ordering
oliverguenther Dec 2, 2024
89feef5
Fix path
oliverguenther Dec 2, 2024
00cf518
Convert meeting tab to cuprite
oliverguenther Dec 2, 2024
928a7ab
Fix expectation for meeting tab
oliverguenther Dec 2, 2024
39a46f0
More robust selector on meeting tab
oliverguenther Dec 2, 2024
4ea6130
Change global menu spec
oliverguenther Dec 2, 2024
e18b675
Add more CRUD specs
mrmir Dec 3, 2024
41e8917
Fix dates and times
mrmir Dec 3, 2024
515f923
Allow cancellation of scheduled meetings
mrmir Dec 3, 2024
8f698c0
Lint
oliverguenther Dec 4, 2024
a0f9d2e
Reschedule init job when updating schedule
oliverguenther Dec 4, 2024
7a6eba0
Fix end date in the form
mrmir Dec 4, 2024
dc59d31
Test cancellation
oliverguenther Dec 4, 2024
52470d8
Extract create spec
oliverguenther Dec 4, 2024
6d200d4
Fix specs
oliverguenther Dec 4, 2024
9140018
Add spec when lacking permissions
oliverguenther Dec 4, 2024
d739bca
Fix cancellation of scheduled meetings
mrmir Dec 4, 2024
807c94e
Render meetings with correct project link
oliverguenther Dec 4, 2024
a3706f0
Remove unused disable
oliverguenther Dec 4, 2024
485ef52
Remove useless cop disable
oliverguenther Dec 4, 2024
88965c5
Add contract specs
oliverguenther Dec 4, 2024
27a517d
Add delete contract spec
oliverguenther Dec 4, 2024
072a3ce
Revert "Add delete contract spec"
oliverguenther Dec 4, 2024
8e014c5
Add delete contract spec for meetings itself
oliverguenther Dec 4, 2024
9eb9e04
Fix spec
oliverguenther Dec 4, 2024
eb0dab0
Hide past cancelled occurrences
mrmir Dec 27, 2024
a053a35
Show different delete labels and messages
mrmir Dec 27, 2024
42129b5
Move to request spec
oliverguenther Dec 4, 2024
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
3 changes: 3 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,9 @@ gem "paper_trail", "~> 15.2.0"

gem "op-clamav-client", "~> 3.4", require: "clamav"

# Recurring meeting events definition
gem "ice_cube", "~> 0.17.0"

group :production do
# we use dalli as standard memcache client
# requires memcached 1.4+
Expand Down
1 change: 1 addition & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1269,6 +1269,7 @@ DEPENDENCIES
httpx
i18n-js (~> 4.2.3)
i18n-tasks (~> 1.0.13)
ice_cube (~> 0.17.0)
json_schemer (~> 2.3.0)
json_spec (~> 1.1.4)
ladle
Expand Down
4 changes: 2 additions & 2 deletions app/components/op_primer/border_box_table_component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class << self
#
# This results in the description columns to be hidden on mobile
def mobile_columns(*names)
return @mobile_columns || columns if names.empty?
return Array(@mobile_columns || columns) if names.empty?

@mobile_columns = names.map(&:to_sym)
end
Expand All @@ -54,7 +54,7 @@ def mobile_columns(*names)
#
# This results in the description columns to be hidden on mobile
def mobile_labels(*names)
return @mobile_labels if names.empty?
return Array(@mobile_labels) if names.empty?

@mobile_labels = names.map(&:to_sym)
end
Expand Down
11 changes: 8 additions & 3 deletions app/menus/submenu.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class Submenu
include Rails.application.routes.url_helpers
attr_reader :view_type, :project, :params

def initialize(view_type:, project: nil, params: nil)
def initialize(view_type:, params:, project: nil)
@view_type = view_type
@project = project
@params = params
Expand Down Expand Up @@ -108,12 +108,13 @@ def query_params(id)
{ query_id: id }
end

def menu_item(title:, icon_key: nil, count: nil, show_enterprise_icon: false, query_params: {})
def menu_item(title:, icon_key: nil, count: nil, show_enterprise_icon: false,
query_params: {}, selected: selected?(query_params))
OpenProject::Menu::MenuItem.new(title:,
href: query_path(query_params),
icon: icon_map.fetch(icon_key, icon_key),
count:,
selected: selected?(query_params),
selected:,
favored: favored?(query_params),
show_enterprise_icon:)
end
Expand Down Expand Up @@ -144,4 +145,8 @@ def icon_map
def query_path(query_params)
raise NotImplementedError
end

def url_helpers
@url_helpers ||= OpenProject::StaticRouting::StaticRouter.new.url_helpers
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class IntegerListOptional < ::Queries::Filters::Strategies::Integer
def operator_map
super_value = super.dup
super_value["="] = ::Queries::Operators::EqualsOr
super_value["*"] = ::Queries::Operators::All

super_value
end
Expand Down
8 changes: 8 additions & 0 deletions app/models/setting/aliases.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,13 @@ def host_without_protocol
def optional_port_from_host_name
Setting.host_name&.split(":")&.[](1)
end

##
# Get the names of working days
# @return [Array<String>] the names of the working days
def working_day_names
weekdays = %i[monday tuesday wednesday thursday friday saturday sunday]
Setting.working_days.map { |day| weekdays[day - 1] }
end
end
end
2 changes: 2 additions & 0 deletions config/initializers/feature_decisions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@
OpenProject::FeatureDecisions.add :custom_field_of_type_hierarchy,
description: "Allows the use of the custom field type 'Hierarchy'."

OpenProject::FeatureDecisions.add :recurring_meetings,
description: "Differentiate between one-time and recurring meetings."
# TODO: Remove once the feature flag primerized_work_package_activities is removed altogether
OpenProject::FeatureDecisions.define_singleton_method(:primerized_work_package_activities_active?) do
Rails.env.production? ||
Expand Down
2 changes: 2 additions & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1017,6 +1017,7 @@ en:
messages:
accepted: "must be accepted."
after: "must be after %{date}."
after_today: "must be in the future."
after_or_equal_to: "must be after or equal to %{date}."
before: "must be before %{date}."
before_or_equal_to: "must be before or equal to %{date}."
Expand Down Expand Up @@ -3093,6 +3094,7 @@ en:
notice_successful_connection: "Successful connection."
notice_successful_create: "Successful creation."
notice_successful_delete: "Successful deletion."
notice_successful_cancel: "Successful cancellation."
notice_successful_update: "Successful update."
notice_successful_update_custom_fields_added_to_project: |
Successful update. The custom fields of the activated types are automatically activated
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,18 @@ export default class OpShowWhenValueSelectedController extends ApplicationContro
}

private toggleDisabled(evt:InputEvent):void {
const value = (evt.target as HTMLInputElement).value;
this.effectTargets.forEach((el) => {
el.hidden = !(el.dataset.value === value);
const input = evt.target as HTMLInputElement;
const targetName = input.dataset.targetName;

this
.effectTargets
.filter((el) => targetName === el.dataset.targetName)
.forEach((el) => {
if (el.dataset.notValue) {
el.hidden = el.dataset.notValue === input.value;
} else {
el.hidden = !(el.dataset.value === input.value);
}
});
}
}
19 changes: 13 additions & 6 deletions lib_static/redmine/i18n.rb
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,7 @@ def link_regex
def format_time_as_date(time, format: nil)
return nil unless time

zone = User.current.time_zone
local_date = time.in_time_zone(zone).to_date
local_date = in_user_zone(time).to_date

if format
local_date.strftime(format)
Expand All @@ -148,21 +147,29 @@ def format_time_as_date(time, format: nil)
def format_time(time, include_date: true, format: Setting.time_format)
return nil unless time

zone = User.current.time_zone
local = time.in_time_zone(zone)
local = in_user_zone(time)

(include_date ? "#{format_date(local)} " : "") +
(format.blank? ? ::I18n.l(local, format: :time) : local.strftime(format))
end

##
# Formats the given time as a time string according to the +user+'s time zone
# @param time [Time] The time to format.
# @param user [User] The user to use for the time zone. Defaults to +User.current+.
# @return [Time] The time with the user's time zone applied.
def in_user_zone(time, user: User.current)
time.in_time_zone(user.time_zone)
end

# Returns the offset to UTC (with utc prepended) currently active
# in the current users time zone. DST is factored in so the offset can
# shift over the course of the year
def formatted_time_zone_offset
def formatted_time_zone_offset(user: User.current)
# Doing User.current.time_zone and format that will not take heed of DST as it has no notion
# of a current time.
# https://github.com/rails/rails/issues/7297
"UTC#{User.current.time_zone.now.formatted_offset}"
"UTC#{user.time_zone.now.formatted_offset}"
end

def day_name(day)
Expand Down
97 changes: 86 additions & 11 deletions lookbook/docs/patterns/02-forms.md.erb
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,81 @@ allowing to put some content in between:

This is the regular way of using Primer forms.



### Basic Interactivity

In many cases, you want to show or hide a certain field based on the value of another field. For this purpose, there is the Stimulus controller `show-when-value-selected`.

To use it, pass the controller to the form, and then use `cause` and `effect` targets together with a `data-value`.

Basic example:

```ruby
primer_form_with(
...
data: { controller: "show-when-value-selected" }
) do |f|
render_inline_form(f) do |my_form|
my_form.select_list(
name: "frequency",
label: "Choose frequency",
data: {
target_name: "frequency",
"show-when-value-selected-target": "cause"
}
) do |list|
list.option(label: "Foo", value: "foo")
list.option(label: "Bar", value: "bar")
list.option(label: "Third option", value: "other")
end

# Will be shown when "Foo" is selected
my_form.text_field(
name: :interval,
type: :number,
data: {
target_name: "frequency",
value: "foo"
"show-when-value-selected-target": "cause"
}
end

# Will be shown when "Bar" is selected
my_form.text_field(
name: :random,
type: :text,
data: {
target_name: "frequency",
value: "bar"
"show-when-value-selected-target": "effect"
}
end

# Will be shown when not "other" is selected
my_form.text_field(
name: :random,
type: :text,
hidden: @my_object.state == 'other'
data: {
target_name: "frequency",
not_value: "other"
"show-when-value-selected-target": "effect"
}
end
end
```

Important data inputs:

- `"show-when-value-selected-target": "cause"` marks a field as the emitter of a change. Whenever this input changes, the other fields visibility will be toggled.
- `"show-when-value-selected-target": "effect"` is the input that will get hidden or shown depending on the selected value
- `data: { value: 'XYZ'}` or `data-value="XYZ"` the value to be checked against the cause
- `data: { not_value: 'XYZ'}` or `data-not-value="XYZ"` the value to be checked against the cause, resulting in it being hidden if the selected value is NOT the given one.
- data: `{ target_name: "abc"}` or `data-target-name="abc"` allows you to define multiple sets of cause/effect handlers



### Accessing the form model

When defining a form, the model sometimes needs to be accessed, for instance to remove or add some fields depending on the state of the model.
Expand Down Expand Up @@ -308,22 +383,22 @@ administration pages.
So far, the following helpers are available:

* `text_field(name:, **options)`: renders a text field for the setting called
`name`, automatically setting the label, value, and disabled state from the
setting's attributes.
`name`, automatically setting the label, value, and disabled state from the
setting's attributes.

* `check_box(name:, **options)`: renders a checkbox for the setting called
`name`, automatically setting the label, checked state, and disabled state
from the setting's attributes.
`name`, automatically setting the label, checked state, and disabled state
from the setting's attributes.

* `radio_button_group(name:, values:, button_options: {}, **options)`: renders
a radio button group for the setting called `name` and radio button for each
element of `values`, automatically setting the label, checked state, html
caption, and disabled state from the setting's attributes.
a radio button group for the setting called `name` and radio button for each
element of `values`, automatically setting the label, checked state, html
caption, and disabled state from the setting's attributes.

* `submit`: renders a submit button with the label "Save" and the primary
scheme.
scheme.

* `form`: the form builder instance if you need to render some form elements
normally handled by the settings form decorator in another way than intended.
Any call to a method that is not defined on the settings form decorator will
be forwarded to this form builder instance so its usage is transparent.
normally handled by the settings form decorator in another way than intended.
Any call to a method that is not defined on the settings form decorator will
be forwarded to this form builder instance so its usage is transparent.
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
<%=
component_wrapper(data: wrapper_data_attributes) do
flex_layout(mb: 3) do |flex|
if @meeting.template?
flex.with_row(mb: 3) do
render Primer::Alpha::Banner.new(scheme: :default,
icon: :info,
dismiss_scheme: :none) do
t("recurring_meeting.template.banner_html",
link: link_to(@meeting.recurring_meeting.title,
recurring_meeting_path(@meeting.recurring_meeting)))
end
end
end
flex.with_row(classes: 'dragula-container', id: insert_target_modifier_id, data: { 'allowed-drop-type': 'section' }.merge(drop_target_config) ) do
first_and_last = [@meeting.sections.first, @meeting.sections.last]
render(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<%=
flex_layout do |flex|
flex.with_column do
render(Meetings::MeetingFilterButtonComponent.new(query: @query, project: @project))
end

flex.with_column(ml: 1) do
render(Primer::Alpha::SegmentedControl.new("aria-label": I18n.t(:label_meeting_date_time))) do |control|
control.with_item(tag: :a,
icon: :"arrow-right",
href: dynamic_path,
label: t(:label_upcoming_meetings_short),
title: t(:label_upcoming_meetings),
selected: upcoming_query?)
control.with_item(tag: :a,
icon: :history,
href: dynamic_path(upcoming: false),
label: t(:label_past_meetings_short),
title: t(:label_past_meetings),
selected: !upcoming_query?)
end
end
end
%>
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#-- 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 Meetings
class CombinedFilterComponent < ApplicationComponent
include ApplicationHelper
include OpTurbo::Streamable
include OpPrimer::ComponentHelpers
include Redmine::I18n

def initialize(query:, params:, project: nil)
super()

@query = query
@project = project
@params = params
end

def dynamic_path(upcoming: true)
polymorphic_path([@project, :meetings], current_params.merge(upcoming:))
end

def upcoming_query?
filter = @query.filters.find { |f| f.name == :time }
filter ? !filter.past? : true
end

def current_params
@current_params ||= params.slice(:filters, :page, :per_page).permit!
end
end
end
Loading
Loading