This change seeks to improve the reliability of our system tests by
resolving the lack of consistency in the state of the client side
application between steps in a system test. This is achieved by patching
various action methods in `Capybara::Playwright::Node` and
`Capybara::Playwright::Browser` so that the methods execute an async
JavaScript function on the client side that waits for the client side
application to reach a settled state. A settled state is currently
defined as:
1. No inflight ajax requests. (_messageBus and presence requests are
excluded_)
2. 2 event cycles of the Javascript event loop has happened for for all
"click", "input", "mousedown", "keydown", "focusin", "focusout",
"touchstart", "change", "resize", "scroll" DOM events that fired.
For debugging purposes, a `--debug-client-settled` CLI flag has been
added to `bin/rspec`. When used, detailed debugging information will be
printed to the browser's console as well as to `stdout` of the
`bin/rspec` process.
This change was inspired by
https://evilmartians.com/chronicles/flaky-tests-be-gone-long-lasting-relief-chronic-ci-retry-irritation
and the https://github.com/makandra/capybara-lockstep rubygem.
Reverts the removal of this from
https://github.com/discourse/discourse-calendar/pull/231. This opens up
the relative url `/discourse-post-event/events.ics` for access to an
ical formatted response.
We also make available the `order` argument for this endpoint which
defaults to ascending order if there is no value or invalid value
passed. This maintains existing behaviour while allowing for users to
specify that they want most recent events first.
We can't enable `Rails/WhereNot` lint/autofix, because it would break
code that uses mini_sql instead of AR (which rubocop, and tbh also we,
can't easily differentiate)
Those are safe because they either:
* are executed in AR model scope definitions
* are clearly chained starting from a AR model
* are less-clearly chained, but still can be traced to a AR model/scope
---------
Co-authored-by: Loïc Guitaut <loic@discourse.org>
Context: The `btn` mixin is used for every functional button, but this
includes button elements that are not, or should not be, styled like our
default or primary buttons.
To change how this works this commit:
* stripped down the mixin to the bare essentials, mainly limiting to the
properties that use variables.
* moved most things into the `btn` class
* moved some things into specific descriptive classes (default, danger,
success) such as border-radius
Example of button that does not need a border-radius and would benefit
from this:
<img width="464" height="184" alt="CleanShot 2025-09-19 at 12 56 04@2x"
src="https://github.com/user-attachments/assets/e908b2cf-971f-4c1f-aade-7492bad2f89c"
/>
* Deprecated…
* FlatButton component
* btn-active: we should use the proper pseudoclass :active or a –-active
modifier in code if we need it
* btn-text: every button by default is a btn-text. We already have a
class to indicate when it isn’t (no-text)
* fixed btn-link property to make DButton component behave like an
inline link (no padding, link-styling)
* Since I moved styling from .btn, ths means every button now needs a
specific declaration. So I’ve added btn-default where necessary.
* Fixed btn-flat hover effect: The difference between btn-flat and
btn-transparent was getting very ambiguous. I’ve fixed the hover effect
for btn-flat so that the distinction is:
<img width="1094" height="408" alt="image"
src="https://github.com/user-attachments/assets/addf56a9-1f61-463d-abd9-5028a3b88fad"
/>
* Changed the custom icon colour from header icons so it follows the
normal btn-flat styling, the way the sidebar icon already was doing.
(Consistency)
**Other small button-related change along the way**
What | BC | AC |
|----| ----|--------|
Inconsistent save/cancel colours | <img width="1720" height="1084"
alt="CleanShot 2025-09-19 at 15 31 40@2x"
src="https://github.com/user-attachments/assets/227289c3-6ded-4633-868d-6e33c32d83c3"
/> | <img width="1720" height="1084" alt="CleanShot 2025-09-19 at 15 30
56@2x"
src="https://github.com/user-attachments/assets/b23f96c9-04f3-40ea-9fba-2be59eae8e64"
/> |
---------
Co-authored-by: Martin Brennan <martin@discourse.org>
We are not sure of the reasons but there are multiple similar (yet not
exactly the same) reports of resizing issues with calendar causing this
exact same `width: 0` state we have experienced.
Replaces Ember's deprecated `filterBy` with the native JavaScript method
`filter`. This aligns with modern JavaScript practices, improves code
clarity, and prepares for future deprecations.
Changes involve various components, controllers, and models across the
codebase.
This Pull Request introduces changes that replace the use of .sortBy
with .sort combined with compare from @ember/utils. This update aims to
modernize and standardize sorting operations throughout the codebase.
**Main Changes:**
* Replaced .sortBy with .sort and compare in various components,
controllers, and services to improve sorting practices.
* Updated sorting logic to handle optional chaining (?.) for increased
robustness.
* Adjusted sorting logic, including reversing, in some cases for more
clarity and correctness.
* Added a new deprecation workflow entry to handle sortBy deprecation
logs (discourse.native-array-extensions.sortBy).
For historical reasons, Discourse has a customized Ember resolver. This
had a much more fuzzy implementation of 'normalize' and 'findTemplate'
functions. This leniency meant that our file naming hasn't always
matched Ember conventions.
Standardizing our naming will make things easier to understand for
developers, and will make adoption of newer ecosystem tooling easier
(e.g. route-based bundle splitting in Embroider/vite)
This commit adds deprecations to the resolver when this leniency is
used, and uses a fully bespoke codemod to rename all of the affected
routes/controllers/templates in the Discourse core repository.
Backwards-compatibility is maintained for anyone looking up the old
names in the resolver.
- rename from calendar -> calendar and events
- fix config for plugin to show a tab for settings
still needs some CSS adjustments but mostly there
---------
Co-authored-by: Martin Brennan <martin@discourse.org>
Disabling post event with category events set would cause an error when
visiting the category, this commit ensures it's not the case and adds a
test for it.
Also added tests to ensure we correctly render category calendar in
different outlets as the before-topic-list-body one was broken.
Prior to this fix events with a description wouldn't show in the
composer when they contain a description. This was particularly
problematic as saving the post in this state would remove the event.
There was two issues:
- using the `TopicListItemSerializer` was fetching way more than we need
and also expecting includes from other plugins (assign for example),
switching to our own dedicated serializer seems a better choice here
- event dates were not preloaded
- fixed a spec which was supposed to track N+1 but was commented
I also improved our fabricator to limit the boilerplate needed.
We might need few more indices to improve perf event more here but going
to merge this first.
This PR modernizes the GroupSelector component by migrating from the
legacy jQuery autocomplete to FloatKit’s DMultiSelect component.
### Changes
* Migrated GroupSelector from an Ember Classic component to Glimmer
component
* Replaced jQuery-based autocomplete with FloatKit’s DMultiSelect
component which handles search
* New scroll-into-view modifier for smooth keyboard navigation (can be
used later to replace d-autocomplete's similar functionality)
* Improved FloatKit's `size` middleware option handling to allow passing
through both minWidth and width props
* Selected items are dynamically removed from dropdown options (no
duplicates)
To prepare for the introduction of `CategoryDefaultTimer`, which allows
posts created in certain categories to have a default TopicTimer, we
need to rename the `topic_id` column to `timerable_id`.
---------
Co-authored-by: Alan Guo Xiang Tan <gxtan1990@gmail.com>
This was preventing the `map_events_to_color` site setting to work
correctly given we couldn't match on tag slug as it was not present.
This commit adds system specs and removes the js test as it was
misleading and incorrectly passing due to the fixture which couldn't
catch the issue in the serializer.
Allows admins to set the `calendar_event_display` site setting to decide
how full-calendar should render events.
It accepts the following values:
- auto
- block
- list-item
And will default to: auto
The AFL Grand Final is typically help on the last Saturday of September,
though there are occasional exceptions. Since 2015, the Friday before
the Grand Final is a public holiday in Victoria, Australia.
This change defines the typical date for the public holiday, but allows
exceptions to be defined where necessary.
Allow picking Saturday,Sunday or Monday as first day of week.
Keeps current default and adds extensive testing.
---------
Co-authored-by: Joffrey JAFFEUX <j.jaffeux@gmail.com>
Co-authored-by: Martin Brennan <martin@discourse.org>
Allows to set the max attendees of an event. When an event is full you
can only mark yourself as interested or not going. The going button will
be disabled.
Maximum attendees can be defined in the post builder:
<img width="569" height="106" alt="Screenshot 2025-09-01 at 20 57 16"
src="https://github.com/user-attachments/assets/bf61cd57-d35e-44a7-8d05-263ee9cd7df0"
/>
---------
Co-authored-by: Joffrey JAFFEUX <j.jaffeux@gmail.com>
Addresses two issues. On sites with many old events, we would not show
the correct items because the query would return the older events first.
Adds `includeSubcategories` parameter to include events from
subcategories in the list.
No tests for now, we might refactor this component very soon.
We were not correctly computing the dates when the option showLocalTime
is enabled on an event. In this case we need to generate a floating time
without a zone in the date.
This commit also refactors the serializers to avoid duplication.
rrule doesn't support duration so we have to ensure we can communicate
the duration to the frontend.
We were also making a mistake for the end date of non recurring events.