* UX: Add new preview links to Popular Themes
Replace previews for 'Discourse' based ones
* prettier
---------
Co-authored-by: Jarek Radosz <jradosz@gmail.com>
There is currently only one scenario when both the composer and a user card would be present at the same time:
if you have the composer open and then you click on something outside it that triggers a card. Which implies intent to see the card (unobstructed by the composer 😉)
The reverse doesn't happen because opening the composer would close an existing user card.
In theory there's also displaying a user card by clicking on a mention in composer's preview but that functionality is currently broken (and this PR is a prerequisite 😉)
---
I changed `.user-card, .group-card` to `.fk-d-menu[data-identifier="card"]` because that regressed when we moved user cards to float-kit – they are nested inside `.fk-d-menu` so its `z-index` is now important (effectively the cards had `z-index: z("dropdown")` instead of `z("usercard")`)
Wasn't quite handling the cases where a closing bracket `]` was used in the value of one of the attributes.
```markdown
[chat quote=user channel="[broken]"]
```
Would not be correctly parsed because we would _greedily_ use the first `]` as the end of the tag even though it might be a valid character when inside proper quotes.
c39a4de139/app/assets/javascripts/discourse-markdown-it/src/features/bbcode-block.js (L62)
Re-wrote the `parseBBCodeTag` to properly handle the following cases
- A closing tag (aka `[/name]`) which are easy since they don't have any attributes
- An old `[quote=...]` format we used that doesn't uses quotes but still has various attributes of the form `key:value`
- All three valid BBCode opening tag formats we support
- `[name]` without any attributes
- `[name=foo]` with a default value
- `[name foo=bar]` with some attributes
Ended up having to fix/rewrite the few bbcode rules that were using the `parseBBCodeTag` function, namely `d-wrap` and `discourse-local-dates`.
While working on this, I think I also found a way to get rid the of shims we had in place so that plugins could use the `parseBBCodeTag` function.
Reference - https://meta.discourse.org/t/having-a-right-bracket-in-a-channel-name-breaks-all-quotes-from-that-channel/308439
* Load search results in displayed order so that when more categories are loaded on scroll, they appear at the end,
* Limit the number of subcategories that are shown per category and display 'show more' links,
This allows modifyClass to be used like this:
```
api.modifyClass(
"model:topic",
(Superclass) =>
class extends Superclass {
static someStaticMethod() {
return `${super.someStaticMethod()} modified`;
}
someFunction() {
return `${super.someFunction()} modified`;
}
get someGetter() {
return `${super.someGetter} modified`;
}
}
);
```
One limitation, which is the same as the old object-literal syntax, is that native class fields and constructors cannot be modified.
`@tracked` properties can be overriden, because the decorator turns them into getters/setters.
There is no need to pass a `pluginId` any more. Changes are automatically rolled back as part of test cleanup 🎉
* use `TrackedSet` instead of `@tracked []`
* correct return type annotations
* move code to outside Promise blocks where possible
* fix an outdated comment
When we turn on settings automatically for customers,
we sometimes use `.set_and_log` which will make a staff
action log for the site setting change. This is fine, but
there is no context for customers.
This change allows setting a message with `.set_and_log`, which
will be stored in the `details` column of the staff action log
created, which will show up on `/admin/logs/staff_action_logs`
---------
Co-authored-by: Kelv <kelv@discourse.org>
This commit introduces the `valueTransformer`API to safely override values defined in Discourse.
Two new plugin APIs are introduced:
- `addValueTransformerName` which allows plugins and theme-components to add a new valid transformer name if they want to provide overridable values;
- `registerValueTransformer` to register a transformer to override values.
It also introduces the function `applyValueTransformer` which can be imported from `discourse/lib/transformer`. This function marks the desired value as overridable and applies the transformer logic.
How does it work?
## Marking a value as overridable:
To mark a value as overridable, in Discourse core, first the transformer name must be added to `app/assets/javascripts/discourse/app/lib/transformer/registry.js`. For plugins and theme-components, use the plugin API `addValueTransformerName` instead.
Then, in your component or class, use the function `applyValueTransformer` to mark the value as overridable and handle the logic:
- example:
```js
export default class HomeLogo extends Component {
@service session;
@service site;
...
get href() {
return applyValueTransformer("home-logo-href", getURL("/"));
}
```
## Overriding a value in plugins or themes
To override a value in plugins, themes, or TCs use the plugin API `registerValueTransformer`:
- Example:
```js
withPluginApi("1.34.0", (api) => {
api.registerValueTransformer("example-transformer", ({ value }) => {
return "new-value";
});
});
```
We were using `autoclose` as the topic status update
when silently closing topics using the bulk
actions (introduced in 0464ddcd9b).
However, this resulted in a message like this showing in
the topic as a small moderator post:
> This topic was automatically closed after X days.
This is not accurate, the topic was bulk closed by someone.
Instead, we can use `closed` as the status, and a more accurate
> Closed on DATE
message is used. `TopicStatusUpdater` needed an additional
option to keep the same "fake read" behaviour as autoclose
so we can keep the same functionality for silently closing
topics in bulk actions.
This commit extracts the content of the `HomeLogo` to a standalone
component. This enables us to utilize the `home-logo-contents` plugin
outlet to render an alternative version of the logo using the new
component to reuse the rendering logic, but using alternative
properties. For example:
```js
const logoSmallUrl = settings
.theme_uploads["theme-alternative-logo-small"];
const logoUrl = settings.theme_uploads["theme-alternative-logo"];
const mobileLogoUrl = settings
.theme_uploads["theme-alternative-logo"];
api.renderInOutlet("home-logo-contents", <template>
<HomeLogoContents
@logoSmallUrl={{logoSmallUrl}}
@logoUrl={{logoUrl}}
@minimized={{@outletArgs.minimized}}
@mobileLogoUrl={{mobileLogoUrl}}
@showMobileLogo={{@outletArgs.showMobileLogo}}
@title={{@outletArgs.title}}
/>
</template>);
``
decorator-transforms (https://github.com/ef4/decorator-transforms) is a modern replacement for babel's plugin-proposal-decorators. It provides a decorator implementation using modern browser features, without needing to enable babel's full suite of class feature transformations. This improves the developer experience and performance.
In local testing with Google's 'tachometer' tool, this reduces Discourse's 'init-to-render' time by around 3-4% (230ms -> 222ms).
It reduces our initial gzip'd JS payloads by 3.2% (2.43MB -> 2.35MB), or 7.5% (14.5MB -> 13.4MB) uncompressed.
This was previously reverted in 97847f6. This version includes a babel transformation which works around the bug in Safari <= 15.
For Cloudflare compatibility issues, check https://meta.discourse.org/t/311390
Inline the helper functions, avoid creating and then immediately destructuring arrays, use complete strings instead of string interpolation, Map instead of a pojo.
* FEATURE: Add Filter for Webhook Events by Status
* Fixing multiple issues
* Lint
* Fixing multiple issues
* Change the range of the status for webhook events
Really fully authored by Jarek, I only made the PR :)
The `DBreadcrumbItem` and `DBreadcrumbContainer` components
introduced in 1239178f49 have
some limitations, mainly that the container has no awareness of
its items, so nothing that requires positional knowledge can
be used. This is needed to use `aria-current` on the last breadcrumb
item, see https://www.w3.org/WAI/ARIA/apg/patterns/breadcrumb/examples/breadcrumb/.
We change `DBreadcrumbItem` to always be a link, removing
the need for `LinkTo`. Then, we introduce a service to keep
track of containers and items (since all items are rendered into
all containers) and make the item itself responsible for registering
to the service, and introduce the needed `aria-current` behaviour.
---------
Co-authored-by: Jarek Radosz <jradosz@gmail.com>
We want to get rid of the old topic bulk actions modal
and use the new dropdown (currently gated behind
experimental_topic_bulk_actions_enabled_groups). To do
this we need to use the new dropdown in all places in the
UI.
This commit changes the full page search UI to use the new
topic bulk actions dropdown if experimental_topic_bulk_actions_enabled_groups
is enabled, and makes some minor refactors to make this work.
Also add a spec for both the old and new functionality.
# Description
Add `addCustomUserFieldValidationCallback` to the user fields validation mixin. This allows you to add a custom validation when checking the validity of custom user field values in the signup form on submit.
```js
addCustomUserFieldValidationCallback((userField) => {
if (userField.field.name === "my custom user field" && userField.value === "foo") {
return EmberObject.create({
failed: true,
reason: I18n.t("value_can_not_be_foo"),
element: userField.field.element,
});
}
});
```
In the case your custom validation deems an input value `failed`, you return an EmberObject with the fields `failed: true`, `reason`, and `element`.
```js
return EmberObject.create({
failed: true,
reason: I18n.t("value_can_not_be_foo"),
element: userField.field.element,
});
```
which will then display your custom `reason` to the user attached to the given user custom field input and will not submit the signup form.
<img width="288" alt="Screenshot 2024-06-06 at 11 08 40 AM" src="https://github.com/discourse/discourse/assets/50783505/11168fb8-8806-43f0-9417-73991bbd1178">
# Other
- Add `addCustomUserFieldValidationCallback` to the plugin api
- Bump plugin api version
- Update plugin api changelog
- Add tests
For cases where you'd be using a TrackedSet to render something and then modifying that set throughout the same render cycle. (specifically it will be used in #27365)
This commit introduces the initial UI for the admin config area for the /about page. The UI isn't wired and doesn't do anything yet, but we're going to iterate on it in future commits.
Internal topic: t/128544.
This commit fixes a problem where the user will not be able to reset
their password when they only have security keys and backup codes
configured.
This commit also makes the following changes/fixes:
1. Splits password reset system tests to
`spec/system/forgot_password_spec.rb` instead of missing the system
tests in `spec/system/login_spec.rb` which is mainly used to test
the login flow.
2. Fixes a UX issue where the `Use backup codes` or `Use authenticator
app` text is shown on the reset password form when the user does
not have either backup codes or an authenticator app configured.
Followup 0434112aa7,
when I introduced the pluralisation for the
password.too_short message I didn't change the
key name to `count`, which is necessary.
This commit includes various UX improvements to the reset
password page:
* Introduce a `hide-application-header-buttons` helper to do the following:
* Hide Sign Up and Log In buttons, they are not necessary on this flow
* Hide the sidebar, it is a distraction on this flow
* Improve messaging when a 2FA confirmation is required first
* Improve display of server-side ActiveRecord model validation errors
in password form, e.g. instead of "is the same as your current password"
we do "The password is the same as your current password"
* Move password tip to next line below input and move caps lock hint
inline with Show/Hide password toggle
* Add system specs for 2FA flow on reset password page
* Fixes a computed property conflict issue on the password reset
page when toggling 2FA methods
Continued work on moderate flags UI.
In this PR admins are allowed to change the order of flags. The notify user flag is always on top but all other flags can be moved.
This reverts commit 0b10e335ae.
I realised that some of these actions are overridden in themes/plugins, so this is going to cause problems (especially because modifyClass doesn't currently work well with the `@action` decorator)
This makes it more obvious what's happening, and makes it much less likely that users will send repeated reset emails (and thereby hit the rate limit)
Followup to e97ef7e9af
Even when the admin sidebar sections are collapsed, they should expand while filtering. When the filter is removed, sections should go back to the previous state.
In addition, trim whitespace from the filter section.
Only remaining ones are `routes/discourse.js` and `routes/application.js`. Those two both contain legacy `actions: {}` hashes which need to be updated before being converted to native class syntax.
This commit removes the `/admin-revamp` routes which were introduced as a part of an experiment to revamp the admin pages. We still want to improve the admin/staff experience, but we're going to do them within the existing `/admin` routes instead of introducing a completely new route.
Our initial efforts to improve the Discourse admin experience is this commit which introduces the foundation for a new subroute `/admin/config` which will house various new pages for configuring Discourse. The first new page (or "config area") will be `/admin/config/about` that will house all the settings and controls for configuring the `/about` page of Discourse.
Internal topic: t/128544
This commit re-introduces the "Move to Inbox" and "Move to Archive"
bulk topic actions, which we had in the old modal but had not yet added
to the new "experimental" dropdown, which isn't really experimental at
this point.
Once this is merged we can remove the old modal and only
rely on the new dropdown.
The issue was simple, we were just not returning the helper in the `user-private-messages` controller which was preventing any action to happen.
Follow up: we should write specs for this toggle.
Prior to this fix we were opening a modal before closing the `DMenu` modal, given `DModal` expects only one modal at a time it was closing the latest modal and instantly closing the one we just opened.
This adds a small indicator of the Ctrl+/ shortcut that
exists for the admin sidebar filter, since it's not very
obvious that you can do that. This should help people
who are struggling with the long list of links -- it's
much faster to use the keyboard and search for what
you are looking for.
Followup 73c6bb2593
The admin sidebar was also disappearing on another
child admin route (in this case the docker_manager
plugin update page). Instead of relying on the route
name which is flaky, we can set a boolean when the
sidebar is forced in the root admin route, then
turn it off when leaving admin.
When uploading a video, the composer will now show a thumbnail image in
the composer preview instead of just the video placeholder image.
If `enable_diffhtml_preview` is enabled the video will be rendered in
the composer preview and is playable.
Delay rendering sidebar sections after sidebar is shown
Showing the popup takes about 100ms, then rendering each section
could take up to and additional 200ms, which leaves the total just
outside of 300ms. If we cheat by rendering the popup first then
the sections in the next frame, it improves our paint time
Introduce DeferredRender to encapsulate 'paint later'
This uses a new nav style with the heirarchy:
```
Breadcrumbs
|- Title
|- Description
|- Third-Level Navigation
```
The navigation bar uses the transparent red-underlined
buttons similar to the user activity page.
Over time all admin pages will use this, but this starts
with the new plugin show page.
---------
Co-authored-by: Ella <ella.estigoy@gmail.com>
We need to register a waiter so that `settled()` will wait for `runAfterFramePaint()` callbacks to be run before proceeding.
Re-lands 63b7b598cb, but wrapped with `isTesting()` to avoid production errors.
# Context
We currently have a tracked value of `topic` in the header service that we utilize across the app for determining the presence of a topic.
A simple example is: If you are in a topic, and scroll down the page, we need to communicate to the header that a topic is present and we change the styling of the header.
The issue with this logic is that when entering a topic (and you are at the top of the page), we **haven't** set the topic on the header service yet. We only set the topic when you have scrolled down on the page (set by `app/components/discourse-topic.js`)
This is unhelpful behavior when you are utilizing a plugin outlet that is receiving the `topic` from the header:
17add599e3/app/assets/javascripts/discourse/app/components/header/topic/info.gjs (L85)
As the `topic` won't be present until you scroll down the page.
# Changes
This PR adds a tracked `inTopic` value to the header service that is a boolean value. This is to let the app know
> Yes, we are scrolled within a topic
And instead sets the tracked `topic` value immediately, if you are loading a topic, to allow the necessary data to be populated to the plugin outlets on page load.
Previously, avatars would be 'sticky' when:
1. The post was longer than the viewport
OR
2. You were scrolling up
The difference in behavior based on scroll direction doesn't 'feel' quite right. This commit makes the behavior consistent, so sticky avatar logic is applied to all posts regardless of scroll direction.
Prior to this fix we had too logic to detect if a user is active or not:
- idle codepath on the frontend
- online user ids on the backend
The frontend solution is not very reliable, and both solution are just trying to be too smart. Making a lot of people questioning why they receive a notification sometimes and sometimes not. This commit removes all this logic and replaces it with a much more simpler logic:
- you can't receive notifications for channel you are actually watching
- we won't play a sound more than once every 3seconds
When selected some text inside a post, we offer the ability to "fast edit" the selected text without opening the composer.
However, there are certain cases where this isn't working quite a expected, due to the fact that we have some text in the "cooked" version of the post that isn't literally in the "raw" version of the post.
This ensures that whenever someone selects the within
- a quote
- a onebox
- an encrypted message
- a "cooked" date
we directly show the composer instead of showing the fast edit modal and then leaving the user with an invisible error.
Internal ref. t/128400
* FIX: When creating new message via URL do not redirect
If a user clicks on `/new-message` route from inside the instance we're
redirecting the user to `/latest` page which is only intended if the
user is coming from an external site. This commit checks for this
condition and only redirects when user is coming from external source.
This also makes the behavior consistent with `new-topic` route.
Internal topic reference: `/t/-/129523/`
We consider that you should always receive a notification sound when someone speaks directly with you in chat.
This commit also refactors the way we play audio in chat to make it simpler and throttle it to 3 seconds.
We also added a safeguard to ensure we won't play sounds for old messages, this case can happen when message bus is catching up the backlog (eg: in an inactive tab for example).
* FEATURE: add agree and edit
adds agree and edit - an alias for agree and keep -- but with a client action to
edit the post in the composer before the flag is agreed with
---------
Co-authored-by: Juan David Martinez <juan@discourse.org>
We're planning to implement a feature that allows adding required fields for existing users. This PR does some preparatory refactoring to make that possible. There should be no changes to existing behaviour. Just a small update to the admin UI.
Before this fix when generating a pm path leading to a group messages inbox we would blindly take the first group of the pm, however, it's possible our current user doesn't have access to this group.
This commit will now try to find the first group the user has access to, and generate a path to this group’s inbox.
For plugins with only an "enabled" site setting, it doesn't
make sense to take them to the site settings page, since the
toggle switch in the list can be used to change enabled/disabled.
This will not be the case for plugins that have their own custom
config page (like Automation), but we will deal with this when
we actually overhaul this plugin to use the new show page.
Also adds another rspec fixture of a test plugin.
This PR aims to add bulk actions to the user's bookmarks.
After this feature, all users should be able to select multiple bookmarks and perform the actions of "deleting" or "clear reminders"
e.g. `unexpectedly found "! no whitespace ~" when slicing source, but expected " no whitespace "`
See: https://github.com/emberjs/ember.js/issues/19392
Co-authored-by: David Taylor <david@taylorhq.com>
- FIX: properly scope category changes to what the current user can see
- UX: previous category is now highlighted in "red", new category is highlighted in "green"
- PERF: no need to serialize the categories
- FIX: properly track wiki
- FIX: properly track post_type (aka. Staff Color)
- FIX: properly track making a topic a PM
- FIX: never show the category changes when a topic is made a PM
- PERF: post_revision serializer is now more leaner (never includes title changes when post_number > 1, never includes user changes if there aren't any)
- UX: always sort the tags by name
This commit reuses the existing codepath in desktop-notifications and make it available to use to chat.
primaryTab was too hard to test if not impossible in this service test, however isIdle and disabled notifications are correctly tested.
Followup 4e7a75a7ec
Several plugins (Gamification, AI) now use the new
plugin show route. Any plugins that are using it can
now redirect to this page via the Settings button in
the plugin list, rather than taking the user to the
old site settings page filtered by category.