This was a regression introduced in
f0069a4fab where clicking on an email
log's subject link did not open a modal that displays the details of the
incoming email.
In this commit, the following changes were also made:
1. Make all `admin-email-logs/*` routes inherit from the same parent
route.
Having two different parent routes doing the same thing was probably
something that was missed in the refactor previously.
Replaces deprecated usage of the Ember's native array extension `.any()`
function with `.some()` across several JavaScript files in the project.
This is a purely refactoring change intended to modernize the codebase
to follow current JavaScript standards.
**Main Changes:**
* Replaced .any() with .some() for array handling in 25 instances across
various files.
* Updated deprecation workflow to handle the any() and related
deprecations explicitly.
* Replace uses of Ember’s deprecated array extension .replace with
native .splice, using TrackedArray where reactivity is needed
(components and tests)
* Modernize TopicController computed properties to getters with
@dependentKeyCompat to preserve reactivity without Ember array
extensions
* Adjust history modal action signature to destructure the argument as
[bodyDiff]
* Add a deprecation-workflow entry for
discourse.native-array-extensions.replace to improve logging
* Add an Ember 6.6.0 patch to ensure isMutableArray excludes native
arrays, preventing false detection as MutableArray
The invite system uses the inviter's timezone to determine the
expiration time (see
0dd1ee2e09)
Now that DST change is less than 90 days away for me, the spec started
failing locally. We should update the spec to use the inviter's
timezone, just like core's own logic
This moves the logic for creating the convert_video job to the upload
after_create hook so that we ensure there is an upload_id. When this
logic
was in the s3 store and direct to s3 uploads was enabled the convert
video job
would never fire because we didn't have an upload_id.
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.
Addition to #34988:
* we also need to apply the new styling to the returning-user
* we need to keep the custom (= official) notices
* added a different background to the official notice
* update the settings copy to make this difference clear
- The menu item logic was incorrect as it was bypassing replacing emoji
if we already had a `safeString` object but in this case the emojis had
not been replaced yet. We now have the superior `replaceEmoji` pattern
which will handle this complexity correctly.
- `replaceEmoji` was not called in `bookmark-list`
1. Use relative paths instead of absolute. This will make the commands
portable to other machines, and matches the out-the-box behavior of the
regular rspec command
2. Strip out some 'infrastructure' ENV and params from the
rerun_command, so that it's easier to copy/paste and run locally
Loading the controller and its template causes a request to `hp.json`,
which can then trigger a race condition with `/session/csrf.json` if an
external auth is in-progress. This commit updates the redirect behavior
so that the the `beforeModel` hook never resolves, and therefore the
transition remains in a pending state until the redirect updates
`window.location`.
This also improves the UX, since there is no need for a flash of a
loading spinner. Instead, the normal route transition animation will
keep running until the redirect is complete.
Our current release process involves pushing two commits to `main`
simultaneously. The first is tagged `beta`, and then the second begins
the new `-latest` cycle for the next beta version. Since they're pushed
together, GitHub only triggers a single 'push' event for the most recent
commit.
This commit updates the publish-assets workflow so that it's also
triggered when the `beta` tag is attached to a new commit. That'll
ensure that assets are built & published for that specific commit, which
is accessible via the `beta` tag and the version-specific tags.
In the `SiteSettingExtension`, when calling
`SiteSetting.send(:setting_name, value)`,
if the setting counts as a global one, we add it to the list of hidden
and shadowed site settings in memory. However, when using the
`global_setting` helper in specs, we were not cleaning up these
overrides after the spec finished, leading to potential flakiness
in tests that rely on the visibility of site settings.
The fix is to just remove the setting from the hidden and shadowed
list after the spec is done.
When fetching voters from the `/polls/voters.json` API endpoint, each
page after the first has an extra voter (the last one from the previous
page). This causes duplicate voters to be returned if loading multiple
pages. This PR fixes the off-by-one error that causes this. (This fix
has initially been proposed by Rob Mackenzie.)
The PR also fixes an issue that could cause non-deterministic ordering
of results from that API; however, I have not been able to craft a test
to reproduce the issue, so the fix is theoretical.
Reported here:
https://meta.discourse.org/t/polls-voters-json-returning-duplicate-users-across-paged-requests/376636
Covers default reactions,
`discourse_reactions_experimental_allow_any_emoji`,
`discourse_reactions_enabled_reactions`, and interaction with the
`emoji_deny_list` setting from core.
---------
Co-authored-by: Jarek Radosz <jradosz@gmail.com>
When a bold font is used within a `b` tag, some browsers will apply a
faux bold that's *too* bold — since we're already applying a bold
font-weight in CSS we don't need these `b` tags anyway
too bold:
<img width="400" alt="image"
src="https://github.com/user-attachments/assets/731dee00-d3bd-41a2-9c19-c6104c9edcf5"
/>
## 🔍 Overview
This PR adds bulk selection functionality to the PostList component and
implements optimized bulk deletion for the drafts page. Users can now
select multiple drafts and delete them all at once with a single network
request, significantly improving performance and user experience.
The implementation includes:
- A new reusable bulk selection system for PostList components
- Optimized bulk delete endpoint that reduces network requests by 90%
- Comprehensive bulk controls UI with select all/clear all functionality
- Shift+click range selection similar to topic lists
- Complete test coverage for all new functionality
## ➕ More details
**Bulk Selection System**
The PostList component now supports optional bulk selection through
these new parameters:
- `@bulkSelectEnabled={{true}}` - Shows checkboxes next to each post
- `@bulkSelectHelper={{helper}}` - Manages selection state (use
`PostBulkSelectHelper`)
- `@bulkActions={{actions}}` - Array of bulk action objects for the
dropdown menu
**Usage Example:**
```gjs
import Component from "@glimmer/component";
import { action } from "@ember/object";
import didUpdate from "@ember/render-modifiers/modifiers/did-update";
import PostBulkSelectHelper from "discourse/lib/post-bulk-select-helper";
export default class MyComponent extends Component {
bulkSelectHelper = new PostBulkSelectHelper(this);
constructor() {
super(...arguments);
// Initial updatePosts call
this.updateBulkSelectPosts();
}
@action
updateBulkSelectPosts() {
if (this.shouldEnableBulkSelect && this.args.posts) {
this.bulkSelectHelper.updatePosts(this.args.posts);
}
}
get showBulkSelectHelper() {
return this.shouldEnableBulkSelect ? this.bulkSelectHelper : null;
}
get bulkActions() {
return [
{
label: "delete_selected",
icon: "trash-can",
action: this.handleBulkDelete,
class: "btn-danger"
}
];
}
<template>
<PostList
@posts={{@posts}}
@bulkSelectEnabled={{this.shouldEnableBulkSelect}}
@bulkSelectHelper={{this.showBulkSelectHelper}}
@bulkActions={{this.bulkActions}}
{{didUpdate this.updateBulkSelectPosts @posts}}
/>
</template>
}
```
**Performance Optimization**
The drafts page now uses a new bulk delete endpoint (`DELETE
/drafts/bulk_destroy`) that:
- Processes multiple drafts in a single HTTP request instead of N
individual requests
- Uses database transactions for atomic operations (all-or-nothing)
- Reduces database queries from 2N to 2 total queries
- Validates draft sequences upfront to fail fast on conflicts
**Technical Implementation**
- `PostBulkSelectHelper`: New helper class for managing selection state
with support for individual selection, range selection (shift+click),
and bulk operations with reactive posts tracking
- `PostListBulkControls`: New component providing selection count,
select all/clear all buttons, and bulk actions dropdown
- Enhanced PostList and PostListItem components with conditional bulk
selection UI
- Updated user-stream component to use optimized bulk deletion with
automatic selection cleanup
- Comprehensive styling with responsive design
**API Changes**
- New controller action: `DraftsController#bulk_destroy`
- New route: `DELETE /drafts/bulk_destroy`
- New JavaScript method: `Draft.bulkClear(drafts)`
- Enhanced `PostBulkSelectHelper` with `updatePosts()` method for
reactive data updates
- Fully backward compatible - existing single delete functionality
unchanged
**Testing**
- 9 new controller specs covering bulk deletion edge cases, validation,
and API access
- 11 integration tests for PostList bulk selection functionality
- 10 system specs for end-to-end drafts page bulk selection workflows
- All existing tests continue to pass
## 📹 Screen Recording
https://github.com/user-attachments/assets/2d5a9b38-f1cb-43ee-88ac-285b71083612
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.