The Problem
Clicking on a large image opens lightbox, however the new lightbox currently waits for the first image to finish loading before it finishes loading the lightbox UI correctly (ie. background color). This makes the visual experience feel broken.
Because open() is waiting for the image to load, it doesn't trigger the onOpen callback, which appends a .has-lightbox class to the html tag. The lightbox background color requires that css class to be set for the styles to be applied correctly.
The Solution
This PR prevents blocking when loading loading the first image (image that was clicked) within the lightbox, and therefore allows the css class to be appended to the html tag correctly and as a result fixing the styling issues.
The #setCurrentItem function is async and awaits the loading of preloadItemImages already, so the image will load correctly when complete despite the rest of the UI loading in advance.
The primary motivation is to simplify `eagerLoadRawTemplateModules` which curently introspects the module dependencies (the `imports` at runtime). This is no longer supported in Embroider as the AMD shims do not have any dependencies (since it's managed internally with webpack).
Prior to this commit the `setSiteThemeColor` could mistakenly receive a color with a leading `#` which would cause an invalid color to be send to `postRNWebviewMessage` and would eventually cause a crash if we try to interpolate between this color and another.
Using the lastViewedTopicId indiscriminately can cause strange scrolling behavior when navigating to a **different** topic list after viewing a topic. We only want to refocus the topic when going 'back' to the same topic list which originally triggered the navigation.
Previously we had three query parameters to control which tests would be run. The default was to run all core/plugin tests together, which would almost always lead to errors and does not match the way we run tests in CI.
This commit removes the three old parameters (skip_core, skip_plugins and single_plugin), and introduces a new 'target' parameter. This can have a value of 'core', 'plugins', 'all', or a specific plugin name. The default is 'core'. Attempting to use the old parameters will raise an error.
Previously we were implementing scroll reset/memorization on a per-page basis. Many of these approaches relied on the `didInsertElement` hook, which is no longer appropriate since Discourse changed to use the 'loading slider' strategy for page transitions.
This commit rips out all of our custom scroll resetting/memorizing, and implements those things in a generic service. There are two features:
1. After every route transition, scroll to the top of the page
2. When using browser back/forward buttons, restore the last known scroll position for those routes
To opt-out of the behaviour, individual routes can add a scrollOnTransition boolean to their RouteInfo metadata using Ember's `buildRouteInfoMetadata` hook.
The new lightbox was missing the tracked property for items when it was launched earlier as experimental feature flag.
This PR should fix issues experienced when the user clicks between multiple galleries causing the carousel images not to be updated as they were previously not tracked.
Why this change?
Prior to this change, dismissing unreads posts did not publish the
changes across clients for the same user. As a result, users can end up
seeing an unread count being present but saw no topics being loaded when
visiting the `/unread` route.
Why this change?
Group mention notifications are currently placed in the "Others" tab
of the user menu which is odd considering that mentioned notifications
are in the reply tab. This commit changes it such that group mention
notifications are displayed in the reply tab as well.
* FEATURE: Inline topic summary. Cached version accessible to everyone.
Anons and non-members of the `custom_summarization_allowed_groups_map` groups can see cached summaries for any accessible topic. After the first 12 hours and if the posts to summarize have changed, allowed users clicking on the button will automatically re-generate it.
* Ensure chat summaries work and prevent model hallucinations when there are no messages.
In the past, widget implementors would have to subclass the MountWidget component and wire up `didUpdateAttrs` or an observer to trigger a re-render. If that wasn't done, then it could lead to weird behaviors, especially now that page transitions in Discourse do not de-render/re-render components by default.
This commit updates MountWidget so that it re-renders whenever any input arguments change.
Browser capabilities are inherently unconnected to the lifecycle of our app. Making them formally available outside of the service means that they can safely be used in non-app-linked functions without needing risky hacks like `helperContext()` or `discourse-common/lib/get-owner`.
One example of where the old hacks were problematic is the `translateModKey()` utility function. This is called in the root of the `discourse/components/modal/keyboard-shortcuts-help` es6 module. If anything (e.g. a theme/plugin) caused that es6 module to be `require()`d before the application was booted, a fatal error would occur.
Following this commit, `translateModKey()` can safely import and access `capabilities` without needing to worry about the app lifecycle.
The only potential downside to this approach is that the capabilities data now persists across tests. If any tests need to 'stub' capabilities, they will need to revert their changes at the end of the test (e.g. by using Sinon to stub a property).
This commit also updates some legacy references from `capabilities:main` to `service:capabilities`.
These avatar-related helper functions are used in pretty-text, which currently means we load the entire `discourse/lib/utilities` module into the mini-racer when running pretty-text on the server side. This stops us adding any logic or imports to discourse/lib/utilities which may depend on other `discourse/` namespace features.
This commit moves the avatar-related utils into a dedicated module in the `discourse-common` namespace, adds backwards-compatibility shims, and updates the pretty-text config accordingly.
- Unify the silencing methods, use a WeakMap to remember the seen objects
- Export a proper plugin and use the absolute path in the config, instead
of the proprietary config from `broccoli-babel-transpiler`
The latter causes problems in Embroider which doesn't use the broccoli
based babel pipeline.
Some themes were doing `require("i18n").t()`, which was never recommended, but did work prior to f8483295. This commit restores that functionality with a deprecation notice.
What does this commit do??
This commit introduces two changes:
1. As a follow up review comment to
cc463c3e9b, we remove the top level
recipientNames cache in composer message to be a property of the
`ComposerMessage` component instead. Across components, we're more
likely to get a cache miss than a hit since we're caching the entire
recipient array so we can just drop it. If we really need this
optimisation, we should probably use a map and cache the information for
each user instead. However, the request is fairly cheap so we avoid that
optimisation for now.
2. This commit adds a debounce to `_typeReply` as well since we were not
debouncing and the method was being called each time we received the
event.
Why is this change being made?
We've decided that the previous "community" section should look more
like a primary section that holds the most important navigation links
for the site and the word "community" doesn't quite fit that
description. Therefore, we've made the decision to drop the
section heading for the community section.
As part of removing the section heading, the following changes are made
as well:
1. Button to customize the section has been moved to the "footer" of the
"More..." section when `navigation_menu` site setting is set to `sidebar`.
When `navigation_menu` is set to `header dropdown`, a button to customize
the section is shown inline.
2. The section will no longer be collapsable.
3. The title of the section is no longer customisable as it is no longer
displayed. As a technical note, we have not dropped any previous
customisations of the section's title previously in case we have to
bring back the header in the future.
4. The new topic button that was previously present in the header has
been removed alongside the header. Admins can add a custom section
link to the `/new-topic` route if there would like to make it easier for
users to create a new topic in the sidebar.
Generally follows the same pattern as #22520
There are some changes here, notably it uses the addon's babel
settings rather than the app's, and it goes through the same
treatment as the rest of the addon code (which may include more
than just babel).
However, this probably brings us closer to the normal expectations
you have around developing addon code, and in any case, does not
seem to have any effect on the final output:
```
$ diff dist/assets/markdown-it-bundle.js /tmp/dist-before/assets/markdown-it-bundle.js
```
* FIX: Default parameter recipients to create new message via params must be a string
The default parameter recipients was defined as an empty array in:
- route:application#createNewMessageViaParams
- mixin:open-composer#openComposerWithMessageParams
However, in model:composer, targetRecipient is handled as a string as can be
verified due to the existence of the #targetRecipientsArray computed property.
Using the default parameter defined as an array was causing issues with
the `discourse-bcc` plugin when opening the composer using the route
/new-message.
* DEV: Added tests for the composer messages for private messages
* Fix test naming
Co-authored-by: Mark VanLandingham <markvanlan@gmail.com>
---------
Co-authored-by: Mark VanLandingham <markvanlan@gmail.com>
Currently, the admin/wizard build relies on the addon build getting
triggered first, so that its `treeForAddon()` hook will be called,
and then it can stash the result on the app's options, which is
super fragile. In Embroider the timing works differently so the
trees end up being `undefined`.
This inverts the logic so that it will be discourse core's build
calling these hooks at a specific timing and return the result
rather than coordinating through the options bag.
```
$ diff dist/assets/admin.js dist-after/assets/admin.js
$ diff dist/assets/wizard.js dist-after/assets/wizard.js
```
Currently the I18n module shim return an object. Per AMD/loader.js,
the properties on the object becomes named exports of the module,
i.e. `import { t } from 'I18n';`.
However, this is not how we actually consume this module. We always
do `import I18n from 'I18n';`.
The returned object from the shim (`window.I18n`) does NOT have a
`default` property on it. This is only working because loader.js
has a `makeDefaultExport` feature that defaults to true, which we
are relying on to synthesize the default export for us.
That feature has been noted as undesirable and may some day be
deprecated. In Embroider, it specifically disables the feature in
loader.js.
https://github.com/embroider-build/embroider/issues/539
This commit also standardize the naming pattern of modals: `<Chat::Modal::FooBar />` and changes css class accordingly.
Co-authored-by: David Taylor <david@taylorhq.com>
When the loading slider is enabled, the rendering of `application.hbs` is slightly delayed compared to the old 'spinner' strategy. This means that if a route tried to render a dialog during its `model()` hook, the dialog wrapper element would not be present and an error would occur.
This commit detects that situation and delays rendering the error until the next runloop iteration. If the element is still not found, we print a useful error to the console.
In the long term, we should ideally convert the dialog service to use a pure-ember rendering strategy instead of leaning on a11y-dialog. But for now, this workaround should resolve the problems identified by the chat system specs.
This PR adds a feature to help admins stay up-to-date with their translations. We already have protections preventing admins from problems when they update their overrides. This change adds some protection in the other direction (where translations change in core due to an upgrade) by creating a notice for admins when defaults have changed.
Terms:
- In the case where Discourse core changes the default translation, the translation override is considered "outdated".
- In the case above where interpolation keys were changed from the ones the override is using, it is considered "invalid".
- If none of the above applies, the override is considered "up to date".
How does it work?
There are a few pieces that makes this work:
- When an admin creates or updates a translation override, we store the original translation at the time of write. (This is used to detect changes later on.)
- There is a background job that runs once every day and checks for outdated and invalid overrides, and marks them as such.
- When there are any outdated or invalid overrides, a notice is shown in admin dashboard with a link to the text customization page.
Known limitations
The link from the dashboard links to the default locale text customization page. Given there might be invalid overrides in multiple languages, I'm not sure what we could do here. Consideration for future improvement.
Follow-up to b27e12445d
This commit adds 2 new site settings `default_sidebar_link_to_filtered_list` and `default_sidebar_show_count_of_new_items` to control the default values for the navigation menu preferences that were added in the linked commit (`sidebar_link_to_filtered_list` and `sidebar_show_count_of_new_items` respectively).
Chat drawer was using the `DiscourseURL` hook `afterRouteComplete`. This hook suffer from a very poor implementation which makes it very unreliable:
```javascript
if (typeof opts.afterRouteComplete === "function") {
schedule("afterRender", opts.afterRouteComplete);
}
```
This commit attempts to return the promise from `handleURL` to directly use it and have a very reliable after transition hook.
This PR converts the following modals:
- `dismiss-new`
- `dismiss-read`
- `dismiss-notification-confirmation`
to make use of the new component-based API
# Additional Changes
## Before
By default we display a warning modal when dismissing a notification however we bypass the warning modal for specific notification types when they are a 'low priority' type of notification (eg. likes). To do this we were overwriting `dismissWarningModal` on a given notification type component
```javascript
dismissWarningModal() {
return null
}
```
but in the case we wanted to change the text within the modal we were calling `showModal` and then passing in the respective options all over again, putting the logic of rendering the modal in multiple places.
```javascript
dismissWarningModal() {
const modalController = showModal("dismiss-notification-confirmation");
modalController.set(
"confirmationMessage",
I18n.t("notifications.dismiss_confirmation.body.assigns", {
count: this._unreadAssignedNotificationsCount,
})
);
return modalController;
}
```
## After
I simplified this by adding an extensible `dismissConfirmationText` function that can be updated on a per component basis as that was the only option being overridden.
eg
```javascript
get dismissConfirmationText() {
return I18n.t("notifications.dismiss_confirmation.body.bookmarks", {
count: this.#unreadBookmarkRemindersCount,
});
```
This saves us from importing the entire modal again and keeps the core logic in one place.
Instead of overwriting the `dismissWarningModal` function and returning `null` to bypass the confirmation modal, I added another extension point of `renderDismissConfirmation` (defaults to true) to _toggle_ whether we should display a confirmation when dismissing notifications.
eg
```javascript
get renderDismissConfirmation() {
return false;
}
```
we utilize this in core for specific _low priority_ notification types. When you need the confirmation modal to be displayed no matter the case you can set `alwaysRenderDismissConfirmation` to `true`
```
get alwaysRenderDismissConfirmation(){
return true
}
```
This can be useful when you want to render the confirmation modal on a custom notification type that is not deemed as _high priority_, leading to the confirmation modal never being rendered.
You can see this in use in [Discourse Assign](https://github.com/discourse/discourse-assign/pull/481)
Followup to d51baa3bb3
Also includes: Force full rerender of post-stream widget when switching topics. This ensures that plugin/theme decorators are re-run when we switch between topics with the loading slider enabled.
Previously we were using the `didInsertElement` hook and querying the DOM to check whether the other button was visible. This is problematic from a performance point of view because it forces the browser to render the layout prematurely. It can also lead to subtle bugs based on the current scroll position.
In addition, having this logic on a `didInsertElement` hook makes it totally incompatible with the new 'loading slider' feature (because the component is not re-rendered between different topic lists).
This commit updates the logic to be based simply on the count of topics in the list. If there are fewer than 5 topics, the top button is hidden.
Under certain conditions, this `afterRender` hook can be triggered after the topic-list-item has been removed from the DOM. This is more likely when the 'loading slider' strategy is used on a site.
This introduces a PLATFORM_KEY_MODIFIER const that
can be used both client and server side, to determine
whether we should be using the Meta or Ctrl key based
on whether the user is on Windows/Linux or Mac.
Why this change?
A new component based API for modals was introduced in
b3a23bd9d6. This commit moves the edit
sidebar section modal to the new API.
Reviewer notes
No functionality or visual change is introduced in this PR.
In previous PR https://github.com/discourse/discourse/pull/22340 bug was introduced. Notifications were blocked when, even if topic was watched directly. New query is taking TopicUser into consideration.
In addition, in user interface, when `watched_precedence_over_muted` is not set, then value from SiteSetting should be displayed.
This brings the functionality from https://github.com/discourse/discourse-loading-slider into Discourse core. Default behaviour remains the same - the new slider mode can be enabled using the new 'page_loading_indicator' site setting.
A follow-up to 585a2e4e. A couple of tests with the new rich tooltip were flaky.
We suppose the reason is some problem related to widgets lifecycle. This PR
doesn't fix the issue, but isolates testing of the tooltip related logic related
inside its own test, which should make it not flaky.
This is a temporal solution, we're going to move all these code to using
glimmer components.
Previously, the `@model` argument would be unset before the component's `willDestroy` hook was called. Wrapping up the component and the opts in a single tracked `activeModal` field, and then using the `#each` helper with an array of 1 element means that Glimmer will keep the `@model` argument available until the end of the component's lifecycle.
Recently, site setting watched_precedence_over_muted was introduced - https://github.com/discourse/discourse/pull/22252
In this PR, we are allowing users to override it. The option is only displayed when the user has watched categories and muted tags, or vice versa.
What is the problem?
Before this change, we were relying on the `/tags` endpoint which
returned all the tags that are visible to a give user on the site leading to potential performance problems.
The attribute keys of the response also changes based on the `tags_listed_by_group` site setting.
What is the fix?
This commit fixes the problems listed above by creating a dedicate `#list` action in the
`TagsController` to handle the listing of the tags in the edit
navigation menu tags modal. This is because the `TagsController#index`
action was created specifically for the `/tags` route and the response
body does not really map well to what we need. The `TagsController#list`
action added here is also much safer since the response is paginated and
we avoid loading a whole bunch of tags upfront.
What is the problem?
This regressed in fe294ab1a7 and we did
not have any tests on mobile to catch the regression. The problem was
that we were conditionally rendering the edit nav menu modals component
in the sidebar. However, the sidebar is collapsed on mobile when a
button is clicked. When the sidebar collapses, the edit nav menu modals
ended up being destroyed with it.
Why this change?
A new component based API for modals was introduced in
b3a23bd9d6. This commit moves the edit
navigation menu tags and categories modal to the new API.
This allows us to use `getOwner(this)` on widgets (without needing to resort to our custom `discourse-common/lib/get-owner` implementation which has a hacky fallback)
`_self` is the default, so we should treat it the same as having no value specified. This fixes navigation to links like `/my/...` in custom sidebar links.
- Inline mentions on posts
- Inline mentions on chat messages
- The user autocomplete for the composer
- The user autocomplete for chat
- The chat section of the sidebar
Ember 4.x will be removing the 'named outlet' feature, which were previously relying on to render modal 'controllers' and their associated templates. This commit updates the modal.show API to accept a component class, and also introduces a declarative API which can be used by including the <DModal component directly in your template.
For more information on the API design, and conversion instructions from the current API, see these Meta topics:
DModal API: https://meta.discourse.org/t/268304
Conversion: https://meta.discourse.org/t/268057
What is the problem?
Before this change, the edit navigation menu tags modal was not
displaying tags that belonged to a tag_group when the tags_listed_by_group
site setting was set to true. This is because we are relying on the
/tags endpoint which returned tags in various keys depending on the
tags_listed_by_group site setting. When the site setting is set to
true, tags under belonging to tag groups were returned in the
extra.tag_groups attribute.
What is the fix?
This commit fixes it by pushing all tags in returned under the
`tag_groups` attribute into the list of tags to displayed. In a
following commit, we will move away from the `/tags` endpoint to a
dedicated route to handle the listing of tags in the modal.
]When changing fonts in the `/wizard/steps/styling` step of
the wizard, users would not see the font loaded straight away,
having to switch to another one then back to the original to
see the result. This is because we are using canvas to render
the style preview and this fails with a Chrome-based intervention
when font loading is taking too long:
> [Intervention] Slow network is detected. See
https://www.chromestatus.com/feature/5636954674692096 for more details.
Fallback font will be used while loading:
https://sea2.discourse-cdn.com/business7/fonts/Roboto-Bold.ttf?v=0.0.9
We can get around this by manually loading the fonts selected using
the FontFace JS API when the user selects them and before rerendering
the canvas. This just requires preloading more information about the
fonts if the user is admin so the wizard can query this data.
Motivation: aligning us with JS/Ember practices (runtime deps in `dependencies`, build/dev-time deps in `devDependencies`)
1. Move deps to devDeps where applicable (rule of thumb: it's a devDep unless it's required at runtime by the rails app or it's imported in the addon's code)
2. Remove unused dependencies and add missing ones (in addons)
3. Remove empty `repository` fields
4. Move `engines` and `ember` fields to the bottom
This reverts commit d8f0f17b50.
This causes errors when uploading to S3 because we are missing
a getFilesByIds function in core which we have not updated
yet c.f. https://github.com/discourse/discourse/pull/22195
Tests don't catch this because tests only try uploads.json
uploading.
Before this change, links which required full reload because they are not in ember routes like `/my/preferences` or links to docs like `/pub/*` were treated as real external links. Therefore, they were opening in self window or new tab based on user `external_links_in_new_tab` setting.
To be consistent with behavior when full reload links are in the post, they are treated as internal and always open in the same window.
Achieved by running `yarn upgrade --latest` both yarn.lock directories, then reverting changes to package.json files and running `yarn` again.
I also de-duped yarn.lock files with `npx yarn-deduplicate && yarn`
This is the first of a number of PRs aimed at helping admins manage their translation overrides. It simply adds a list of available interpolation keys below the input field when editing an override.
It also includes custom interpolation key.
Why this change?
We are currently not fully satisfied with the current way to edit the
categories and tags that appears in the sidebar where the user is
redirected to the tracking preferences tab in the user's profile causing
the user to lose context of the current page. In addition, the dropdown
to select categories or tags limits the amount of information we can
display.
Since editing or adding a custom categories section is already using a
modal, we have decided to switch editing the categories and tags that
appear in the sidebar to use a modal as well.
This commit removes the `new_edit_sidebar_categories_tags_interface_groups` site setting and
make the modals the default for all users.
Updates the interface for implementing summarization strategies and adds a cache layer to summarize topics once.
The cache stores the final summary and each chunk used to build it, which will be useful when we have to extend or rebuild it.
When the composer is open with a draft for a topic and the user clicks the edit button of a post on the same topic, we shouldn't display the "Save Draft" button. Because the edited post's draft will override the existing draft of the same topic even if we saved it.
Why this change?
We want the position of the filters to remain fixed when scrolling
through the list of categories or tags. Otherwise, the user has to
scroll all the way back to othe top in order to access the filters when
the list of categories or tags is large.
Why does this change do?
If the `fixed_category_positions` is `false`, we want to order the
categories in the edit navigation menu categories modal by name. This
makes it easier to filter through a large list of categories.
This commit also fixes a bug where we were unintentionally mutating the
`this.site.categories` array.
Why is this change required?
The `/new-topic` route is a special route which we use to open the
composer by loading a URL. By default, the `new-topic` route is replaced with the
`discovery.latest` route. On a fresh page load, this makes sense since
there is no template for the `new-topic` route to render. However, this
behavior does not make sense if we're transition from another route.
There is no need to replace the current route with the `discovery.latest` when all we want
is to open the composer.
What does this commit do?
This commit fixes the undesirable behaviour described above by aborting
the existing transition to the `new-topic` route if `transition.from` is
present. This indicates that we're navigating from an existing route and
we can just open the composer.
While still in ember-cli new app blueprint, I don't think this package does much for us. It has support for older things like bower and npm-shrinkwrap, but doesn't support checking yarn.lock and doesn't necessarily work well with our project structure.
This commit adds data attributes to identify the controls in the user settings UI.
Plugins and TCs can use this information to target each setting to highlight or hide
them.
Although most of the settings also have specific classes identifying them, using data
attributes is more future proof as it is less likely to change them classes, specially
as we increase the adoption of the BEM methodology in CSS.
Using data attributes also are semantically correct as the setting name is data not really related to the classes used.
The user card is always present in the DOM. Therefore we only need to
add the `aria-labelledby` attribute when there is a user (and a title)
to point to.
What does this change do?
This change adds a dropdown filter that allows a user to filter by
selected or unselected categories/tags in the edit navigation menu
modal.
For the categories modal, parent categories that do not match the
dropdown filter will be displayed as disabled since those parent
categories need to be displayed to maintain the hieracy of the child
child categories.