`delete_previous!` deletes existing topics even when we cannot send a new one due to the `limit_once_per` option. The dashboard problems PM gets deleted the next time the job runs (30 minutes), so the inbox could be empty when
admins click on the summary notification.
This PR restores a small feature which was present in the old menu and allowed users to click on the active tab in the menu to navigate to some page that showed the same items in the menu but with more details.
For example, if you switch to the PMs tab and then click on it again, currently nothing happens. However, with this change, clicking on the tab again will take you to your messages page at `/my/messages`.
Note: plugins that register custom tabs in the menu can provide a `linkWhenActive` property for their tab if they wish to mimic core's tabs, but it's optional; if they don't provide one, the tab will do nothing if the user clicks on it again.
Internal topic: t/73349.
Because Discourse is a single-page application, clicks on the majority of `<a>` elements in the app need to be intercepted by JavaScript to prevent browsers' default action (full page reload). Links in the user menu - which include notifications, reviewables, bookmarks etc. - are no exception to this rule and currently clicks on these items are handled by the global [click-interceptor](1fa21ed415/app/assets/javascripts/discourse/app/lib/intercept-click.js (L20)) which calls the `preventDefault` function on the click event object and uses the `DiscourseURL.routeTo` function to route the user to the page they request.
However, for links in the user menu, there's an extra step which is to let the header know that it should close the user menu after clicking an item in the menu, but the global interceptor doesn't know that because the step is specific to links in the user menu. This can cause a bug on mobile devices where the menu remains open after clicking on a notification which results in the user having to close the menu to see the page that the notification takes them to.
This commit adds a click handler to user menu items that ensures the menu is closed when an item is clicked and navigates the user to wherever the item links to. There's a small downside to this change which is that user menu items now have their own click interceptor instead of relying on the global interceptor, i.e. duplicated logic, but since it's only a couple of lines, I think we can live with it for a while.
I did try to make the click handler of the user menu items only close the menu (call the `closeUserMenu` function), but for some reasons it caused a full page reload to happen when clicking a notification item due to some weird interactions between the header widget and the user menu. I didn't debug this thoroughly because we have plans to change the header implementation from widgets/virtual-dom to Glimmer component, which will likely resolve that weird full page reload issue and we'll be able to make the click handler just close the menu and let the global interceptor prevents the default action and do the routing.
Internal topic: t/71911/118.
Right now the experimental user menu sorts notifications the same way that the old menu does: unread high-priority notifications are shown first in reverse-chronological order followed by everything else also in reverse-chronological order. However, since the experimental user menu has dedicated tabs for some notification types and each tab displays a badge with the count of unread notifications in the tab, we feel like it makes sense to change how notifications are sorted in the experimental user menu to this:
1. unread high-priority notifications
2. unread regular notifications
3. all read notifications (both high-priority and regular)
4. within each group, notifications are sorted in reverse-chronological order (i.e. newest is shown first).
This new sorting logic applies to all tabs in the experimental user menu, however it doesn't change anything in the old menu. With this change, if a tab in the experimental user menu shows an unread notification badge for a really old notification, it will be surfaced to the top and prevents confusing scenarios where a user sees an unread notification badge on a tab, but the tab doesn't show the unread notification because it's too old to make it to the list.
Internal topic: t72199.
This PR changes the icon for `posted` notification types (these are the notifications that you receive when someone posts in a topic you're watching) from `reply` to `discourse-bell-exclamation`. We're doing this to visually distinguish between the `posted` notifications and `replied` notifications which are the notifications that you receive when someone replies to you directly.
Internal topic: t72835.
In Safari, `img.complete` is sometimes true even before the image is loaded. Checking for the presence of `img.naturalHeight` seems to be more reliable. It is very difficult to write a test for this behaviour due to the dependence on network conditions, scroll location, etc.
`img.naturalHeight` is supported by all our target browsers, and I have verified the functionality of this commit in Chrome, Safari and Firefox.
This updates the ember-cli plugin detection logic to match the logic in `Plugin::Instance.find_all`. It will now ignore plugin directories which do not have a `plugin.rb` file.
This commit adds to the experimental user menu a new "other notifications" tab that's very similar to the "all notifications" tab, but with the main difference being that it doesn't show notification types that do have dedicated tabs in the menu (e.g. mentions, likes, replies etc.).
The rationale behind this is that the notification types that do have dedicated tabs tend to dominate the "all notifications" tab, leaving very small chances for the user to notice rarer or infrequent notification types. Adding a tab for all the other types gives the user a way to review those infrequent notification types.
Internal ticket: t72978.
Co-authored-by: OsamaSayegh <asooomaasoooma90@gmail.com>
We were using the directory name rather than the plugin's defined `name`. This was an unintended change in behaviour from the old sprockets implementation. This commit makes the ember-cli naming logic match the old sprockets logic.
If the server is configured to use a view like `categories_and_latest_topics`, it will preload data for the topic list. If the client doesn't actually use it (e.g. on mobile), then that preloaded data would remain cached and be used for the next loaded topic list. This commit ensures it's always removed, and adds a test for the behaviour.
https://meta.discourse.org/t/237126/35
A user could receive more than a notification for the same post if they
watched both the categories and tags at different levels. This commit
makes sure that only the watching notification is created.
* Add DiscourseEvent before post notifications are created
Previously we were relying on a highly-customized version of the unmaintained Barber gem for theme template compilation. This commit switches us to use our own DiscourseJsProcessor, which makes use of more modern patterns and will be easier to maintain going forward.
In summary:
- Refactors DiscourseJsProcessor to move multiline JS heredocs into a companion `discourse-js-processor.js` file
- Use MiniRacer's `.call` method to avoid manually escaping JS strings
- Move Theme template AST transformers into DiscourseJsProcessor, and formalise interface for extending RawHandlebars AST transformations
- Update Ember template compilation to use a babel-based approach, just like Ember CLI. This gives each template its own ES6 module rather than directly assigning `Ember.TEMPLATES` values
- Improve testing of template compilation (and move some tests from `theme_javascript_compiler_spec.rb` to `discourse_js_processor_spec.rb`
The generate RSA key and import theme routes worked separate from each
other. The RSA key returned both the public and private key and it was
the frontend which posted the private key back to the server. With this
commit, only the public key is necessary as the server keeps a map of
public and private keys that is used to get the private key back from
a public key.
It used to return the next URL anyway which lead to an additional
request. On the frontend, if the result set was empty, it kept retrying
until at least one result was returned. This bug is fixed in this commit
too.
`popupAjaxError` is used by the controller to handle errors when saving the badge model. That only works properly when it gets the original exception from the ajax call. This manipulation of the error in the badge model was breaking that behavior.
The admin-badges controller is the only place which saves this model, so this shouldn't cause any issues elsewhere in the app.
This lets us use all our normal JS tooling like prettier, esline and babel on the splash screen JS. At runtime the JS file is read and inlined into the HTML. This commit also switches us to use a CSP hash rather than a nonce for the splash screen.
* FIX: hide welcome topic banner as soon as the welcome topic is edited
This commit adds a message bus listener on client to hide the welcome
topic banner as soon as the welcome topic is edited.
* update test
* only subscribe when show_welcome_topic_banner is true
* Do not lookup for messageBus service if it's not required
* Remove unneeded code
* Cache result for Site.show_welcome_topic_banner
* Update tests per latest changes
* Changes per PR review
Each new user menu notifications should have their own count. Therefore, we need to include all types to serializer and not only `grouped_unread_high_priority_notifications`
Additional PR will be created for chat and assign plugin, as they will have to switch to `grouped_unread_notifications` as well.
When installing private themes and theme components, the public key does
not show until the administrator types a valid Git repo URL. The regular
expression that checked the URL was too strict and it required the URL
to end with ".git".
The source-of-truth for our ember version is now the installed node_module. The `ember_source` gem carries an old version of Ember and so the constant is no longer useful. We'll be dropping the gem soon.
In eb12daa7f8 when adding community
section support for anonymous users, we changed the `sectionLinks`
property into a getter method. This meant that if the getter method was
called again after the community section has been rendered, we would end
up reintializing the section links classes. As part of the
initialisation, some section links would setup a TopicTrackingState
onStateChange listener. However, the listener is only removed when the
entire community section is removed which resulted in us leaking the
onStateChange listeners.
This commit reverts the `sectionLinks` from being defined as a getter
method into a property which is only set once when the community section
is being constructor. Also, we changed it such that the community
section will register the listener instead of each section link since it
makes cleaning up much easier to reason about.
No tests have been added for this commit because the original bug is
not possible after this change and we already have an existing tests
ensuring that TopicTrackingState change listeners are cleaned up when
the community section is destroyed.
Internal ref: /t/73224
When you receive a new notification, Discourse prepends a small count `(n)` to the tab title (i.e. `document.title`) if the tab is in the background to alert the user that they have a new notification. The count that's shown in the tab title should reflect the numbers shown on the notification bubbles above the user's avatar. Prior to the experimental user menu, there were 2 bubbles: a blue one which was removed once the user opened the menu and a green one that indicated high priority notifications and it was only removed when the user read all of their high priority notifications.
In the new experimental user menu, we no longer have the green bubble; everything is now combined (including flags/reviewables) into the blue one with no change to its behavior (i.e. it's removed once the user opens the menu). However, the logic that is responsible for updating the tab title hasn't been updated and still updates the tab title to include the count of the old green bubble. This commit updates the logic for the tab title count so that it only reflects the number on the blue bubble when the experimental user menu is enabled.
This commit makes a number of improvements to the DiscourseJsProcessor:
1. Remove dependence on the out-of-date Ember template compiler from the ember-rails gem; switch to modern template compiler
2. Refactor to make use of a proper module system with `define`/`require`
3. Introduce `babel-plugin-ember-template-compilation` to enable inline hbs compilation
The `mini-loader` is upgraded to support relative lookup and `require.has`, so that these new JS packages work correctly.
We were already compiling the markdown bundle via ember-cli, but that version was only being used in the test environment. This commit improves the implementation, and updates the filename so it's also used in production.
This commit also
- Removes the vendored copy of `markdown-it.js` and fetches from node_modules instead
- Updates `pretty_text.rb` to remove the custom sprockets-manifest-parsing
- Removes `pretty-text-bundle.js`, which was only being used by `pretty_text.rb`
This adds a new framework for accessible dialogs that will eventually replace bootbox. Under the hood, it uses the a11y-dialog package and an in-repo Ember addon. See PR for usage details.
If a topic is converted to a private message, all posters were invited
to the new private message. This included users who only whispered or
posted small actions.
The old logic did not make sense and hid the selector from regular users
even if they could tag PMs or showed selector for admins even if they
could not tag PMs.
The preload key was changed in e7a84948b9 but this location was missed. This caused an extra AJAX request and left the cached topic list in the PreloadStore, which would then be accidentally used when navigating to the next topic-list route.
Topic allowed user records were created for small actions, which lead to
the system user being invited in many private topics when the user
removed themselves or if a group was invited but some members already
had access.
This commits skips creating topic allowed user. They are already skipped
for the whisper posts.
If a user was granted a trust level, joined a group that granted a trust
level and left the group, the trust level was reset. This commit tries
to restore the last known trust level before joining the group by
looking into staff logs.
This commit also migrates old :change_trust_level user history records
to use previous_value and new_value fields.
This commit extends the plugin API introduced in 40fd82e2d1 to the `Bookmark` and `Notification` models. It also refactors the code that's responsible for loading items in the experimental menu to use `async`...`await` instead of `Promise`s.
This API allows plugins to transform a list of model objects before they're rendered in the UI. At the moment, this API is limited to items/lists of the experimental user menu, but it may be extended in the future to other parts of the app.
Additional context can be found in https://github.com/discourse/discourse/pull/18046.
The previous sprockets implementation was including admin-specific JS in the plugin's main JS file, which would be served to all users regardless of admin status. This commit achieves the same result under the ember-cli plugin asset compiler with one difference: the admin js is compiled into a separate file. That means that in future, we'll be able to make it loaded only for admins. For now though, it's loaded for everyone, just like before.
When preloading topic_list data we were giving it a 'preload key' which was loosely based on the parameters of the list. However, it did not include all parameters, and mismatches between client/server-side logic would cause the preloaded data to be ignored.
This commit simplifies things by using a single key for all topic_list preloading. This works on the assumption that "The first topic_list the JS app will load is the one which was preloaded". That assumption also existed to some extent in the old design, so we don't expect any regressions here.
In 49a70a37f1 I removed the
topic: :posts preload for TopicBookmarkable, but did not
update the UserTopicBookmarkSerializer to reflect this,
which was causing up to multi-hundred millisecond queries to
be made for each topic bookmark based on the size of the
topic.
Omitting the flag from optional-features enables the runtime deprecation notice.
Also introduces `ember-jquery-legacy` which can be used to migrate to the new behaviour early. Details at https://deprecations.emberjs.com/v3.x/#toc_jquery-event
Core does not appear to make use of `originalEvent` in Ember event handlers. When searching for `originalEvent` there are some matches which relate to our pan-events mixin, but this is our own implementation and not affected by this deprecation.
We observed that some sites seemingly put us in a tarpit when we attempt to pull hotlinked images. Increasing the timeout will help in these situations.
Plugins often change core behavior, and thereby cause core's tests to fail. In CI, we work around this problem by running core CI without any plugins loaded.
In development, the only option to safely run the core tests is to uninstall all plugins, which is clearly a bad developer experience. This commit aims to improve that experience.
The `qunit_skip_plugins=1` flag would previously prevent the plugin **tests** from running. This commit extends that flag to also affect the plugin's application JS.
Default sidebar tags for not authenticated users can be defined in admin panel. Otherwise, top 5 categories and tags are taken.
Optionally, if categories are set up in permanent order, then the first 5 categories are taken.
```
1) CurrentUserSerializer#sidebar_category_ids includes visible default sidebar categories
Failure/Error: expect(json[:sidebar_category_ids]).to eq([category.id, category_2.id])
expected: [378, 379]
got: [379, 378]
```
Note that in the Ruby doc it says "The order is preserved from the original array". In this case, we want to preserve the order of the site setting.
`#main` in the test environment is replaced with `#ember-testing`, so this code would break. It never did only because we don't test these code paths 👀
The logic was added in commit ec8306835d,
to show the like action even if the user could not like the post. It is
not necessary for this logic to be implemented on the server side.
* FIX: Do not allow to remove like if topic is archived
* FIX: Always show like button
The like button used to be hidden if the topic was archived and it had
no likes. This commit changes that to always show the like button, but
with a not-allowed cursor if the topic is archived.
When `EMBER_CLI_PLUGIN_ASSETS=1`, plugin application JS will be compiled via Ember CLI. In this mode, the existing `register_asset` API will cause any registered JS files to be made available in `/plugins/{plugin-name}_extra.js`. These 'extra' files will be loaded immediately after the plugin app JS file, so this should not affect functionality.
Plugin compilation in Ember CLI is implemented as an addon, similar to the existing 'admin' addon. We bypass the normal Ember CLI compilation process (which would add the JS to the main app bundle), and reroute the addon Broccoli tree into a separate JS file per-plugin. Previously, Sprockets would add compiled templates directly to `Ember.TEMPLATES`. Under Ember CLI, they are compiled into es6 modules. Some new logic in `discourse-boot.js` takes care of remapping the new module names into the old-style `Ember.TEMPLATES`.
This change has been designed to be a like-for-like replacement of the old plugin compilation system, so we do not expect any breakage. Even so, the environment variable flag will allow us to test this in a range of environments before enabling it by default.
A manual silence implementation is added for the build-time `ember-glimmer.link-to.positional-arguments` deprecation while we work on a better story for plugins.
When there is not enough window width to display the admin menu on the
right, we display it on the left instead. Behavior is reversed on RTL
layout.
This commit also removes jQUery usage.
`TopicQueryParams` allows for `match_all_tags` to be passed as a query parameter. `TagsController` forces the value to be true.
This change allows a value to be passed, and only sets it to true if no value has been set. It then uses `ActiveModel::Type::Boolean.new.cast` to compare the value.
This commit adds the profile tab to the experimental user menu. We're adding it to the user menu because it contains links/buttons that are not available anywhere else. We may remove the tab again if we find better places for those links/buttons, but for now it'll stay.
For more context on the experimental user menu, see https://github.com/discourse/discourse/pull/17379.
This regressed when we switched these bundles to be compiled by ember-cli. Before/after sizes:
```
before after
admin.js: 1370 KB (190 KB gz) --> 782 KB (125 KB gzipped)
wizard.js: 127 KB ( 22 KB gz) --> 68 KB ( 18 KB gzipped)
```
The logic to determine what post excerpt to show for
a topic-level bookmark based on the last unread post
was complex and slow, so we decided to remove it and
always just use the first post excerpt.
This commit also fixes an issue where a couple of
instances of for_topic were missed when doing the
Bookmarkable refactors, so:
1. Clicking the topic bookmark link was not taking
the user to the last unread post
2. When replying to a topic where there was a topic
level bookmark with the auto delete preference
of "on owner reply", we were not removing the
bookmark from the UI correctly.
A test has been added for the former, the latter would
be quite time-consuming to test and not really worth
it considering it's quite an edge case UI bug.
Ever opened `/tests`, immediately tried to change the config, and got frustrated that focus keeps getting stolen by the running tests? Worry no more - this commit will make the tests auto-abort when you click any of the input/dropdowns in the QUnit header. It's not perfect - abort will wait until the end of the currently running test, so sometimes focus will be stolen one more time. But it's still a lot better than having to manually find and click the abort button.
The following changes are made in this commit:
1. Move caret icon in sidebar section header to the right.
1. Each row in sidebar takes the full width which enables us to do a
full width highlight on hover and when sidebar link is active.
1. Ensure each row in Sidebar is of the same height.
Internal refs: /t/70546, /t/72196, /t/71820
These packages are not published anywhere - they only exist for organizational purposes within this repository. Even so, it makes sense for their metadata to match that of the top-level discourse/discourse repository.
By default, in CI environments, Ember CLI does not output anything between "building..." and "cleaning up". Depending on configuration and hardware, Discourse asset builds can take upwards of 60s, and so this lack of output can make the build feel 'stuck'.
This commit introduces an addon which checks for CI mode, and then outputs status information periodically. The logic is very similar to Ember CLI's non-CI progress output implementation (https://github.com/ember-cli/ember-cli/blob/04a38fda2c/lib/models/builder.js#L183-L185).
Without this filter, a binary file (e.g. `.DS_Store`) in one of these addon directories will be concatenated into the output JS. Note that this filter is applied at the end of the build pipeline, so any hbs files have already been transpiled into `.js`.
This mirrors the filtering performed on the main application bundle by Ember CLI: https://github.com/ember-cli/ember-cli/blob/04a38fda2c/lib/broccoli/default-packager.js#L1255
We can finally rely on template colocation in our app and we'll be
standarizing on that in the near future. However, I want to have sidebar
adopt this convention earlier.
Instead of relying on another help to generate the icons, we want to
rely on the interface for adding prefix icons. This ensures that prefix
icons are consistent across the section links in Sidebar
Previously, for every bookmarked topic, all topic_user records were being preloaded. Only the current user's record is actually required.
This commit introduces a new `perform_custom_preload!` API which bookmarkables can use to add custom preloading logic. We use this in topic_bookmarkable to load just the topic_user data we need (in the same way as `topic_list.rb`).
Co-authored-by: Blake Erickson <o.blakeerickson@gmail.com>
If a widget toggles between displaying two different RenderGlimmer instances, the Widget framework treats them as the same, and so `update()` is called rather than destroy/init. This commit detects this scenario and manually destroys/inits to ensure the correct component is being rendered.
Handles edge-case when a user is an admin and has an associated reviewable. Hitting this exception should be rare since we clear the reviewable when
granting staff to the user.
Before this commit, we carried custom code and styles for the sidebar on
mobile. This meant the look and feel of bringing up the sidebar on
mobile was very different from the user menu resulting in a very
inconsistent experience on mobile. Also, we could not leverage on the
existing swipe to close support on mobile.
In this commit, we made it such that the sidebar dropdown is always
rendered on mobile and made the interaction with the dropdown more
consistent with the user menu. There is also more parity with the old
hamburger dropdown when the experimental sidebar is disabled.
This commit introduces a new `{{on-resize}}` modifier along with its companion `resize-observer` Service. These automatically take care of setting up the observer and handling cleanup.
This commit includes the changes proposed in #17823. I've made these changes so that plugins that need to add tabs/lists with mixed item types - like the bookmarks tab that displays notifications and bookmarks - to the menu, don't have to write 2 templates like we currently do for the bookmarks/messages tabs (see user-menu/bookmark-notification-item.js that has been deleted in this commit).
These are in widespread use, and upgrading themes/plugins right now would break their compatibility with the stable branch. These should be unsilenced for the release of 2.9.0 stable.
Previously, this would require manually adding `?safe_mode=...` multiple times during the email-based login flow. `/u/admin-login` is often used when debugging a site, so it makes sense for this to be easier.
This commit introduces a new checkbox on the `/u/admin-login` screen. When checked, it'll set the safe_mode parameter on the `/email-login` link, and then pass it all the way through to the homepage redirect.
- `no_custom` -> `no_themes` (history: before themes existed, we had a similar tool called 'customizations')
- `only_official` -> `no_unofficial_plugins` (matches format of `no_themes` and `no_plugins`, and makes it clear that this doesn't affect themes)
- `?safe_mode=no_themes%2C%no_plugins` -> `?safe_mode=no_themes,no_plugins` (the query portion of a URL does not require commas to be encoded. This is much nicer to read)
- If `no_plugins` is chosen from `/safe-mode` the URL generated will omit the superfluous `no_unofficial_plugins` flag
- Some tweaks to copy on `/safe-mode`
There was existing logic for this, but it was broken because the values were being run through `encodeURI` before checking its type. This commit takes the opportunity to modernise the function to use `URLSearchParams`, which means we no longer need to handle encoding/joining strings manually.
Co-authored-by: Jarek Radosz <jradosz@gmail.com>
This was a temporary solution while we updated the resolver and migrated all our singletons to true ember services. Now that's done, we can switch to use `@glimmer/component` directly, and explicitly inject services as required.
This fix is for the experimental user menu. Some `bookmark_reminder` notifications may not be associated with a topic/post (e.g. bookmark reminder for a chat message) in which case the default notification renderer cannot figure out the `href` for those `bookmark_reminder` notifications. This commit teaches the `bookmark_reminder` notification type renderer to fallback to `bookmarkable_url` that's present in the notification data if the default notification renderer doesn't return a `href` for the notification.
At a certain point, the cost of debugging a flaky acceptance test is
just too high for what we're testing for here. I've decided to just
accept the risk of a minor UX feature.
Follow-up to 55fa94f759
Previously, PM only tags were being routed to the public topic list with
the tag added as a filter. However, the public topic list does not fetch
PMs and hence PM only tags did not provide any value when added to the
Sidebar. This commit changes that by allowing the client to
differentiate PM only tag and thus routes the link to the PM tags show
route.
Counts for PM only tags section links are not supported as of this
commit and will be added in a follow up commit.
1. Replace `{{did-insert` with the builtin `{{on` modifier
2. Move the i18n call into the template
With both of those changes, there is no logic left in the backing class, so we can switch to `templateOnly()` which is significantly faster. (granted, not a big deal for a component like this, but it makes for a good demonstration)
Now that all of our singletons have been converted to true Ember Services, we can remove our custom `discourse/component/glimmer` superclass and use explicit injection
This also updates `section-message` to be a templateOnly glimmer component rather than a classic component.
Now that all of our singletons have been converted to true Ember Services, we can remove our custom `discourse/component/glimmer` superclass and use explicit injection
Now that all of our singletons have been converted to true Ember Services, we can remove our custom `discourse/component/glimmer` superclass and use explicit injection