This commit is a follow up to b02bc707dec12c607511d4a95c7d791f63131b49.
When the `s3_enable_access_control_tags` site setting is enabled,
calling `FileStore::S3Store#update_access_control` will result in a
argument error.
This commit introduces a new property `hasNoPreferredMode` to the
chat state manager, which represents a user who has not purposely
set chat mode to drawer or full page, meaning they have no LocalStorage
value set.
This can be useful for themes to change the chat mode but only
if the user has no preference already.
c.f.
https://meta.discourse.org/t/full-screen-chat-as-default-for-collaboration-setup/369849
Before this change, we were relying on the `lograge`'s gem default
`log_level` of `info`. However, `lograge` should be following
`Rails.application.config.log_level` instead and this commits seeks to
correct that behaviour.
### What I changed
- Wrapped the theme title and the pencil icon in a single `DButton` so
the whole thing is clickable
- Added ARIA stuff: heading role, level, and label to help screen
readers know it’s both a title and editable
### Why
Changed it so the entire title acts as the edit trigger, instead of just
the icon.
[Kapture 2025-06-13 at
16.34.12.webm](https://github.com/user-attachments/assets/c44049a0-bfd0-455a-94a3-fe9ec4d387ff)
A new `<InterpolatedTranslation>` component for interpolating components into translatable strings.
This change also includes a little bit of refactoring in the `i18n` library to make it easier to hook into.
The current way mentions are prioritised when trying to autocomplete
(with the `@` character in composer and some other search interfaces),
it's fairly easy for the list of suggestions to get crowded out by
seemingly unrelated suggestions as users that match on metadata are
prioritised in front of all groups.
The existing order of prioritisation:
1. All users that match (even partially) on usernames, names, metadata
2. Emails
3. Groups
This PR changes the order of prioritisation to favour the following in
order:
1. Exact match on User usernames
5. Exact match on Group names
6. Emails (this is kind of a special case, we don’t allow the ‘@’
character in usernames or group names anyway, but we do want to include
it here to easily adhere to the suggestion list limit)
7. Partial match on User usernames
8. Partial match on Group names
9. Exact match on User names
10. Partial match on User names
11. Users with matching metadata
Previously, a mention autocomplete with no matching entities would at
minimum return groups viewable by the user, this change also removes
that so it's a stricter autocomplete.
We recently added validation for mentions in rich text editor mode of
composer in #32879.
In an effort to eliminate potential edge cases for non-text nodes, I
have restored the input rules and simplified the approach used in the
plugin code.
This change means that Instead of finding and inserting mention nodes
within text while the user is typing, we let the input rules handle the
mention node creation part. This allows the plugin code to focus
entirely on validating nodes within the document.
As part of this change we introduced a new data attribute ("data-valid")
which will assume by default that mentions are valid and therefore be
"true", but will proceed to invalidate them by changing to false for
mentions that were not found. It also means that invalid mentions are
retained as mention nodes, whereas previously we would convert them to
text.
When uploading > 1 video in the composer, any upload after
the first one would fail silently, and not show anything in
the composer.
This was happening because we were removing uploads before the video
thumbnail callback was fired, but that had code like this `if
(this.#inProgressUploads.length === 0) { this.#reset() }`, which meant
that before the second upload was completely done we were resetting the
state.
Instead, we can remove the in progress upload file inside the video
thumbnail callback, which will ensure that the state is not reset
until all uploads are done.
This commit introduces a `s3_enable_access_control_tags` site setting
which,
when enabled, adds a `discourse:acl` tag with values `public` or
`private` to
S3 objects created by the application. The presence of the tags on S3
objects
enables bucket administrators to implement tag-based access control
policies, providing an alternative to
object ACLs which AWS now discourages.
The `discourse:acl` tag can be customized via the
`s3_access_control_tag_key ` site setting.
Values for `public` and `private` can also be customized via the
`s3_access_control_tag_public_value` and
`s3_access_control_tag_private_value ` site settings respectively.
### Reviewer Notes
To test it locally, run the following commands in your working discourse
directory:
1. `script/install_minio_binaries.rb`
2. Start a local minio server by running: `bundle exec rails runner
script/local_minio_s3.rb`
3. bundle exec rails runner "SiteSetting.enable_s3_uploads = true"
5. Start your development rails server with the following environment
variables: `DISCOURSE_ENABLE_S3_UPLOADS=true
DISCOURSE_S3_ENABLE_ACCESS_CONTROL_TAGS=true
DISCOURSE_BACKUP_LOCATION=s3`
This commit makes the "Color palettes" link in the admin sidebar points to
the new color palettes page at `/admin/config/colors` instead of the
legacy one `/admin/customize/colors` if the experimental feature flag
for the improved color palette system is enabled.
The filtering is currently being done in the controller. This leads to weird things where the filter loop might already be initiated and we get double filtering, as well as the issue that we can't abort like we could with a route transition.
After this change we:
- Cache the site settings fetched from the server in the route instance.
- Hook up the controller to the query params.
- Use the query params to filter the model in the route.
When uploading videos in chat using Safari the thumbnail isn't being
displayed
so we need to trick the browser to by adding the timestamp property so
that it
will fetch the metedata the html5 video tag needs to render the
thumbnail.
This allows date based filters to use a count of days as well as the
existing date string system (`YYYY-MM-DD`). This is convenient if you
want a dynamic list based on the current date, you could use:
`created-after:7` to return topics from the past week.
This will work for:
- created-before/after
- activity-before/after
- latest-post-before/after
This also makes filters consistent with our existing query params like
`?before=7`
This came up in:
https://meta.discourse.org/t/creating-a-custom-filter-homepage/370062
and is something that we mentioned internally while defining our domain
specific language for the /filter route, but never implemented.
This adds sets of CSS button variables that can be overridden in themes.
This won't change any default styles, but just provides a less
problematic method of customization.
The current suggested way of doing this is with SCSS like so:
```scss
.btn-default {
@include btn(
$text-color: var(--tertiary),
$bg-color: var(--secondary),
$icon-color: var(--tertiary-high),
$hover-text-color: var(--tertiary),
$hover-bg-color: var(--tertiary-very-low),
$hover-icon-color: var(--tertiary)
);
}
```
The trouble with this is that it brings along _all_ the btn mixin
styles, so you also end up re-setting things like this, in addition to
changing colors:
```scss
.btn-default {
display: inline-flex;
align-items: center;
justify-content: center;
margin: 0;
// and also the colors
}
```
That can problematic because it can override existing button styles
(e.g., if you already altered a single instance of margin). With these
new CSS custom properties, you can avoid this by doing:
```css
:root {
--d-button-default-text-color: var(--tertiary);
--d-button-default-text-color--hover: var(--tertiary);
--d-button-default-bg-color: var(--secondary);
--d-button-default-bg-color--hover: var(--tertiary-very-low);
--d-button-default-icon-color: var(--tertiary-high);
--d-button-default-icon-color--hover: var(--tertiary);
}
```
So now you can override the button colors without bringing along other
styles from the btn mixin.
I also removed an old `.btn.hidden` style, as we already apply
`!important` to the `.hidden` class elsewhere. Comments have also been
updated to pass our new linting rules.
Discourse has a fantastic feature whereby when installed as PWA (on
Android or Windows), you can share content to that Discourse from other
apps and browsers.
Currently when sharing a link to a Discourse PWA, it pre-populates a
draft Topic body with the link.
Whilst this is really nice already, we can improve this further.
Currently, sharing a link to the body misses out on the auto-magic core
feature of pasting a link in the title which simultaneously hydrates a
title from the og tag and creates a one-box in the body.
This PR remedies this whilst carefully maintaining the current behaviour
for text shares.
Documentation for the standard is here:
https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps/How_to/Share_data_between_apps
Demo of this working change is implemented in this plugin:
https://github.com/merefield/discourse-share-to-link-oneboxer
I added a test to check presence of share target in manifest endpoint.
Introduction of system themes. System themes are local themes which:
- Cannot be deleted;
- Cannot have “custom code” added, components only;
- Cannot have uploads;
- Cannot edit color palettes;
- Are updated on deploy, like core plugins.
This PR added the Foundation system theme, which is an empty theme like
Default. The Foundation theme will be added in the next PR.
In a development environment, when system theme files are
changed/added/deleted, the theme is reuploaded and the page is reloaded
to make it a good experience for the engineer working on improvements.
System themes are not visible until
`SiteSetting.experimental_system_theme` is enabled.
This commit adds a new option in the bookmark menu for existing
bookmarks that allows users to clear the bookmark reminder without
having to delete the bookmark or edit it manually.
## 🔍 Overview
Sometimes users may overlook that there is a post translations selector
when writing posts. This could lead to the site's default locale being
used when a post is written in the user's preferred language.
This update ensures that:
- the user's `effective_locale` is used as the default for the
`PostLanguageSelector` in the composer
- when the user's `effective_locale` is not one of the
`experimental_content_localization_supported_locales`, we default to
blank so that the `post.locale` doesn't get set
- we also allow for setting a "none" option in the language selector for
cases where the user wants to post in a language that is not part of
`experimental_content_localization_supported_locales`
## 📷 Screenshots
<img width="216" alt="Screenshot 2025-06-12 at 07 03 56"
src="https://github.com/user-attachments/assets/651b9387-de57-408f-9445-92501bd47567"
/>