* FIX: Displaying the wrong number of minimum tags in the composer
When the minimum number of tags set for the category is larger than the minimum number of tags
set in the category tag-groups, the composer was displaying the wrong value.
This commit fixes the value displayed in the composer to show the max value between the required
for the category and the tag-groups set for the category.
This bug was reported on Meta in https://meta.discourse.org/t/tags-from-multiple-tag-groups-required-only-suggest-select-at-least-one-tag/263817
* FIX: Limiting tags in categories not working as expected
When a category was restricted to a tag group A, which was set to only allow
one tag from the group per topic, selecting a tag belonging only to A returned
other tags from A that also belonged to other group/s (if any).
Example:
Tag group A: alpha, beta, gamma, epsilon, delta
Tag group B: alpha, beta, gamma
Both tag groups set to only allow one tag from the group per topic.
If Category 1 was set to only allow tags from the tag group A, and the first tag
selected was epsilon, then, because they also belonged to tag group B, the tags
alpha, beta, and gamma were still returned as valid options when they should not be.
This commit ensures that once a tag from a tag group that restricts its tags to
one per topic is selected, no other tag from this group is returned.
This bug was reported on Meta in https://meta.discourse.org/t/limiting-tags-to-categories-not-working-as-expected/263143.
* FIX: Moving topics does not prompt to add required tag for new category
When a topic moved from a category to another, the tag requirements
of the new category were not being checked.
This allowed a topic to be created and moved to a category:
- that limited the tags to a tag group, with the topic containing tags
not allowed.
- that required N tags from a tag group, with the topic not containing
the required tags.
This bug was reported on Meta in https://meta.discourse.org/t/moving-tagged-topics-does-not-prompt-to-add-required-tag-for-new-category/264138.
* FIX: Editing topics with tag groups from parents allows incorrect tagging
When there was a combination between parent tags defined in a tag group
set to allow only one tag from the group per topic, and other tag groups
relying on this restriction to combine the children tag types with the
parent tag, editing a topic could allow the user to insert an invalid
combination of these tags.
Example:
Automakers tag group: landhover, toyota
- group set to limit one tag from the group per topic
Toyota models group: land-cruiser, hilux, corolla
Landhover models group: evoque, defender, discovery
If a topic was initially set up with the tags toyota, land-cruiser it was
possible to edit it by removing the tag toyota and adding the tag landhover
and other landhover model tags like evoque for example.
In this case, the topic would end up with the tags toyota, land-cruiser,
landhover, evoque because Discourse will automatically insert the
missing parent tag toyota when it detects the tag land-cruiser.
This combination of tags would violate the restriction specified in
the Automakers tag group resulting in an invalid combination of tags.
This commit enforces that the "one tag from the group per topic"
restriction is verified before updating the topic tags and also
make sure the verification checks the compatibility of parent tags that
would be automatically inserted.
After the changes, the user will receive an error similar to:
The tags land-cruiser, landhover cannot be used simultaneously.
Please include only one of them.
Moving all control of 'hidden' into Ember will resolve issues we're seeing with Ember fighting against manual DOM manipulation (both vanilla JS and JQuery).
Looking up `controller:modal` from components is not ideal. However, the next step in the refactoring is to create a modal 'service' which will be able to injected into components cleanly.
Having these things configured at the invocation of showModal is a strange API, and means that any changes to the modal require updating the call sites. It makes much more sense for these to be defined as part of the modal's own template. This was already supported for many of the properties. This commit adds support for the `modalClass` and `titleAriaElementId` config to be passed to DModalBody.
For now there is no deprecation message. Support for passing these things to `showModal` will be dropped as part of an upcoming conversion of modals from controllers to components.
Watched words were converted to regular expressions containing \W, which
handled only ASCII characters. Using [^[:word]] instead ensures that
UTF-8 characters are also handled correctly.
What is the problem?
The main problem here is that we were incorrectly registering the same `onStateChange` callback with `TopicTrackingState`
each time a user reads a post. When a user reads a post, the state in `TopicTrackingState` is updated and it triggers all
the `onStateChange` callbacks which have been registered. In the `CommunitySection` class, we register a callback which
would then call the `onTopicTrackingStateChange` method for each link in the class. For the `EverythingSectionLink` class,
this would lookup the state in `TopicTrackingState` to get a new count of unread/new topics and update the `totalUnread` and
`totalNew` properties which are tracked. For some reason that I have yet to figure out, updating the either of the tracked properties
would result in Ember rerendering the entire `{{#each this.sections as |section|}}` in `component/sidebar/user/custom-sections.hbs`
template. Note that `this.sections` refers to a `@cached` getter in the `SidebarUserCustomSections` class. The problem is that
the `sections` getter is initializing a new bunch of sidebar sections related classes without calling the teardown function.
As a result, we end up registering new `onStateChange` callbacks in `TopicTrackingState` in `CommunitySection` without
removing the old ones. Over time, the number of callbacks build up and we end up slowing down the application. While we do
not know the reason why defining a getter for the `sections` is causing the entire block to re-render, I realized that
it is dangerous to use a getter for `sections` here since we have very little control on when the cached is broken.
Instead, I moved the `sections` getter to a tracked property instead where the property is updated via `appEvents`. With
this change, updating the tracked properties in `EverythingSectionLink` is no longer triggering a complete re-render of the
said block above. We also now call `teardown` on the section objects that has been initialised before updating the `sections`
property.
An extensibility point we support server side is setting meta_data
(topic / post custom fields) with the composer payload.
Previous to this change even though we had a lot of setup code we never
actually sent the payload.
This ensures that on create we send meta_data.
- Update welcome topic copy
- Edit the welcome topic automatically when the title or description changes
- Remove “Create your Welcome Topic” banner/CTA
- Add "edit welcome topic" user tip
a373bf2 updated the behavior of replace-emoji so that the input is treated as unsafe-by-default. fancy_title is already escaped, so we need to mark it as html-safe to avoid it being double-escaped.
There is no need to html-safe the result of replace-emoji - it's already done as part of the helper.
The issues fixed:
1. Previously all static pages (e.g. login-required landing page, /tos, /privacy, forgot-password) were wrapped in the faq-read-tracking component
2. All these pages shared one controller with methods that were relevant to one route
3. There were two route-generating functions: `static-route-builder` and `build-static-route` 🤣
4. They were using the deprecated `renderTemplate()` API
5. A slight misuse of Ember API (`controllerFor()`)
6. Small mark-faq-read related bugs
added site toggle functionality through site settings
added tests to implemented feature
Introduced suggested correction
renamed find_new_topic method and deleted click_new_topic_button method
Currently the /new-category url can be accessed by moderators, regardless of whether the Site Setting for moderators_manage_categories_and_groups is true or false.
On top of this, non authorized users can also access this page but shows errors (no 404 loaded).
Since the 404 redirect happens within Ember, we need to allow the site setting value to be accessed within JS.
After this change all non admin users will see a 404 for this route, the exception being moderators if the moderators_manage_categories_and_groups setting has a value of true.
/t/73360
The problem
When selecting text and clicking the "Edit" button that pops up, this opens up the Fast Edit dialog.
The fast edit feature doesn't work well with non standard characters (non-ascii). If the user selects a string of text that contains non-ascii characters, sometimes they won't save. It is non-obvious to the user why this is happening. This issue occurs more frequently when editing content that is written in non-english languages, as fast-edit doesn't work well with non-ascii characters. We currently do a global replace on a couple of the more obvious quotation marks when the fast edit dialog attempts to save, but there are too many edge cases for foreign language content.
The solution
We can fix this issue by using a catch-all approach for non-ascii characters before the user clicks the edit button to bring up the fast edit dialog. Then we can fallback to the full composer to edit their text, which has much better support for non-ascii characters.
What does this regex do?
The regex used matches any character that is not within the ASCII range of 0x00 to 0x7F, which includes all control characters and non-ASCII characters.
This regex pattern can be used to match any character that is not a standard ASCII character, such as accented characters, non-Latin characters, and special symbols.
This improves keyboard navigation in and out of select-kit components.
The improvements include:
- `Tab` will now dismiss the dropdown once the active element is outside
the select-kit element
- pressing `Escape` will not bubble, this is most noticeable in the
composer, pressing `Esc` there now when a dropdown is expanded will not
dismiss the composer
- `Shift+Tab` will also dismiss the dropdown once focus is outside it
The problem
The fast edit feature doesn't work well with non standard characters (non-ascii). If the user selects a string of text that contains non-ascii characters, then the edit won't save.
The solution
The best solution is to catch those non-ascii characters before the user clicks the edit button to bring up the fast edit dialog. Then we can fallback to the full composer to edit their text, which has much better support for non-ascii characters.
What does this regex do?
The regex used to catch this is [^\x00-\x7F], which matches any character that is not within the ASCII range of 0x00 to 0x7F, which includes all control characters and non-ASCII characters.
This regex pattern can be used to match any character that is not a standard ASCII character, such as accented characters, non-Latin characters, and special symbols.
Ember's implicit injections feature is removed in Ember 4.x. We want to give ourselves more time to migrate to explicit injections, so this commit re-implements our implicit injections as extensions to the base framework classes.
Incremental migration to newer patterns can be achieved using the `@disableImplicitInjections` class decorator (available from `discourse/lib/implicit-injections').
This resolves and unsilences the `implicit-injections` deprecation.
Change mechanism handling `more` button for sidebar.
Before it was using HTML details tag.
To make tests more reliable, we are switching to use ember runloop.
What is the problem?
The TopicTrackingState is a service on the client side that is used to store
state of topics which is new or has unread posts for a given user. The state
is updated via various means and the one in concern here is whenever we load
a new topic list from the server. When a topic list is loaded from the server,
we sync this new topic list with the states in TopicTrackingState. There is also
a hard limit on the number of states that is stored by TopicTrackingState for
performance reasons and the limit is currently set to 4000. It was noticed that
once this limit has been reached, syncing a topic list with TopicTrackingState can
result in the registered state change callbacks to be called unnecessarily. This
is because during `TopicTrackingState#sync` we call `TopicTrackingState#removeTopic`
if the topic in question is neither new or unread to a user. However, `TopicTrackingState#removeTopic`
would call `TopicTrackingState#_afterStateChange` even if nothing was removed.
What is the fix?
This commit fixes the problem by checking that `TopicTrackingState#_afterStateChange` is only
called in `TopicTrackingState#removeTopic` when a topic is actually removed.
- Ensure changing timezones are reflected immediately in the date-time-input (the computed property was missing a dependent key)
- Ensure date-input doesn't lose timezone information (calling `toDate()` causes moment timestamps to lose timezone information)
This was created to resolve issues in the discourse-calendar plugin (https://github.com/discourse/discourse-calendar/pull/399)
In the expand table event handler, we currently rely on `event.target`
to select the table being expanded. Sometimes, the target is the svg icon
wrapped inside the button instead of the button itself. This throws
things off.
This change uses `currentTarget` which refers to the button
element even if the event originated from svg icon.
* DEV: move sidebar community section to database
Before, community section was hard-coded. In the future, we are planning to allow admins to edit it. Therefore, it has to be moved to database to `custom_sections` table.
Few steps and simplifications has to be made:
- custom section was hidden behind `enable_custom_sidebar_sections` feature flag. It has to be deleted so all forums, see community section;
- migration to add `section_type` column to sidebar section to show it is a special type;
- migration to add `segment` column to sidebar links to determine if link should be displayed in primary section or in more section;
- simplify more section to have one level only (secondary section links are merged);
- ensure that links like `everything` are correctly tracking state;
- make user an anonymous links position consistence. For example, from now on `faq` link for user and anonymous is visible in more tab;
- delete old community-section template.
This commit fixes a bug on subfolder setups where the user messages
inbox dropdown will always be blank. This is because we were comparing
URLs using values from `router.currentURL` and `router.urlFor` where
`router.currentURL` does not include `router.rootURL` while
`router.urlFor` does.
Ember's implicit injections feature is removed in Ember 4.x. We want to give ourselves more time to migrate to explicit injections, so this commit re-implements our implicit injections as extensions to the base framework classes.
Incremental migration to newer patterns can be achieved using the `@disableImplicitInjections` class decorator (available from `discourse/lib/implicit-injections').
This resolves and unsilences the `implicit-injections` deprecation.
When navigating with the keyboard, the select-kit would not close when
focus was moved to an element outside of the body. For example, when
navigating via Tab or Shift+Tab, once the end (or beginning) of the list
was reached, focus would move out of the SK element, but the SK itself
would stay visible.
Switching from a click event to a focusout event solves the issue and
covers both mouse and keyboard navigation.
Ran into an issue with these hooks preventing click events on anchors from completing (because the triggered rerender cancels the click). See:
https://github.com/discourse/discourse-header-search/pull/24
This change should have no effect on existing usage of these hooks. Current usage is limited to:
- legacy navigation (should be a no-op)
- reactions plugin (should be a no-op)
- discourse-header-search (will fix the issue!)
* FIX: Empty video thumbnails
This fix ensures that topic video thumbnail generation is completed
before the composer is allowed to submit which should prevent some bugs
around missing thumbnails on video topics.
* move callback to on upload-success
User status updates come from the server in a map where keys are user IDs.
If user.trackStatus() is called for a user model without an ID, the model
cannot identify its status updates and silently misses them. It's quite hard to
notice that a user rendered in the UI doesn't receive live status updates.
Also, it's not immediately obvious what's the reason of the problem.
A warning will be very helpful here.
Named outlets are deprecated and will be removed in Ember 4.x.
Backwards-compatibility shims are introduced so that plugin overrides to `controller:composer` are ported to `service:composer`.
After removing `TextareaTextManipulation` from `ChatComposer` and using `TextareaInteractor` as a proxy, one function has been forgotten: `paste(event)` which is not available in glimmer components anymore, and even less avaiable now that the mixin is not tied to a component anymore but a real DOM node. As a solution we now add a manual paste event listener which will call `paste(event)`.
This pull request is a full overhaul of the chat-composer and contains various improvements to the thread panel. They have been grouped in the same PR as lots of improvements/fixes to the thread panel needed an improved composer. This is meant as a first step.
### New features included in this PR
- A resizable side panel
- A clear dropzone area for uploads
- A simplified design for image uploads, this is only a first step towards more redesign of this area in the future
### Notable fixes in this PR
- Correct placeholder in thread panel
- Allows to edit the last message of a thread with arrow up
- Correctly focus composer when replying to a message
- The reply indicator is added instantly in the channel when starting a thread
- Prevents a large variety of bug where the composer could bug and prevent sending message or would clear your input while it has content
### Technical notes
To achieve this PR, three important changes have been made:
- `<ChatComposer>` has been fully rewritten and is now a glimmer component
- The chat composer now takes a `ChatMessage` as input which can directly be used in other operations, it simplifies a lot of logic as we are always working a with a `ChatMessage`
- `TextareaInteractor` has been created to wrap the existing `TextareaTextManipulation` mixin, it will make future migrations easier and allow us to have a less polluted `<ChatComposer>`
Note ".chat-live-pane" has been renamed ".chat-channel"
Design for upload dropzone is from @chapoi
Due to the order we were parsing markdown, bbcode [url] elements were not
handled properly.
`[url]https://example.com/path[/url]` was not currectly parsing cause
linkify was detecting the url as: `https://example.com/path[/url]` which is
legit.
To resolve this I swapped url to use a replace rule, and instead re-parsed
the internal payload and injected the tokens in.
This fix is complex cause we support stuff like
`[url][b]test.com[/b][/url]`
So we need to parse the content inside url `[b]test.com[/b]`
* FIX: Blank video thumbnails
On some mobile and possibly other browsers, the automatic video
thumbnail generation would create blank or all white images.
This commit addresses several different issues that was preventing image
generation from working correctly on mobile.
* fix typo
The updated user menu is the default for new sites, and will soon be enabled on older sites. This commit removes the 'EXPERIMENTAL' warning from the new `registerUserMenuTab` API, and adds a note to the `addUserMenuGlyph` documentation.
Followup to 17ba00c395.
Fix for https://meta.discourse.org/t/-/261917
This fixes a usability issue where the user couldn't switch to the user
menu when the search menu was visible and the text in the input was
selected.
Explanation: The `click` event is triggered both when clicking and when
selecting some text and clicking. This means that when selecting text in
the search input, at the end of the selection event, a click event was
triggered. And if that click event happened to be outside of the search
menu, then the menu would be dismissed.
Previously, we fixed this by checked if a current text selection was
present. But that results in a small side-effect of not switching to
other menus. This PR switches to setting a flag during `mouseDown` and
then using that flag when evaluating whether to trigger clickOutside or
not.
It's backward compatible so still supports our 3.28 ember-source.
The visible change is finally getting rid of this message:
```
WARNING: Node v18.12.0 is not tested against Ember CLI on your platform. We recommend that you use the most-recent "Active LTS" version of Node.js. See https://git.io/v7S5n for details.
```
---
`@ember/string` dependency is added for future compatibility. See: https://github.com/ember-cli/ember-cli/pull/10125
---
`tests/helpers/index.js` is unused for now, but is a nice pattern. We could move some of our test setup into local `setupApplicationTest/setupRenderingTest/setupTest` helpers.
Co-authored-by: David Taylor <david@taylorhq.com>
All supported browsers use `transitionend` event now, so this code is not necessary and makes it difficult to use that event in tests (you'd have to trigger all variants to cover the bases)
That function was used only in core (no hits in all-the*) in two places, so I think it's rather safe to just trash it without deprecating it first.
(History Corner – this helper was originally added in the initial commit of Discourse! 1839614bcc/app/assets/javascripts/discourse/components/transition_helper.js.coffee)
Following a change in e9f7262813 which prevents the notification level to be returned from the update endpoint, the model couldn't update itself. This commit makes the update manually and adds a test to prevent future regressions.
Note we could also change the backend endpoint, but this should work correctly with minimum risk.
This feature will allow sites to define which emoji are not allowed. Emoji in this list should be excluded from the set we show in the core emoji picker used in the composer for posts when emoji are enabled. And they should not be allowed to be chosen to be added to messages or as reactions in chat.
This feature prevents denied emoji from appearing in the following scenarios:
- topic title and page title
- private messages (topic title and body)
- inserting emojis into a chat
- reacting to chat messages
- using the emoji picker (composer, user status etc)
- using search within emoji picker
It also takes into account the various ways that emojis can be accessed, such as:
- emoji autocomplete suggestions
- emoji favourites (auto populates when adding to emoji deny list for example)
- emoji inline translations
- emoji skintones (ie. for certain hand gestures)
EmberObject's `reopen` feature allows changes to be made to the prototype of the class, but it does not work with native class fields. Native class field values are set on the instance in the constructor, and therefore override any values from the prototype.
This commit implements a workaround which detects possible field overrides and then sets the values during the `init()` function of the EmberObject. This isn't perfect - old field values will still be present while any constructor function is running. But in the vast majority of cases, it should provide parity with old non-native-class EmberObject properties.
This commit also adds a warning when trying to override fields on non-EmberObject classes. There is no change in behavior here - we're just warning about the fact it doesn't work.
When running `yarn install` in a yarn workspace, the lifecycle hooks in the root package.json are not triggered. https://github.com/yarnpkg/yarn/issues/5790
As a workaround, we can additionally run `patch-package` from the `javascripts/discourse/package.json` `postinstall` hook. `patch-package` is idempotent, so it doesn't matter if it is triggered multiple times.
Longer term we intend to move to pnpm, which has built-in patch support.
Fixes the unnecessary message when starting ember server:
```
Invalid watchman found, version: [2023.04.03.00] did not satisfy [>= 3.0.0].
Visit https://ember-cli.com/user-guide/#watchman for more info.
```
Moves a couple things from discourse-boot.js to a different JS file imported from app/app.js.
This is a forwards compatible technique to import and throw data on the window.
One thing to make note of, though, is that if the virtual-dom and discourse-widget-hbs/helpers were previously included in the build elsewhere, they will now become part of the app bundle.
Later, when using embroider, all bundles will be chunks, and webpack will optimize which chunk contains which modules appropriately.
When selecting the "Keep bookmark" in the user preference for what to do after a bookmark reminder is sent, it does not propagate to the drop-down in the "Create bookmark" modal. Instead it defaults to "Keep bookmark and clear reminder". All other options work fine.
We set a default ("Keep bookmark and clear reminder") if no user preference is found, However, this uses the index of the option, and the index of the first option ("Keep bookmark") is 0, which is treated as falsey in JavaScript, thus causing the default to be selected.
This change switches from logical "or" conditional `||` operator to nullish coalescing `??` operator.
Previously, public custom sections were only visible to logged-in users. In this PR, we are making them visible to anonymous as well.
The reason is that Community Section will be moved into custom section model to be easily editable by admins.
Followup to 6ad9e4ad06,
I was not aware that `site.categories` is undefined if
the user is anon and the site is login_required, this
handles that scenario and does not continue trying to
generate CSS.
This commit adds a system to generate CSS variables and classes for categories
and hashtags, which will be used in an effort to remove baked icons for hashtags
and add color to those icons.
This is in two parts. First I added an initializer generate a category color CSS
variable style tag in the head tag that looks like this:
```css
:root {
--category-1-color: #0088CC;
--category-2-color: #808281;
--category-3-color: #E45735;
--category-4-color: #A461EF;
--category-5-color: #ee56c9;
--category-6-color: #da28c2;
--category-7-color: #ab8b0a;
--category-8-color: #45da37;
...
}
```
The number is the category ID. This only generates CSS variables for categories
the user can access based on `site.categories`. If you need the parent color variable
you can just use the `category.parentCategory.id` to get it.
Then, I added an initializer to generate a hashtag CSS style tag using these variables.
Only the category and channel hashtags need this, the category one generates the
background-gradient needed for the swatch, and the channel just generates a color
for the icon. This is done in an extendable way using the new `api.registerHashtagType`
JS plugin API:
```css
hashtag-color--category-1 {
background: linear-gradient(90deg, var(--category-1-color) 50%, var(--category-1-color) 50%);
}
hashtag-color--category-2 {
background: linear-gradient(90deg, var(--category-2-color) 50%, var(--category-2-color) 50%);
}
hashtag-color--category-5 {
background: linear-gradient(90deg, var(--category-5-color) 50%, var(--category-4-color) 50%);
}
...
.hashtag-color--channel-4 {
color: var(--category-12-color);
}
.hashtag-color--channel-92 {
color: var(--category-24-color);
}
```
Note if a category has a parent, its color is used in the gradient correctly. The numbers
here are again IDs (e.g. channel ID, category ID) and the channel’s chatable ID is used
to find the category color variable.
The status should use the word "user" instead of "flag", for example
"approved user" instead of "approved flag". The problem was caused by
a mismatched type.
Using the `mouseDownOutside` event was problematic here because two
events were being triggered consecutively: `mouseDown`
would toggle the menu off and `click` would then toggle it back on. This
switches the logic to use `clickOutside` again, but with two changes:
- it limits the action to the `search-menu` key (so that theme component
overrides can do their own handling)
- it does not trigger the event when there is an active text selection
(this was the original reason for switching to `mouseDownOutside`, see
https://github.com/discourse/discourse/pull/14788)
The translation key is built using the name of the reviewable as it was
defined in Ruby. The chat plugin uses the `Chat` namespace and defines
`Chat::ReviewableMessage`. This was then transformed to
`chat::reviewable_message`, but it should be `chat_reviewable_message`
to resemble the other translation keys.
Back in d0e1c222f7 we added
performance measuring for uppy uploads using the Performance
API in the browser. However we recently discovered that
sometimes performance.measure can fail if for whatever reason
one of the marks passed to it does not exist:
> Failed to upload ... Performance.measure: Given mark name, upload-uppy-....-create-multipart-success, is unknown
This would cause the entire upload to fail, which is unnecessary
for a debugger. Improve the situation so if this happens again
the error does not stop the upload.
The following are the changes being introduced in this commit:
1. Instead of mapping the query language to various query params on the
client side, we've decided that the benefits of having a more robust
query language far outweighs the benefits of having a more human readable query params in the URL.
As such, the `/filter` route will just accept a single `q` query param
and the query string will be parsed on the server side.
1. On the `/filter` route, the tags filtering query language is now
supported in the input per the example provided below:
```
tags:bug+feature tagged both bug and feature
tags:bug,feature tagged either bug or feature
-tags:bug+feature excluding topics tagged bug and feature
-tags:bug,feature excluding topics tagged bug or feature
```
The `tags` filter can also be specified multiple
times in the query string like so `tags:bug tags:feature` which will
filter topics that contain both the `bug` tag and `feature` tag. More
complex query like `tags:bug+feature -tags:experimental` will also work.
Previously, reorder on touch screens was disabled https://github.com/discourse/discourse/pull/20769.
This PR enables it again. However, link has to be hold for 300 ms to enable drag&drop. Otherwise, normal scroll is performed.
As part of another regression, we realized that the plugins tab is visible to moderators, but they cannot interact with anything inside without triggering authorization errors.
This change hides the plugin tab for non-admin users.
When an admin removes all the categories from their personal sidebar configuration, the section should remain visible to them with the “Configure default categories” prompt.
Similar solution for tags.
/t/95036
Instead of being tied to the old implementation and constraints, a
dedicated route and controller for the `discovery.filter` app route will
allow us to iterate on changes much faster.
Before, incorrectly filled fields were marked with red border. Now, additional information under the field is displayed to notify the user what is incorrect.
/t/93696