With out AI credit system being rolled out, we no longer rely on
allowing/disallowing seeded models in the enumerator. This update allows
seeded models to be selected and used in the `LlmEnumerator`.
We markup video thumbnail `div`s in posts with `tabindex="0"` which
makes them tabbable, but without a role it's unclear they're
interactive.
Since on click or keypress these play the video, it should have
`role="button"` as well as an an accessible label.
I also noticed that `onKeyPress` was added here but isn't wired up to
anything... so I've included that and also added the space key as a
trigger in addition to enter.
1. In `initializers/chat-setup`, we call the async
`this.chatService.loadChannels()` function which we do not call `await`
on.
2. `ChatChannelRoute`'s `model` calls
`this.chatChannelsManager.find(params.channelId)` which will trigger an
API call if the `this.chatService.loadChannels` function has not loaded
the given channel yet.
3. The `ChatChannel` component is then rendered once the route's model
resolves and the `setup` function is called.
Within the `setup` function,
`this.chatChannelsManager.find(params.channelId)` is called to set the
channel's draft.
If the async call in step 1 does not resolve before step 3 happens, the
channel draft will be blank until the component is rerendered. To
resolve this, we can move the responsibility of loading a channel's
draft into `chatDraftsManager` from the `chat` service into the
`chatChannelsManager` service
instead so that a channel's drafts are populated whenever we store a
channel into `chatChannelsManager`.
This commit replaces several instances of `.uniq`, `.uniqBy`, and related
array deduplication methods with a new utility function
`uniqueItemsFromArray`. This change ensures proper deduplication logic
across the codebase while addressing the deprecation issues.
**Main Changes:**
* Created new utility function `uniqueItemsFromArray`: Located in a new
file, `array-tools.js`, this function provides a reusable and
configurable alternative for deduplication.
* Replaced old methods: Updated multiple files to use the new utility
function instead of deprecated or custom implementations for
deduplication.
* Replaced manual deduplication: Replace uses of `[...new Set(array)]`
to standardize the deduplication logic across the codebase.
* Added unit tests: Introduced thorough test coverage
(`array-tools-test.js`) to validate functionality and edge cases for the
utility function.
* Updated deprecation workflow: Added logging for deprecated uniq and
uniqBy methods to the `deprecation-workflow.js`.
This change is primarily focused on code quality improvements, ensuring
future-proof deduplication, and maintaining alignment with deprecation
guidelines.
This commit replaces the use of `.compact()` with `.filter((item) => item !=
null)` across multiple JavaScript files in the codebase. Additionally,
it introduces a new logging handler for a specific deprecation in the
deprecation workflow.
**Main Changes:**
* Replaced `.compact()` with `.filter((item) => item != null)` to
eliminate the Ember Array dependency and align with native JavaScript
practices.
* Deprecation Workflow: Added a log handler for
discourse.native-array-extensions.compact.
The Data Explorer plugin has historically only ever accepted query
parameters as a JSON-encoded string. This behaviour has existed since
the plugin was first created 10 years ago (44bbc78160716dba0d3d456364b975156f8dd50d).
This change doesn't alter how the plugin UI behaves, it simply allows
query parameters to be submitted as a JSON object _or_ as a JSON-encoded
string, rather than requiring that it must be JSON encoded. This allows
developers who call this API directly to work in a more familiar
pattern.
We do have a lot of messages like the following in dev logs turned on by
default.
```
DiscourseAi::Completions::Endpoints::AwsBedrock: request_tokens 22 response_tokens 13
DiscourseAi::Completions::Endpoints::AwsBedrock: request_tokens 51 response_tokens 57
DiscourseAi::Completions::Endpoints::AwsBedrock: request_tokens 22 response_tokens 13
DiscourseAi::Completions::Endpoints::Gemini: request_tokens 42 response_tokens 9
```
So switching it around to off by default. `DISCOURSE_AI_NO_DEBUG` ->
`DISCOURSE_AI_DEBUG`.
t/159704/34
- Skip seeded LLMs from health checks
- Detect and ignore rate limit errors (429, 503, quota exceeded)
- Use framework retry mechanism (max_retries, retry_after, max_blips)
- Remove blocking sleep calls that could tie up Sidekiq workers
- Add transient error detection for network timeouts
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.
Minor follow-up to 20552f0 — posts were still being skipped if the user
is a bot, this will process the posts even if they're from a bot as long
as `allow_system_posts` is true
This removes the option for the AI bot button to trigger a new PM in the
composer and makes the dedicated /discourse-ai/ai-bot/conversations
route the default for everyone.
This splits the Login and Authentication admin page into multiple
sections: Settings, social logins, DiscourseConnect, OAuth2.0, OIDC.
Internal ticket `t/161648`
This PR also adds a new extension point for plugins that want to extend
this area of the app.
```
register_site_setting_area("oauth2")
register_admin_config_login_route("oauth2")
```
Adding this to a plugin allows it to extend both the setting areas
(existing functionality) and add a tab to this admin settings screen via
`register_admin_config_login_route`.
This commit refactors code that previously relied on Ember's deprecated array `toArray` method.
- Replaces all usages of `toArray` with native JavaScript array conversion
- Ensures compatibility with newer Ember versions
I want to use the AI llm_tagger script on
https://discover.discourse.com, but in order to do this the automation
needs to be allowed to run on posts created by the system user.
To accomplish this, I've added the ability for scripts to add a
`allow_system_posts` setting. Existing scripts will still ignore system
posts, but this allows script authors to add a setting to opt-in to
processing them.
These automation setups use a full-fledged editor where you can toggle between markdown and rich editing, but they don't have the logic that the composer comes with, that decides whether to display the preview or not, so it still (incorrectly) displays the preview when rich editor mode is selected.
This PR restricts the editor to just rich mode, and disables the preview.
This change ensures that oneboxes, lightboxes are correctly generated
for localized posts.
The `PostLocalizer` was using `PrettyText.cook` directly, which does not
perform all the necessary post-processing steps, such as onebox
generation.
This commit introduces a new `LocalizedCookedPostProcessor` class that
is responsible for post-processing the cooked HTML of translated posts.
This new class reuses the `CookedProcessorMixin` to gain access to the
`post_process_oneboxes` method. The `PostLocalizer` is updated to use
this new processor, ensuring that oneboxes are correctly generated in
the translated content.
---------
Co-authored-by: Nat <natalie.tay@discourse.org>
This updates /admin/plugins/discourse-ai/ai-translations so that:
1. We don't show the count for locale detected, we had some feedback
that this was just confusing. Too much of "how the sausage is made."
2. Clarifies some text
* instead of showing the number of posts with locale detected, we just
say "There are N posts eligible for translation."
* Clarifying "backfilling is disabled" to "Backfilling is disabled, only
new posts will be translated."
3. Adds a toggle to enable the feature instead of navigating to the
settings page... this is similar to the AI Spam toggle
4. I was confused when initially trying the plugin, because I didn't
have `Content localization supported locales` configured, and we didn't
mention it. I've added the ability to set this setting from the
translation page when it's not configured, which should help people
successfully set it up without having to bounce around different admin
pages. Adding languages here also toggles on `Content localization
enabled`
5. Added relevant specs
Before:
<img width="1698" height="440" alt="image"
src="https://github.com/user-attachments/assets/2b9d62c3-f400-40b7-903c-712a7dd55031"
/>
<img width="1718" height="596" alt="image"
src="https://github.com/user-attachments/assets/958b044e-6f92-4739-8108-36f195b389a0"
/>
After:
With no locale configured... the toggle to enable is disabled
<img width="1698" height="708" alt="image"
src="https://github.com/user-attachments/assets/35c69496-284c-4973-a5b2-42662d11b9b7"
/>
We can then add the locales, and once saved the toggle becomes active...
<img width="1706" height="562" alt="image"
src="https://github.com/user-attachments/assets/d4624f7e-50f2-41d3-95fd-57d836e25429"
/>
And now it's toggled on...
<img width="1704" height="706" alt="image"
src="https://github.com/user-attachments/assets/b7ca7e1e-798d-447e-98aa-e7e3f25ed1ff"
/>
The scroll momentum bug has apparently been fixed in iOS 26, given it's
not preventing usage prior to this fix we are just fully removing the
hack.
https://bugs.webkit.org/show_bug.cgi?id=262287
It was using `WebMock.allow_net_connect!`, which doesn't completely
disable WebMock's stubbing. In the logs of our flaky failures,
backtraces point to the webmock internals.
`WebMock.disable!` is more comprehensive, and matches what we do for
other core specs which need to bypass it.
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.
When a post is edited, avoid re-flagging it if there’s already a flag
pending in the review queue. This prevents duplicate triage runs and
reduces unnecessary processing.
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>
Now that `ServerSession` can store arbitrary data, we can move some more
data into it.
This patch moves some data related to authentication into it, as
sometimes that kind of data can be pretty big.
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>