Since the default for the bookmark modal is to have no
reminder if you create a bookmark by clicking out of
the modal or pressing the Save button, this commit highlights
None by default.
Also changes the bookmark component to not use @on for Ember
lifecycle, we don't use that style
The commit fcc2e7ebbf to promote
polymorphic bookmarks did not correctly set the username for
the quick access bookmark menu based on the new serializer
values, so the username is not being shown in the bookmark
quick access menu. This commit fixes it, and also adds additional
tests for that menu and updates the user fixtures to reflect
the current state of the bookmarks endpoint.
Given this html:
```
<aside class="quote no-group">
<blockquote>
<aside class="quote no-group">
<blockquote>
<p dir="ltr">test</p>
</blockquote>
</aside>
<p dir="ltr">test2</p>
</blockquote>
</aside>
```
The result was an invalid markdown:
```
[quote]
[quote]
> test
> [/quote]
>
>
>
> test2
[/quote]
```
Now the result is:
```
[quote]
[quote]
test
[/quote]
test2
[/quote]
```
Sometimes we need to render the icon as a call to action
to create a bookmark at which point the bookmark does
not yet exist, so we need to just show the normal bookmark
icon and a create title.
Also adds a CSS class for the bookmark existing and not existing
for styling.
This improves the bookmark-icon title to be more like the
post bookmark icons, to include the special formatted date
as well as the name of the bookmark.
This component will be useful for chat, and also moves
the definition of the icon for with and without reminders
to the bookmark model as consts, so they can easily be
referenced in other places.
This commit migrates all bookmarks to be polymorphic (using the
bookmarkable_id and bookmarkable_type) columns. It also deletes
all the old code guarded behind the use_polymorphic_bookmarks setting
and changes that setting to true for all sites and by default for
the sake of plugins.
No data is deleted in the migrations, the old post_id and for_topic
columns for bookmarks will be dropped later on.
Categories that had a CategoryUser record and the notification level
set to "Normal" were not selectable in any of the "Watched", "Tracked",
"Watching First Post" or "Muted" inputs. This happened because the
category seemed to be already selected in the "Normal" input, but that
does not exist (it is the default value if category is not present in
any of the other inputs).
While editing a reviewable's tags, the tag chooser did not show the tags
restricted to a specific category. This happened because the tag-chooser
did not pass the categoryId to the server while it was requesting the
list of tags the user can use.
The prioritize_username_in_ux site settings controls if the username or
name will be prioritized in the user interface. On the user directory
page the name was never displayed if the user and username were very
similar, being completely different from all the other places where the
username or name is displayed.
Note this commit also introduce a new {{d-popover}} component, example usage:
```hbs
{{#d-popover |state|}}
{{d-button label="foo.things" class="d-popover-trigger"}}
<div class="d-popover-content">
Some content
<div>
{{/d-popover}}
```
If you happen to mention someone with the wrong capitalization for that
person's username (e.g. `@sAm`), that incorrect capitalization would get
displayed on their user card.
This update will fix that by displaying the `user.username` value, which
will have the correct capitalization.
I also added some tests that will ensure `username` and `name` are
displayed on the user card in the correct order based on the
`prioritize_username_in_ux` setting.
This issue was reported here:
https://meta.discourse.org/t/capitalization-does-not-match-when-you-open-user-cards-using-mentions/217166
There was an edge when a user re-quoted a nested quote that it would return an incorrect `full name` but the correct `username` for the original quote. This PR updates the logic to fall back to using the OP user's username.
The complexity of the changes required to allow for full names to be displayed on nested quotes far outweighs how rare quoting nested quotes is.
Commit 68497bddf2 implemented a function
to format durations in a medium format, similar to how durationTiny did.
The existent translation strings do not cover all cases and this commit
adds the missing translation strings.
This commit fixes two issues at play. The first was introduced
in f6c852b (or maybe not introduced
but rather revealed). When a user posted a new message in a topic,
they received the unread topic tracking state MessageBus message,
and the Unread (X) indicator was incremented by one, because with the
aforementioned perf commit we "guess" the correct last read post
for the user, because we no longer calculate individual users' read
status there. This meant that every time a user posted in a topic
they tracked, the unread indicator was incremented. To get around
this, we can just exclude the user who created the post from the
target users of the unread state message.
The second issue was related to the private message topic tracking
state, and was somewhat similar. Whenever a user created a new private
message, the New (X) indicator was incremented, and could not be
cleared until the page was refreshed. To solve this, we just don't
update the topic state for the user when the new_topic tracking state
message comes through if the user who created the topic is the
same as the current user.
cf. https://meta.discourse.org/t/bottom-of-topic-shows-there-is-1-unread-remaining-when-there-are-actually-0-unread-topics-remaining/220817
This updates the fix in commit eb70ea4.
Co-authored-by: Osama Sayegh <asooomaasoooma90@gmail.com>
Co-authored-by: Alan Guo Xiang Tan <gxtan1990@gmail.com>
This PR will include `suspended` attribute in post serializer to check it in post widget and add a CSS class name.
Co-authored-by: Alan Guo Xiang Tan <gxtan1990@gmail.com>
The error would happen when emoji_autocomplete_min_chars site setting is set to anything superior to 0, in this case until we reach the min chars length, emojiSearch would return "skip" and the code was currently expecting an array.
Discourse has the Discourse Connect Provider protocol that makes it possible to
use a Discourse instance as an identity provider for external sites. As a
natural extension to this protocol, this PR adds a new feature that makes it
possible to use Discourse as a 2FA provider as well as an identity provider.
The rationale for this change is that it's very difficult to implement 2FA
support in a website and if you have multiple websites that need to have 2FA,
it's unrealistic to build and maintain a separate 2FA implementation for each
one. But with this change, you can piggyback on Discourse to take care of all
the 2FA details for you for as many sites as you wish.
To use Discourse as a 2FA provider, you'll need to follow this guide:
https://meta.discourse.org/t/-/32974. It walks you through what you need to
implement on your end/site and how to configure your Discourse instance. Once
you're done, there is only one additional thing you need to do which is to
include `require_2fa=true` in the payload that you send to Discourse.
When Discourse sees `require_2fa=true`, it'll prompt the user to confirm their
2FA using whatever methods they've enabled (TOTP or security keys), and once
they confirm they'll be redirected back to the return URL you've configured and
the payload will contain `confirmed_2fa=true`. If the user has no 2FA methods
enabled however, the payload will not contain `confirmed_2fa`, but it will
contain `no_2fa_methods=true`.
You'll need to be careful to re-run all the security checks and ensure the user
can still access the resource on your site after they return from Discourse.
This is very important because there's nothing that guarantees the user that
will come back from Discourse after they confirm 2FA is the same user that
you've redirected to Discourse.
Internal ticket: t62183.
Firefox does not support window.ClipboardItem yet (it is behind
a flag (dom.events.asyncClipboard.clipboardItem) as at version 87.)
so we need to fall back to the normal non-async clipboard copy, that
works in every browser except Safari.
This commit also tests the clipboardCopyAsync function by stubbing out
the clipboard on the window.navigator.
This fixes an issue in the discourse-chat plugin, where the
"Quote in Topic" button errored in Firefox.
After this commit, category group permissions can only be seen by users
that are allowed to manage a category. In the past, we inadvertently
included a category's group permissions settings in `CategoriesController#show`
and `CategoriesController#find_by_slug` endpoints for normal users when
those settings are only a concern to users that can manage a category.
The test was dependent on a translation string. Under certain seeds, the translation string for `{{category-drop}}`'s `noCategoriesLabel` is broken. This is because the value is calculated the first time a `{{category-drop}}` is rendered during the suite. If that first time happens to be during a test which is messing with `I18n.translations`, then it will cache a broken value. Maybe this should be fixed in a future commit... but for now moving to `data-value` will make the `tags-test` more robust and will stop the flakiness.
Moderators don't have access to notifications of other users. So we shouldn't display the notifications tab on other user profiles for them.
Co-authored-by: Alan Guo Xiang Tan <gxtan1990@gmail.com>
There are still some, but those are in actual code that's used outside core, so the change there would need to go through the deprecation cycle. That's a task for another day.
Previously we only supported a single 'required tag group' for a category. This commit allows admins to specify multiple required tag groups, each with their own minimum tag count.
A new category_required_tag_groups database table replaces the existing columns on the categories table. Data is automatically migrated.
A while ago in 27b97e4 the
pick-files-input was added but only used once for data-explorer. This commit uses it
for the composer-editor, and cleans it up to be usable either via uppy
handling the uploads or with this component handling the uploads.
This can then be used in other places in the app and also for plugins.
Browsers automatically calculate an aspect ratio based on the width/height attributes of an `<img`. HOWEVER that aspect ratio only applies while the image is loading. Once loaded, it'll use the image's actual dimensions. This can cause things to jump around after loading. For example:
- if a user deliberately inserts false width/height
- the image fails to load (404)
- an optimised image is a few pixels different, due to a rounding when resizing
This decorator explicitly sets the `aspect-ratio` property so that things are consistent throughout the lifetime of all `<img` elements.
Invited users were allowed to accept invites without entering a
password. When this happened, instead of receiving an activation email,
they received a password reset email. Basically, a user could postpone
choosing a password until after registration.
Unfortunately, this led to a confusing user experience and this commit
attempts to fix that by making the client require a password. There is
a single case when users do not need to input a password: when they sign
up using an external authenticator and password field is completely
hidden. In this case, the third party handles the password logic.
Technically, invites can still be redeemed without a password, but that
functionality was kept to preserve backwards compatibility.
String.prototype.substr() is deprecated so we replace it with String.prototype.slice() which works similarily but isn't deprecated.
Signed-off-by: Tobias Speicher <rootcommander@gmail.com>
Co-authored-by: Jarek Radosz <jradosz@gmail.com>
The links returned by post.url and topic.url are relative, but contain
the subdirectory. When getAbsoluteURL is called to construct the
complete share URL, it adds the host and the subdirectory again. As a
result the created URLs contained the subdirectory twice.
Since 3fd7b31a2a some tests
were failing with this error:
> Error: Unhandled request in test environment: /c/feature/find_by_slug.json
> (GET) at http://localhost:7357/assets/test-helpers.js
This commit fixes the issue by adding the missing pretender. Also
noticed while fixing this that the parameter for the translation
was incorrect -- it was `group` instead of `groupNames`, so that
is fixed here too, along with moving the onShow functions into
@afterRender decorated private functions. There is no need for the
appevent listeners.
Clicking the Replies cell of a topic in a topics list shows a little
modal with 2 buttons that take you to the first and last posts of the
topic. This modal is currently completely inaccessible to
keyboard/screen reader users because it can't be reached using the
keyboard.
This commit improves the modal so that it traps focus when it's shown
and makes it possible to close the modal using the esc key.
Another attempt at fixing https://meta.discourse.org/t/discourse-with-a-screen-reader/178105/88?u=osama. Previous PR (reverted): #16240.
The problems with the previous PR were:
1. As you scrolled down a topics list, the first topic of every new batch of topics would receive focus and the indicator would show up.
2. Similar to 1, clicking the `See X new or updated topics` notice would also focus a random topic from the new topics that were just loaded.
3. Topics in the suggested topics list received focus too
4. Our custom focus indicator appeared on mobile, but it shouldn't.
This commit should have none of these problems.
This is done by defining a `/all` route for use when a category's default filter is 'none'. This was defined for regular category routes in 3e7f7fdd, but not for tag routes.
This commit also corrects the route name TagsShowNoneCategory*Route -> TagsShowCategoryNone*Route, which fixes an error when setting subcategories=none while filtering by tags.
share-topic modal is used everywhere expect when clicking on the top
right corner of the post. This changes standardize on share-topic modal
and add the missing features from share-popup.
The user can select what happens with a bookamrk after it expires. New
option allow bookmark's reminder to be kept even after it has expired.
After a bookmark's reminder notification is created, the reminder date
will be highlighted in red until the user resets the reminder date.
User can do that using the new Clear Reminder button from the dropdown.
This PR adds an extra description to the 2FA page when granting a user admin access. It also introduces a general system for adding customized descriptions that can be used by future actions.
(Follow-up to dd6ec65061)
The current implementation ties the filter query params tightly to the
`summary` attribute on the post stream model making it hard to support
other filters.
This feature was rarely used, could be used for spamming users and was
impossible to add a context to why the user was notified of a topic. A
simple private messages that includes the link and personalized message
can be used instead.
* FEATURE: upload an avatar option for uploading avatars with selectable avatars
Allow staff or users at or above a trust level to upload avatars even when the site
has selectable avatars enabled.
Everyone can still pick from the list of avatars. The option to upload is shown
below the selectable avatar list.
refactored boolean site setting into an enum with the following values:
disabled: No selectable avatars enabled (default)
everyone: Show selectable avatars, and allow everyone to upload custom avatars
tl1: Show selectable avatars, but require tl1+ and staff to upload custom avatars
tl2: Show selectable avatars, but require tl2+ and staff to upload custom avatars
tl3: Show selectable avatars, but require tl3+ and staff to upload custom avatars
tl4: Show selectable avatars, but require tl4 and staff to upload custom avatars
staff: Show selectable avatars, but only allow staff to upload custom avatars
no_one: Show selectable avatars. No users can upload custom avatars
Co-authored-by: Régis Hanol <regis@hanol.fr>
Meta topic: https://meta.discourse.org/t/rtl-direction-is-broken-in-quotes/217639?u=osama.
Posts in Discourse are by default always rendered in the same direction as the rest of site, for example if the site is RTL, a post in that site is always rendered RTL even if it's made of an LTR language entirely. However, this behavior can be changed by enabling the `support mixed text direction` site setting which makes our posts rendering engine consider each "paragraph" in the post and apply an appropriate direction (using the `dir` attribute) on it based on its content/language.
I put paragraph in quotes because technically we only loop through the immediate children of the HTML element that contains the post cooked HTML and do this direction check on them. Most of the time the immediate children are actually paragraphs, but not always. The direction of an element is determined by checking its `textContent` property against a regular expression that checks all characters are RTL characters and based on the regular expression result the `dir` attribute is set on the element.
This technique doesn't work so well on quotes because they may contain multiple paragraphs which may be in different languages/directions. For example: if a site's language is Arabic (RTL language) and the `support mixed text direction` setting is enabled, regular paragraphs outside quotes are rendered as expected with the right direction depending on the paragraph's language. However, paragraphs within a quote are all (incorrectly) rendered in a single direction, LTR or RTL, regardless of whether they're of different languages/directions or not.
The reason for this is that when we're determining the direction for the quote, it's considered as one element and the direction is set on the whole quote. But for complex quotes that contain mixed paragraphs, we need to be more surgical and apply direction on individual paragraphs/elements within the quote.
This commit adds special handling for quotes to ensure that:
* the quote top bar (the avatar plus the chevron and arrow) always match the site direction
* each immediate paragraph (`<p>` elements) under `<blockquote>` in the quote gets a direction based on its content.
For before/after screenshots, see PR #16004.
* DEV: remove duplicate code in button component template
* DEV: refactor is-loading state of d-button component
Before this change on initialisation `forceDisabled` is set `false` and then might change to `undefined` - depending on the use of the button component. This change ensures a boolean value for `forceDisabled`.
The added test works with and without the new change. The test is added as it represents the default use case for most buttons.
Previously we were publishing one messagebus message per user which was 'tracking' a topic. On large sites, this can easily be 1000+ messages. The important information in the message is common between all users, so we can manage with a single message on a shared channel, which will be much more efficient.
For user-specific values (notification_level and last_read_post_number), the JS app can infer values which are 'good enough'. Correct values will be loaded as soon as a topic-list containing the topic is visited.
2FA support in Discourse was added and grown gradually over the years: we first
added support for TOTP for logins, then we implemented backup codes, and last
but not least, security keys. 2FA usage was initially limited to logging in,
but it has been expanded and we now require 2FA for risky actions such as
adding a new admin to the site.
As a result of this gradual growth of the 2FA system, technical debt has
accumulated to the point where it has become difficult to require 2FA for more
actions. We now have 5 different 2FA UI implementations and each one has to
support all 3 2FA methods (TOTP, backup codes, and security keys) which makes
it difficult to maintain a consistent UX for these different implementations.
Moreover, there is a lot of repeated logic in the server-side code behind these
5 UI implementations which hinders maintainability even more.
This commit is the first step towards repaying the technical debt: it builds a
system that centralizes as much as possible of the 2FA server-side logic and
UI. The 2 main components of this system are:
1. A dedicated page for 2FA with support for all 3 methods.
2. A reusable server-side class that centralizes the 2FA logic (the
`SecondFactor::AuthManager` class).
From a top-level view, the 2FA flow in this new system looks like this:
1. User initiates an action that requires 2FA;
2. Server is aware that 2FA is required for this action, so it redirects the
user to the 2FA page if the user has a 2FA method, otherwise the action is
performed.
3. User submits the 2FA form on the page;
4. Server validates the 2FA and if it's successful, the action is performed and
the user is redirected to the previous page.
A more technically-detailed explanation/documentation of the new system is
available as a comment at the top of the `lib/second_factor/auth_manager.rb`
file. Please note that the details are not set in stone and will likely change
in the future, so please don't use the system in your plugins yet.
Since this is a new system that needs to be tested, we've decided to migrate
only the 2FA for adding a new admin to the new system at this time (in this
commit). Our plan is to gradually migrate the remaining 2FA implementations to
the new system.
For screenshots of the 2FA page, see PR #15377 on GitHub.
When parent category or grandparent category is muted, then category should be muted as well.
Still, it can be overridden by setting individual subcategory notification level.
CategoryUser record is not created, mute for subcategories is purely virtual.
Instead of relaying on /timings request, we should cache last read post number. That should protect from having incorrect unread counter when going back to topic list.
This additional cache is very temporary as once /timings request is finished, serializer will have a correct result.
Simplified flow is:
1. Store in cache information about last seen post number before /timings request is sent
2. When getting back to topic list compare value of last seen post number returned by /latest request and information in cache. If cache number is higher, than use it instead of information returned by /latest. In addition delete cache item as there is high chance that `/timings` request already finished.
3. Optionally, delete cache when timings request is done and topic list was not yet visited.
Keeping cache reasonably small should not affect performance.
TopicTrackingState should correctly set filterCategory and filterTag for all different configurations.
When filterTag exists and new_topic message arrives, it ensures that filterTag is included in payload tags
If filterTag is part of payload tags, message that new topics are available is displayed and after click, new topics are included in the list.
Allows to write custom code blocks:
```
```mermaid height=200,foo=bar
test
```
```
Which will then get converted to:
```
<pre data-code-wrap="mermaid" data-code-height="200" data-code-foo="bar">
<code class="lang-nohighlight">
test
</code>
</pre>
```
This commit adds a new helpful function to the composer controller
which can be used to focus the composer and insert text, regardless
of whether the consumer knows whether the composer is open or has
a draft. This is good for cases where an action needs to copy text
to the composer or open it with text after navigating to a URL.
The inspiration for this addition is the discourse-chat plugin,
which needs to be able to copy quoted markdown from the chat
and insert it into the composer, and unlike in the topic controller
we have no idea of the state of the composer from chat.
In the commit d8bf2810ff we hoisted
the userOptionFields array to a module-level variable, but kept
the code inside save() the same. This causes an issue where if
save() is called twice on the same user with some array of user
option fields, the userOptionFields array is mutated, which means
the second save is likely not saving the fields intended.
This commit fixes the issue by not mutating the array. We cannot
change them into consts though, because we have an API to add more
items to the array.
This commit allows group SMTP emails to be sent with a
different from email address that has been set up as an
alias in the email provider. Emails from the alias will
be grouped correctly using Message-IDs in the mail client,
and replies to the alias go into the correct group inbox.
When uploading an image, we change the uploading placeholder several times. Every time, we correct the position of the cursor after replacing. But we schedule repositioning of cursor to the afterRender queue in Ember Run Loop. As a result, sometimes we replace the placeholder several times but correct the cursor position only once at the end.
It just cannot work correctly with scheduling, we'll always be dealing with cumulative error. Removing scheduling fixes the problem.
Sadly, I cannot make the test work, I skipped it for now, going to give it another try later.
When changing to uppy for file uploads we forgot to add
these conditions to the paste event from 9c96511ec4
Basically, if you are pasting more than just a file (e.g. text,
html, rtf), then we should not handle the file and upload it, and
instead just paste in the text. This causes issues with spreadsheet
tools, that will copy the text representation and also an image
representation of cells to the user's clipboard.
This also moves the paste event for composer-upload-uppy to the
element found by the `editorClass` property, so it shares the paste
event with d-editor (via TextareaTextManipulation), which makes testing
this possible as the ember paste bindings are not picked up unless both
paste events are on the same element.
Previously, `resetSite()` would immediately generate a new `Site` instance, and run all the initialization logic within the model. This included initializing Category objects.
This was problematic because `resetSite()` is called before any initializers have been run. That means that any modifications to the Site or Category classes would not have any effect on the already-initialized Site/Category instances.
This commit makes two main changes so so that the test environment is more production-like:
1. Update `resetSite` so that it simply stores the new data in the PreloadStore, and destroys the old Site instance. Initialization of a new site instance happens 'just in time' (normally during the `inject-discourse-objects` initializer)
2. Update the `helperContext` in tests to use getters. This avoids the need to look up `Site.current()` before initializers have run
It also makes a minor adjustment to one test which was relying on a side-effect of the previous behavior.
This should resolve the failing tests for discourse-category-expert under Ember-CLI: https://github.com/discourse/discourse-category-experts/pull/69
* Some are no longer flaky or easily fixed
* Some are out of date or test things we can't do accurately (scroll
position) and are removed.
* Unwinds some uppy tests and makes sure all promises and runloops are
resolved.
Everything has been run in legacy/ember cli multiple times to ensure no
obvious suite regressions.
This reverts commit f43bba8d59.
Adding randomness has introduced a lot of flakiness in our ember-cli tests. We should fix those issues at the source. However, given the upcoming stable release, this randomness has been reverted so that the stable release includes a stable test suite. Having a stable test suite on stable will make backporting future commits much easier.
Removes one layer of indirection in the tests. `emoji-uploader`'s
`uploadDone` can call the test handler directly without going through
an additional action method.
It does this by creating a new initializer that runs every time the app
is booted to track the current test. Then after each test, we see if the
app needs to be torn down.
This creates a helper function with all the cleanup tasks we need to do
after tests, then makes sure to call it after tests that previously
weren't.
This fixes a lot of flakey tests.
As part of /t/10298, try to remove the first flaky test in the list.
One finding is that the /t/280 topic has a very long post stream, so that may have caused some delay when rendering the topic. One way is to wait for the first expected element to load, but that doesn't scale well given how many waits we will need to add. So I chose to render a shorter topic instead.
Previously we were adding `/assets/discourse/tests/core_plugin_tests.js` to the test html all the time. This works in development mode, but fails silently when using testem via the `ember test` CLI, because there is no proxy running.
This commit makes a few changes to fix this, and make it more useful:
- Only renders the plugin `<script>` when in development mode, or when `LOAD_PLUGINS=1` (matching core's behavior)
- Only loads plugin translations based on the same logic
- When running via testem, and the above conditions are met, testem is configured to proxy `core_plugin_tests.js` through to a rails server. (port based on the `UNICORN_PORT` env variable)
- Adds a descriptive error if the plugin `<script>` fails to load. This can happen if the rails server hasn't been started
- Updates the logic for testem browsers. Ember CLI always launches testem in "CI" mode, and we don't really want 3 browsers opening by default. Our CI explicitly specifies the 3 browsers at runtime
* The current evaluation of uppy promises is causing the entire suite to fail
if there's an exception. Instead of using `done` we use the simpler
pattern of returning the promise from the test to force Qunit to wait
until it's completed.
* In some browser conditions `/last.json` will be requested depending on the
particular scroll / performance. This causes the tests not to fail if
that is the case.
* Keyboard shortcuts were not being fully cleared between runs,
resulting in tests failures.
Follow up to 48f70dcd5f. The group
_appeared_ to be saved in the UI until a refresh when it became
clear that the group wasn't actually sent to the DB. This is because
of the way the per-file data was being set with a computed property.
This commit fixes the computed property by changing it to a regular
function and also makes sure the name resetting after the first upload
in multiple uploads works too.
When uploading multiple emoji in Admin/Customize/Emojis
with an emoji Group selected, the group was cleared between
each file uploaded, making bulk uploading of emojis a chore
if anything but the default group was needed.
This commit fixes the issue, introduces tests for emoji-uploader,
and also adds `add-files` appEvents for uppy-upload mixin, same
as the composer-upload-uppy mixin, for interop with tests and so
we don't have to rely on a file upload element's change event.
This reverts commit 2c7906999a.
The changes break some things in local development (putting JS files
into minified files, not allowing debugger, and others)
This means that our DiscourseURL logic will work consistently in tests, where `window.location` doesn't get updated.
To make it work properly, our `replaceState` implementation needed to be updated so that it writes the new URL to Ember's router, rather than bypassing the router and going straight to the `location` API.
A couple of tests needed updating following this fix:
- the composer-test was asserting that the new reply should be missing from the DOM... when really it **should** be in the DOM, and this fix to the test environment makes it so
- the topic-test was making a fake topic fixture based on the data from a topic with a different id. This was causing the topic route to get confused, and 'fix' the currentURL. This commit updates it to use a fixture with consistent data.
This commit also removes the feature detection of `window.history`. It's feature-detected within `discourse-location`. Plus, we don't support any browsers without it.
Previously only `<div>one top element</div>` was allowed because we use `firstChild` instead of `children`.
We also want `<div>one</div><div>two</div>` to work with this method.
This reverts commit ea84a82f77.
This is causing problems with `/theme-qunit` on legacy, non-ember-cli production sites. Reverting while we work on a fix
This is quite complex as it means that in production we have to build
Ember CLI test files and allow them to be used by our Rails application.
There is a fair bit of glue we can remove in the future once we move to
Ember CLI completely.
- Update the TOPIC_URL_REGEXP in `lib/url` so that `navigatedToPost` doesn't attempt to handle slug-less URLs. Slugs must contain at least one non-numeric character, so we can use that fact to make the regex more specific. We want slug-less URLs to be routed as a normal Ember transition, so that `topic-by-slug-or-id` can catch them and re-write the URL to include the slug.
- Update the `topic-by-slug-or-id` afterModel to ensure that the Ember router is used to handle the redirect, rather than DiscourseURL. This guarantees that it will function as a redirect (DiscourseURL.routeTo sometimes bypasses the router). This solves the history problem which was worked-around in 27211ee7bb.
- Update routes/topic to recover from aborted transitions gracefully. This means that following an aborted transition, the browser URL continues to be updated with post numbers as the user scrolls down the page.
This commit extends the options which can be passed to
`PrettyText.markdown` so that which Markdown-it rules and Discourse
Markdown plugins to be used when rendering a text can be customizable.
Currently, this extension is mainly used by plugins.
…after you re-open the modal or select another emoji.
Reason:
Even the most used emoji would be knocked off the list after a while, if you use any emoji outside the recent. Consider the sequence:
✅, 😃, ✅ (from recent), 😀, ✅ (from recent), 😛, ✅ (from recent), 😎, ✅ (from recent), and so on
With the previous logic, the check mark emoji would leave the list, even though it used constantly and (and the time of removal) would the the second most recent used emoji.
---
It doesn't update the list when you use the recent list so that you can click an emoji repeatedly and it doesn't shift from under your mouse cursor.
The app's wrapper element ID is different in tests. `app.rootElement` allows us to consistently obtain the selector in the initializer, so it works correctly regardless of the app's configuration.
Modern Ember only sets up a container when the ApplicationInstance is booted. We have legacy code which relies on having access to a container before boot (e.g. during pre-initializers).
In production we run with the default `autoboot` flag, which triggers Ember's internal `_globalsMode` flag, which sets up an ApplicationInstance immediately when an Application is initialized (via the `_buildDeprecatedInstance` method).
In tests, we worked around the problem by creating a fresh container, and placing a reference to it under `Discourse.__container__`.
HOWEVER, Ember was still creating a Container instance for each ApplicationInstance to use internally, and make available to EmberObjects via injection. The `Discourse.__container__` instance we created was barely used at all.
Having two different Container instances in play could cause some weird issues. For example, I noticed the problem because the `appEvents` instance held by DiscourseURL was different to the `appEvents` instance held by all the Ember components in our app. This meant that events triggered by DiscourseURL were not picked up by components in test mode.
This commit makes the hack more robust by ensuring that Ember re-uses the Container instance which we created pre-boot. This means we only have one Container instance in play, and makes `appEvents` work reliably across all parts of the app. It also adds detailed comments describing the hack, to help future travelers.
Hopefully in future we can remove this hack entirely, but it will require significant refactoring to our initialization process in Core and Plugins.
The mapping-router and map-routes initializer are updated to avoid the need for `container.lookup` during teardown. This isn't allowed under modern Ember, but was previously working for us because the pre-initializer was using the 'fake' container which was not ember-managed.
It was impossible to select the 'all' filter for categories that have
the default list filter set to 'no subcategories'. This happens because
'/all' was not appended to the URL and in the absence of any list filter
('all' or 'none'), the default list filter ('none') was automatically
selected.
da6edc1 introduced the `lookupView` method, which initialized a fresh resolver, and used it to directly look up raw-views (with no caching). This worked well, but was not a clean solution. It required initializing an entirely new resolver, and did not have any caching.
This commit updates the `helperContext` to include access to the registry, and uses it to perform raw-view lookups. As well as re-using the registry, this also means we're making use of the resolver's built-in cache.
I haven't been able to measure any noticeable performance impact from this change, but there is certainly less work being done, so it may be beneficial on older devices.
Co-authored-by: Ayke Halder <rr-it@users.noreply.github.com>
- switches to a raster image QR code so it can be long-pressed (or right
clicked) and added to iCloud keychain
- adds `autocomplete="one-time-code"` to the 2FA input for better
discoverability
Meta topic: https://meta.discourse.org/t/cant-pin-unpin-topic-from-the-title/213444?u=osama.
I know there is an inconsistency between the category of the linked topic (#bug) and the title prefix of this PR, but I really couldn't find anything in the code base that suggested this ever worked before, so I'm categorizing this PR as a feature.
A follow-up to #15117 and #15141. Applies the previous changes to PM-specific fields, makes the preview area take the all the available height of the composer, and unifies more spacing between composer elements.
This commit removes jQuery file uploader from Discourse,
completing the transition to Uppy. The image-uploader
and UploadMixin components are also removed in this commit
as they have already been replaced and are the only things
using jQuery file upload.
.-'~~~`-.
.' `.
| R I P |
| jquery |
| file |
| upload |
| |
\\| 2013-2021 |//
-----------------
This commit introduces scheduled problem checks for the admin dashboard, which are long running or otherwise cumbersome problem checks that will be run every 10 minutes rather than every time the dashboard is loaded. If these scheduled checks add a problem, the problem will remain until it is cleared or until the scheduled job runs again.
An example of a check that should be scheduled is validating credentials against an external provider.
This commit also introduces the concept of a `priority` to the problems generated by `AdminDashboardData` and the scheduled checks. This is `low` by default, and can be set to `high`, but this commit does not change any part of the UI with this information, only adds a CSS class.
I will be making a follow up PR to check group SMTP credentials.
Discourse sent only translation overrides for the current language to the client instead of sending overrides from fallback locales as well. This especially impacted en_GB -> en since most overrides would be done in English instead of English (UK).
This also adds lots of tests for previously untested code.
There's a small caveat: The client currently doesn't handle fallback locales for MessageFormat strings. That is why overrides for those strings always have a higher priority than regular translations. So, as an example, the lookup order for MessageFormat strings in German is:
1. override for de
2. override for en
3. value from de
4. value from en
If the Ember OnError validation test is added, it breaks the "no tests were run" detection (since at least 1 test is always run). This is particularly important when running tests scoped to a single plugin, because there is no indication that you have typo'd the `qunit_single_plugin` query parameter.
This commit allows for using Tab and Shift+Tab to indent
and de-indent selected text in the composer. The selected
text is searched for the most occurrences of either tabs (\t)
or spaces at the start of each line, and that character is
used for indentation of all lines.
This commit introduces a new site setting "google_oauth2_hd_groups". If enabled, group information will be fetched from Google during authentication, and stored in the Discourse database. These 'associated groups' can be connected to a Discourse group via the "Membership" tab of the group preferences UI.
The majority of the implementation is generic, so we will be able to add support to more authentication methods in the near future.
https://meta.discourse.org/t/managing-group-membership-via-authentication/175950
Before this, if you were composing a new topic and then switched the mode to "New Message", the dropdown would disappear.
So if you changed your mind, you'd have to copy the text you typed, cancel, click "New Topic" again, and then paste the text. (and if you already had a title entered too, things would be more complicated…)
The commit 20b2a42f49 broke
upload handlers, because previously we passed through the
native File object to the handler, not the uppy-wrapped
File object.
* Running the tests only in the ember cli env hid the fact that the pending posts feature wasn't working in the legacy environment
* Tests were using ember-cli-only APIs while there are widely used testing APIs in Discourse that support both ember envs
* `ember-test-selectors` was in both dependencies and devDependencies in discourse/package.json
* `qunit-dom` in package.json was not only unused but also defunct, as it wasn't pulled into the legacy env app
A followup to #14501, and #15128.
* DEV: Improve PresenceChannel state storage
Replaces some objects with Maps, and removes the redundant _presentChannels Set.
* DEV: Automatically leave PresenceChannels when in the background
If a tab has been in the background for 10s, or there has been no user activity for 60s, then the user will be removed from all PresenceChannels until activity resumes. Developers can opt-out of this by passing `{onlyWhileActive: false}` to the `enter` method.
The leak was introduced in #11722 and a test was added that relied on it in #14563
This PR fixes the leak (bookmarks-test), fixes the test that relied on it (fast-edit-test), and repleces some ad-hoc code with cloneJSON helper (other files)
This is a big change to change over to using the uppy
upload mixin in the composer by default. This gets rid
of the temporary composer-editor-uppy component, as well
as removing the old ComposerUpload mixin and copying over
any missing functions that were not yet implemented by
ComposerUploadUppy. This has been working well on our
hosting for some time now and has led us to several
bug fixes.
This commit also deletes the old plugin API for adding
preprocessors for the uploads. The accepted method of doing
this now is via an uppy preprocessor plugin, which we have
several examples of in the core codebase.
Leaving the `enable_experimental_composer_uploader` site setting
intact for now because some plugins still rely on it, this
will be removed at a later date.
One step closer to ending the jQuery file uploader saga...
Currently when a user creates posts that are moderated (for whatever
reason), a popup is displayed saying the post needs approval and the
total number of the user’s pending posts. But then this piece of
information is kind of lost and there is nowhere for the user to know
what are their pending posts or how many there are.
This patch solves this issue by adding a new “Pending” section to the
user’s activity page when there are some pending posts to display. When
there are none, then the “Pending” section isn’t displayed at all.
In jQuery file upload land, we were sending a single file through
at a time to matching upload handlers. This in turn required plugin
authors to marshal the files as they came through one by one if they
wanted to group them together to do something with them. Now that
we are using uppy, files come through in the groups they are added
in (for example dropping multiple, selecting multiple from the system
file dialogue).
This commit changes the matching upload handlers to send through
all matching files at once instead of piecemeal.
- Remove JQuery
- Remove legacy `document.webkitHidden` support. None of our currently supported browsers need this
- Use `passive` event listeners. These allows the browser to process the events first, before passing control to us
- Add a new `unseenTime` parameter. This allows consumers to request a delay before being notified about the browser going into the background
- Add a method for removing a callback
- Fire the callback when presence changes in either direction. Previously it would only fire when the user becomes present after a period of inactivity.
- Ensure callbacks are only called once for each state change. Previously they would be called every 60s, regardless of the value
- Listen to the `visibilitychanged` and `focus` events, treating them as equivalent to user action. This will make messagebus re-activate more quickly when switching back to a stale tab
- Add test helpers
- Delete the unused `discourse/lib/page-visible` module.
- Call message-bus's onVisibilityChange API directly, rather than dispatching a fake event on the `document`
* FEATURE: Always show advanced invite options
The UI is more simple and more efficient than how it was when the
advanced options toggle was introduced. It does not make sense to keep
it anymore.
* UX: Minor copy edits
* UX: Merge expire invite controls
There were two controls in the create invite modal. One was a static
text that displayed how much time is left until the invite expires. The
other one was a datetime selector that set the time the invite expires.
This commit merges the two controls in a single one: staff users will
continue to see the datetime selector without the static text and
regular users will only see the static text because they cannot set
when the invite expires.
* UX: Remove invite link
It should only be visible after the invite was created.
Time spent in the 'find module with suffix' portion of our `customResolve` function were adding up to around 100ms-150ms when booting the app. This time is spread over 150+ calls, so it's not immediately obvious in flamegraphs.
This commit implements a (reversed) [Trie](https://en.wikipedia.org/wiki/Trie) which enables fast suffix-based lookups on a list of strings.
In my tests, this requires < 5ms to initialize, and brings the cumulative 'find module with suffix' time down to `< 5ms`. This corresponds to a ~100ms improvement in LCP metrics in my browser.
The only behavior change is to remove support for module filenames which are **not** dasherized. I haven't found any core/theme/plugin modules which are not dasherized in their filenames.