Fixes two issues:
- frontend was reloading the page when clicking-to-remove avatar
- backend wasn't allowing resetting the setting by deleting all avatars
When the user sees no results in their admin sidebar query,
we are adding two additional links:
* "Search site settings" - Navigates to the site settings page
with the filter prefilled in the search
* "Admin user list" - Navigates to the user list with the filter
prefilled in the username search
This will bridge the gap until we have a full admin-wide search.
Also make admin site setting search param refresh on filter changes
---------
Co-authored-by: Jarek Radosz <jradosz@gmail.com>
Automatically add `moderators` and `admins` auto groups to specific site settings.
In the new group-based permissions systems, we just want to check the user’s groups since it more accurately reflects reality
Affected settings:
- tag_topic_allowed_groups
- create_tag_allowed_groups
- send_email_messages_allowed_groups
- personal_message_enabled_groups
- here_mention_allowed_groups
- approve_unless_allowed_groups
- approve_new_topics_unless_allowed_groups
- skip_review_media_groups
- email_in_allowed_groups
- create_topic_allowed_groups
- edit_wiki_post_allowed_groups
- edit_post_allowed_groups
- self_wiki_allowed_groups
- flag_post_allowed_groups
- post_links_allowed_groups
- embedded_media_post_allowed_groups
- profile_background_allowed_groups
- user_card_background_allowed_groups
- invite_allowed_groups
- ignore_allowed_groups
- user_api_key_allowed_groups
To add a components link to the sidebar refactoring was required to create unique URLs for themes and components. Before the query param was used. After changes, we have two URLs `/admin/customize/themes` and `/admin/customize/components`.
This commit changes the identifier displayed in the navigation tree of
the theme objects editor from the generic "category 1" to "<category
name>, <category 2 name>" when a property of typed categories is set as
the identifier.
Example:
For the following theme objects schema:
```
some_setting:
type: objects
default: []
schema:
name: <some scheme name>
identifier: list_of_categories
properties:
list_of_categories:
type: categories
```
If the `list_of_categories` property's value has been set to `category
1` and `category 2`, the navigation tree will display `category 1,
category 2` as the text to represent the object in the navigation tree.
This commit changes enum typed theme objects property to be optional.
Previously, an enum typed property is always required but we have found
that this might not be ideal so we want to change it.
Why this change?
For a `typed: objects` theme setting with an enum property, we are
adding a `default` key for `type: enum` fields which will be used
as the default value on the client side.
```
some_objects_setting:
type: objects
schema:
name: field
properties:
enum_field:
type: enum
default: awesome
choices:
- nice
- cool
- awesome
```
Why this change?
Prior to this change, the input fields were not displaying when adding
an object to a objects typed theme setting which has a default value of
`[]`. This is because the `fields` getter was not being recomputed.
In this PR, all references in the UI to the word "`upgrade`" are changed to "`update`". This is to differentiate the update process in self-hosted sites from the plan "upgrade" process in hosted sites.
Follow-up to the PR: https://github.com/discourse/docker_manager/pull/208
Why this change?
Before this change, the validation error message shown to the user when
saving a theme objects setting is very cryptic. This commit changes the
validation error messages to be displayed on top of the editor instead.
Note that I don't think this way of displaying is the ideal state we
want to get to but given the time we have this will do for now.
Why this change?
In the categories, groups and tags selectors, we were showing a
validation error message when a property that is not required but
has a min validation is empty. In this case, we should not be displaying
the min validation error message because the property is allowed to be
empty.
Why this change?
When adding a new object, we want to switch to the input fields of the
new object instead of just appending the new object to the list of
objects as we believe this is a better UX flow.
Why this change?
The field components to select categories, groups and tags had quite a
bit of logic duplicated between them. This commit refactors the logic
to remove most of the duplication so that we can introduce changes
without having to make the changes in multiple places.
... rather than just the category id.
In order for the user to have selected a category, the category must
have been loaded and it's useful for the category chooser to provide
this fetched category so that it doesn't need to be refetched.
In the future, it would be better to store the categories that the
chooser knows about in local component state, so that the category
doesn't need to be fetched from the id map, but this, at least, puts the
API in place.
Why this change?
This is a follow-up to 86b2e3a.
Basically, we want to allow people to select more than 1 group as well.
What does this change do?
1. Change `type: group` to `type: groups` and support `min` and `max`
validations for `type: groups`.
2. Fix the `<SchemaThemeSetting::Types::Groups>` component to support the
`min` and `max` validations and switch it to use the `<GroupChooser>` component
instead of the `<ComboBoxComponent>` component which previously only supported
selecting a single group.
Why this change?
Prior to this change, the `SchemaThemeSetting::Editor#tree` was creating a
new `Tree` instance which holds instances of `Node`. Both classes
consisted of tracked properties. The problem with this approach is that
when any tracked properties is updated, Ember will revaluate
`SchemaThemeSetting::Editor#tree` and because that method always return
a new instance of `Tree`, it causes the whole navigation tree to
rerender just because on tracked property changed.
This rerendering of the whole navigation tree every time made it hard to
implement simple features like hiding a section in
9baa820d53. Instead of being able to just
declare a tracked property to hide/show a section, we end up with a more
complicated solution.
This commit rewrites `SchemaThemeSetting::Editor` to depend on Ember
components to form the tree structure instead. As needed, each component
in the tree structure can declare its own tracked property as necessary.
Why this change?
In cdba864598, we added support for adding
a description which will be displayed under the input of each property
on the client side.
Currently this convention in the locale file is followed:
```
en:
theme_metadata:
settings:
objects_setting:
description: <description> for the setting
schema:
properties:
name: <description for the name property>
links:
name: <description for the name property in link>
url: <description for the url property in link>
```
Since we now want to allow the label to be translated as well, we will
be changing the convention to the following:
```
en:
theme_metadata:
settings:
objects_setting:
description: <description> for the setting
schema:
properties:
name:
label: <label for the name property>
description: <description for the name property>
links:
name:
label: <label for the name property>
description: <description for the name property in link>
url:
label: <label for the url property>
description: <description for the url property in link>
```
If the locale file does not provide a `label` key under the property's
name, the client side will just display the property's name as the
label for the input field.
Descriptions for the `category-list`, `file-size-restriction` and `file-types-list` site/theme settings aren't rendered due to a bug that was introduced when those components were migrated to Glimmer components. This commit fixes the bug which is that arguments passed to .gjs components should be accessed as `@argument` and not `this.arugment` inside the `<template>` tag.
Why this change?
This is a follow-up to 86b2e3aa3e.
Basically, we want to allow people to select more than 1 category as well.
What does this change do?
1. Change `type: category` to `type: categories` and support `min` and `max`
validations for `type: categories`.
2. Fix the `<SchemaThemeSetting::Types::Categories>` component to support the
`min` and `max` validations and switch it to use the `<CategorySelector>` component
instead of the `<CategoryChooser>` component which only supports selecting one category.
Why this change?
Previously, we were preloading the necessary metadata for
`adminCustomizeThemes.show.schema` route in the
`adminCustomizeThemes.show` route. This is wasteful because we're
loading data upfront when the objects setting editor may not be used.
This change also lays the ground work for a future commit where we need
to be shipping down additional metadata which may further add to the
payload.
Why this change?
When a property of `type: tags` is required, we should be displaying the
"at least 1 tag is required" validation error message when there are no
tags selected in the `TagChooser` compoment. However, we were passing
`this.min` as the `count` attribute when generating the translation
string which is incorrect as `this.min` is not always set.
Why this change?
While working on the tag selector for the theme object editor, I
realised that there is an extremely high possibility that users might want to select
more than one tag. By supporting the ability to select more than one
tag, it also means that we get support for a single tag for free as
well.
What does this change do?
1. Change `type: tag` to `type: tags` and support `min` and `max`
validations for `type: tags`.
2. Fix the `<SchemaThemeSetting::Types::Tags>` component to support the
`min` and `max` validations
Why this change?
Prior to this change, the category selector was not clearable and did
not allow a none value. This is incorrect as the category selector
should be clearable and should allow a none value when the property is
not required.
Why this change?
Prior to this change, the group selector was using the `<GroupChooser>`
component which is a `<MultiSelectComponent>` and is not ideal in our
situation when we only allow a single group to be selected.
The other problem is that we are doing an async load of the groups when
it is already loaded and available in the `Site` service.
Why this change?
This is a continuation of a30d73f255
In our schema, we support the `min` and `max` validation
rules like so:
```
some_objects_setting
type: objects
schema:
name: some_object
properties:
id:
type: float
validations:
min: 5
max: 10
```
While the validations used to validate the objects on the server side,
we should also add client side validation for better UX.
What does this change do?
Since the integer and float input fields share very very similar logic
in the component. This commit pulls the common logic into
`admin/components/schema-theme-setting/number-field.gjs` which
`admin/components/schema-theme-setting/types/integer.gjs` and `admin/components/schema-theme-setting/types/float.gjs`
will inherit from.
Why this change?
This is a continuation of 8de869630f.
In our schema, we support the `min` and `max` validation
rules like so:
```
some_objects_setting
type: objects
schema:
name: some_object
properties:
id:
type: integer
validations:
min: 5
max: 10
```
While the validations used to validate the objects on the server side,
we should also add client side validation for better UX.
Why this change?
In our schema, we support the `min_length` and `max_length` validation
rules like so:
```
some_objects_setting
type: objects
schema:
name: some_object
properties:
title:
type: string
validations:
min_length: 1
max_length: 10
```
While the validations used to validate the objects on the server side,
we should also add client side validation for better UX.
This commit changes the API for registering the plugin config
page nav configuration from a server-side to a JS one;
there is no need for it to be server-side.
It also makes some changes to allow for 2 different ways of displaying
navigation for plugin pages, depending on complexity:
* TOP - This is the best mode for simple plugins without a lot of different
custom configuration pages, and it reuses the grey horizontal nav bar
already used for admins.
* SIDEBAR - This is better for more complex plugins; likely this won't
be used in the near future, but it's readily available if needed
There is a new AdminPluginConfigNavManager service too to manage which
plugin the admin is actively viewing, otherwise we would have trouble
hiding the main plugin nav for admins when viewing a single plugin.
Why this change?
If an object doesn't have any child objects for a particular property
and we try to add one through the editor, an error will be raised.
```
Cannot read properties of undefined (reading 'push')
at SchemaThemeSettingEditor.addItem (editor.js:190:1)
```
Currently, a new sidebar link for what's new and reports is going to the main dashboard page and activates the proper tab.
It might be problematic, especially, when the instance has a lot of problems. In that case, it would be difficult for admin to find reports or what’s new which is rendered at the bottom of the page.
Therefore separate pages for reports and what's new were created.
Reports were moved to a component that is shared between a separate page and the dashboard.
Why this change?
This is a first pass at styling the editor for creating/editing/updating
an objects typed theme setting. Only the desktop view is being
considered at the current moment.
The objects typed theme setting is still behind a feature flag at this moment so there is no need for us to get the styling perfect. The purpose of this PR is to get us to a state which we can quickly iterate with a designer on.
This commit makes it so the site settings filter controls and
the list of settings input editors themselves can be used elsewhere
in the admin UI outside of /admin/site_settings
This allows us to provide more targeted groups of settings in different
UI areas where it makes sense to provide them, such as on plugin pages.
You could open a single page for a plugin where you can see information
about that plugin, change settings, and configure it with custom UIs
in the one place.
In future we will do this in "config areas" for other parts of the
admin UI.
Why this change?
When editing a objects typed theme setting, the input fields which are
rendered should include a description so that the user knows the purpose
of the field which they are changing.
What does this change do?
This change adds support for adding description to each property in the
schema for an object by following a given convention in the locale file.
For a schema like this:
```
objects_setting:
type: objects
schema:
name: section
properties:
name:
type: string
required: true
links:
type: objects
schema:
name: link
properties:
name:
type: string
required: true
validations:
max_length: 20
url:
type: string
```
Description for each property in the object can be added like so:
```
en:
theme_metadata:
settings:
objects_setting:
description: <description> for the setting
schema:
properties:
name: <description for the name property>
links:
name: <description for the name property in link>
url: <description for the url property in link>
```
If the a description is not present, the input field will simply not
have an description.
Also note that a description for a theme setting can now be added like
so:
```
en:
theme_metadata:
settings:
some_other_setting: <This will be used as the description>
objects_setting:
description: <This will also be used as the description>
```
With the new admin sidebar restructure, we have a link to "Installed plugins". We would like to ensure that when the admin is searching for a plugin name like "akismet" or "automation" this link will be visible. Also when entering the plugins page, related plugins should be highlighted.
Why this change?
Prior to this change, there is no description being displayed for
objects typed theme setting because we were rendering a button instead
of the components for the various setting types which will render the
setting's description.
What does this change do?
1. Introduce `SiteSettings::Description` compoment to centralise the HTML
being rendered across all settings component.
2. Renders the `SiteSettings::Description` component after the edit
button in `site_setting.hbs`.
This commit adds new plugin show routes (`/admin/plugins/:plugin_id`) as we move
towards every plugin having a consistent UI/landing page.
As part of this, we are introducing a consistent way for plugins
to show an inner sidebar in their config page, via a new plugin
API `register_admin_config_nav_routes`
This accepts an array of links with a label/text, and an
ember route. Once this commit is merged we can start the process
of conforming other plugins to follow this pattern, as well
as supporting a single-page version of this for simpler plugins
that don't require an inner sidebar.
Part of /t/122841 internally
Why this change?
On the `/admin/customize/themes/<:id>` route, we allow admins to edit
all settings via a settings editor. Prior to this change, trying to edit
and save a typed objects theme settings will result in an error on the
server.
Why this change?
On a slow network, using the `AceEditor` component will result in a blob
of text being shown first before being swapped out with the `ace.js`
editor after it has completed loading.
There is also a problem when setting the theme for the editor which
would result in a "flash" as reported in
https://github.com/ajaxorg/ace/issues/3286. To avoid this, we need to
load the theme js file before displaying the editor.
What does this change do?
1. Adds a loading spinner and set the `div.ace` with a `.hidden` class.
2. Once all the relevant scripts and initialization is done, we will
then remove the loading spinner and remove `div.ace`.
Why this change?
The `/admin/customize/themes/:id/schema/name` route is a work in
progress but we want to be able to start navigating to it from the
`/admin/customize/themes/:id` route.
What does this change do?
1. Move `adminCustomizeThemes.schema` to a child route of
`adminCustomizeThemes.show`. This is because we need the model
from the parent route and if it isn't a child route we end up
having to load the theme model again from the server.
1. Add the `objects_schema` attribute to `ThemeSettingsSerializer`
1. Refactor `SiteSettingComponent` to be able to render a button
so that we don't have to hardcode the button rendering into the
`SiteSettings::String` component
Adds a site setting to include a post's content in penalty message.
When silencing/suspending a user from a post, or a reviewable with
a post, adds an option to include a post's content in the email
message by default.
With the adjustments of `btn-transparent` in https://github.com/discourse/discourse/pull/24666, there are more buttons that could use this class instead of `btn-flat`. This mostly relates to `x` close buttons, but also includes composer and chat toggles.
The primary difference between these styles is that `btn-transparent` never has a background, where `btn-flat` may have a hover or focus background.
Continue from https://github.com/discourse/discourse/pull/25673.
This commit starts building the inputs pane of schema theme settings. At the moment only string fields are rendered, but more types will be added in future commits.
This commit adds a loading spinner when installing a theme as sometimes
installing a theme can take quite a bit of time this way we have some
indication that things are still working as the theme is being
installed.
This commit is the first of a series of commits that will allow themes to define complex settings types by declaring a schema of the setting structure that Discourse core will use to build a UI for the setting automatically. We implement the navigation logic and support for multiple levels of nesting in this commit and we'll continue building this new system gradually in future commits.
Internal topic: t/116870.
* Revert "FEATURE: Use native number fields for integer inputs (#24984)"
This reverts commit 8fce890ead.
* FIX: Deprecate NumberField, use <input> instead
This reverts #24984 as it introduced regressions (behavioral and visual) and instead it deprecates the NumberField component and replaces its uses in core with native `<input>` elements.
Having the admin sidebar code in an instance initializer is not
ideal because:
* It runs during app boot which may not even be necessary based on site settings
* It makes it hard for plugins to register additional links in time without resorting
to before/after initializer gymnastics
This PR moves the admin sidebar into a lib and creates the panel
in custom-sections.js, then the sections and links are loaded when
the main sidebar component is rendered, which leaves plugins enough
time to add additional links in an initializer.
---------
Co-authored-by: David Taylor <david@taylorhq.com>
This commit adds some more links to the admin sidebar and
removes some to give it more parity with the old nav structure.
This also adds the `addAdminSidebarSectionLink` plugin API to
replace the admin-menu plugin outlet, which is used by plugins
like docker-manager to add links to the old admin nav.
Followup to be841e666e,
this commit does not show the themes/components list filter
if there are < 10 items in the list. This brings parity
with the search input, which does the same. If you only have
a few themes/components, then this extra UI is just unnecessary.
---------
Co-authored-by: Jarek Radosz <jradosz@gmail.com>
In this PR we introduced the enabled/disabled components filter.
https://github.com/discourse/discourse/pull/25105
However, components are slightly more complicated and can be used/unused/enabled/disabled.
- Add plugin outlet to `AdminUserFieldItem`
- Add ability to include custom fields when saving `AdminUserFieldItem`
- Update plugin API with `includeUserFieldPropertiesOnSave` per ☝️
- Add `DiscoursePluginRegistry` to `UserFieldsController` to add custom columns
This is v0 of admin sidebar navigation, which moves
all of the top-level admin nav from the top of the page
into a sidebar. This is hidden behind a enable_admin_sidebar_navigation
site setting, and is opt-in for now.
This sidebar is dynamically shown whenever the user enters an
admin route in the UI, and is hidden and replaced with either
the:
* Main forum sidebar
* Chat sidebar
Depending on where they navigate to. For now, custom sections
are not supported in the admin sidebar.
This commit removes the experimental admin sidebar generation rake
task but keeps the experimental sidebar UI for now for further
testing; it just uses the real nav as the default now.
Followup e37fb3042d
* Automatically remove the prefix `Discourse ` from all the plugin titles to avoid repetition
* Remove the :discourse_dev: icon from the author. Consider a "By Discourse" with no labels as official
* We add a `label` metadata to plugin.rb
* Only plugins made by us in `discourse` and `discourse-org` GitHub organizations will show these in the list
* Make the plugin author font size a little smaller
* Make the commit sha look like a link so it's more obvious it goes to the code
Also I added some validation and truncation for plugin metadata
parsing since currently you can put absolutely anything in there
and it will show on the plugin list.
Reverts
- DEV: maxmind license checking failing tests #24534
- UX: Show if MaxMind key is missing on IP lookup #18993
These changes are leading to surprising results, our logs are now filling up with warnings on dev environments
We need the change to be redone
* Remove checkmark for official plugins
* Add author for plugin, which is By Discourse for all discourse
and discourse-org github plugins
* Link to meta topic instead of github repo
* Add experimental flag for plugin metadata and show this as a
badge on the plugin list if present
---------
Co-authored-by: chapoi <101828855+chapoi@users.noreply.github.com>
In the long term we should aim to modernize these places, but for now this change will make them compatible with Ember 5.x (while maintaining compatibility with Ember 3.28)
When we started using NumberField for integer site settings
in e113eff663, we did not end up
passing down a min/max value for the integer to the field, which
meant that for some fields where negative numbers were allowed
we were not accepting that as valid input.
This commit passes down the min/max options from the server for
integer settings then in turn passes them down to NumberField.
c.f. https://meta.discourse.org/t/delete-user-self-max-post-count-not-accepting-1-to-disable/285162
Follow-up to #24278 that is slightly less trivial.
* Some were "trivial" usages that were missed in the previous PR because the same file that had at least one other non-trivial usage.
* These involve extra arguments or inheritance but I have checked that they seem correct.
- Remove vendored copy
- Update Rails implementation to look for language definitions in node_modules
- Use webpack-based dynamic import for hljs core
- Use browser-native dynamic import for site-specific language bundle (and fallback to webpack-based dynamic import in tests)
- Simplify markdown implementation to allow all languages into the `lang-{blah}` className
- Now that all languages are passed through, resolve aliases at runtime to avoid the need for the pre-built `highlightjs-aliases` index
This removes all trivial usages of the `{{action}}` keyword (the helper form, not the modifier form), where trivial means:
1. It's a co-located component (`.hbs` next to `.js`)
2. The JS file has a default export that is native class
3. `{{action "foo"}}` or `(action "foo")` with no extra arguments
4. There is a corresponding `foo()` method defined on the class (not inherited, etc)
There are more usages that is slightly more involved (with arguments, etc) that we can deal with, but this PR seems big enough so I just included the easiest cases here.
To aid review, each file is converted in an individual commit, and the matching method is temporary annotated with `@__action__` instead of the normal `@action`. This forces a git diff when it is already annotated as `@action`.
* DEV: {{action}} -> @action admin-penalty-post-action.hbs
* DEV: {{action}} -> @action admin-report.hbs
* DEV: {{action}} -> @action admin-watched-word.hbs
* DEV: {{action}} -> @action emoji-value-list.hbs
* DEV: {{action}} -> @action bool.hbs
* DEV: {{action}} -> @action category.hbs
* DEV: {{action}} -> @action secret-value-list.hbs
* DEV: {{action}} -> @action category-list.hbs
* DEV: {{action}} -> @action color.hbs
* DEV: {{action}} -> @action compact-list.hbs
* DEV: {{action}} -> @action group-list.hbs
* DEV: {{action}} -> @action host-list.hbs
* DEV: {{action}} -> @action named-list.hbs
* DEV: {{action}} -> @action simple-list.hbs
* DEV: {{action}} -> @action tag-group-list.hbs
* DEV: {{action}} -> @action tag-list.hbs
* DEV: {{action}} -> @action value-list.hbs
* DEV: {{action}} -> @action watched-word-form.hbs
* DEV: {{action}} -> @action composer-messages.hbs
* DEV: {{action}} -> @action section.hbs
* DEV: {{action}} -> @action user-status-picker.hbs
* DEV: cleanup @__action__ -> @action
Followup to b53449eac9,
it was too easy to add broken routes which would break
configuration for the whole site, so now we validate ember
routes on save.
Followup to b53449eac9, we cannot
generate the links to plugin admin pages in this way because it
depends on which plugins are installed; we would need to somehow
do it at runtime. Leaving it out for now, for people who need to
find these admin routes the Ember Inspector extension for Chrome
can be used in the meantime.
NOTE: Most of this is experimental and will be removed at a later
time, which is why things like translations have not been added.
The new /admin-revamp UI uses a sidebar for admin nav. This initial
step adds a script to generate a map of all the current admin nav
into a format the sidebar to read. Then, people can experiment
with different changes to this structure.
The structure can then be edited from `/admin-revamp/config/sidebar-experiment`,
and it is saved to local storage so people can visually experiment with different ways
of showing the admin sidebar links.
As much as possible I would like us to avoid having to go the with a global event listener on click/mouseover. For now I have removed all cases of `data-tooltip`, if we clearly identify a use case of a global event listener we might reconsider this.
The following changes are also included:
- by default tooltips won't attempt to focus first focusable element anymore
- tooltip will now use `cursor: pointer` by default
- a new service has been introduced: `InternalTooltip` which is responsible to track the current instance displayed by a `<DTooltip />`. Portal elements when replaced are not properly cleaned and I couldn't figure out a way to have a proper hook to ensure the previous `DTooltipInstance` is properly set as not expanded; this problem was very visible when using a tooltip as interactive and hovering another tooltip, which would replace the interactive tooltip as not closed.
As of #23867 this is now a real package, so updating the imports to
use the real package name, rather than relying on the alias. The
name change in the package name is because `I18n` is not a valid
name as NPM packages must be all lowercase.
This commit also introduces an eslint rule to prevent importing from
the old I18n path.
For themes/plugins, the old 'i18n' name remains functional.
We'll probably have to keep the globals around for compatibility, but we should always import it ourselves. We'll followup with an updated eslint config to enforce this.
`escape` from `pretty-text/sanitizer` is a re-export of the same
function defined in `discourse-common`. Updating the import paths
across the codebase to use the `discourse-common` import path.
`escape` is a rather simple function that can be accomplished with
a regular expression in `discourse-common`.
On the other hand, the remaining parts in `pretty-text/sanitizer`
has a lot of code, PLUS it depend on the rather heavy "xss" NPM
library.
Currently, most of the consumers of `pretty-text/sanitizer` are of
the `{ escape }` varient. This is resolved by this PR.
The remaining usages are either:
1. via/through `PrettyText` which is essentially gated behind
loading the markdown-it bundle, OR
2. via `sanitize` from `discourse/lib/text`
I believe we may ultimately be able to move all the usages to behind
the markdown-it bundle (or, equivilantly, set up another lazy bundle
for `sanitize`) and be able to shed the sanitization code and the
"xss" library from the initial page load.
`discourse/lib/text` also defines a `sanitizeAsync` which is gated
behind loading the markdown-it bundle.
Looking through the usages of `sanitize`, I believe most of these
can be safely switched to use `sanitizeAsync`, in that they are
already in an asynchrnous path that handles a server response. Most
of them are actually rendering a piece of server-generated HTML
message as flash message, so I am not sure there really is value in
sanitizing (we should be able to trust our own server?), but in any
case, code-wise, they should already be able to absorb the async
just fine.
I am not sure if `sanitize` and `sanitizeAsync` are actually API
compatible – they both take `options` but I think those `options` do
pretty different things. This is somethign for another person to
investigate down the road in another PR.
According to `all-the-plugins`, `discourse-graphviz` also import
from this location, so perhaps we should PR to update. That being
said, it doesn't really hurt anything to keep the alias around for
a while.
Currently, if you set an integer site setting in the admin interface and include thousands separators, you will silently configure the wrong value.
This PR replaces TextField inputs for integer site settings with NumberField. It also cleans the numeric input of any non-digits in the backend in case any separators make it through.
1. actually call `popupAjaxError`, thanks :P
2. don't close a modal on error
3. use `extractError()` instead of manually joining error messages
4. …or passing just the error object to `this.flash`
1. Use `this.` instead of `{{action}}` where applicable
2. Use `{{fn}}` instead of `@actionParam` where applicable
3. Use non-`@` versions of class/type/tabindex/aria-controls/aria-expanded
4. Remove `btn` class (it's added automatically to all DButtons)
5. Remove `type="button"` (it's the default)
6. Use `concat-class` helper
This commit contains a few improvements:
* Use LinkTo instead of a button with a weird action referencing the
controller to navigate to the filtered settings for a plugin
* Add an AdminPlugin model with tracked properties and use that when
toggling the setting on/off and in the templates
* Make it so the Settings button for a plugin navigates to the correct
site setting category instead of always just going to the generic
"plugins" one if possible
In this commit 2.5 years ago, variables for showOnUserCard and showOnProfile were removed, but we still used them in the component. e29605b
This corrects the variable names and adds a test to confirm the text is now shown.
provide the ability to edit theme settings in the json editor, and also copy them as a text file so they can be pasted into another instance.
Reference: /t/65023
- Convert `admin-incoming-email` modal to component-based API
- Testing that the modal was working in local development was extremely challenging due to the need for `rejected` and `bounced` emails. Something that is not easy to stub in a local dev environment. To make this process more smooth for future developers I have added a new rake task:
```
desc "Creates sample email logs"
task "email_logs:populate" => ["db:load_config"] do |_, args|
DiscourseDev::EmailLog.populate!
end
```
That will generate fully functional email logs in development to be toyed with.
<img width="787" alt="Screenshot 2023-07-20 at 3 27 04 PM" src="https://github.com/discourse/discourse/assets/50783505/47b3fe34-cd7e-49a5-8fe6-768c0fbd1aa2">
The gjs/gts formats are a new pattern for authoring Ember components. This commit introduces support for these patterns to our build pipeline for core/plugins, and converts a handful of components to use the new format. It also introduces relevant updates to our linting config, and to our sample vscode configuration.
Co-authored-by: Godfrey Chan <godfreykfc@gmail.com>
Co-authored-by: Krystan HuffMenne <kmenne+github@gmail.com>
Fixes an issue where saving a theme translation would reset unsaved
changes made to other theme translations.
Also cleans up unused `saveSettings` and `saveTranslations` actions.
Co-authored-by: Jarek Radosz <jradosz@gmail.com>
Async, modern syntax, no `on()` component hooks, const extraction, sorted props, template tweaks, and a small filtering bugfix (filtering could throw errors after saving a category-selection setting)
This commit implements many changes to topic and comments embedding. It
deprecates the class_name field from EmbeddableHost and suggests using
the className parameter. discourse_username parameter has been
deprecated and it will fetch it from embedded site from the author or
discourse-username meta.
See the updated code sample from Admin > Customize > Embedding page.
* FEATURE: Add className parameter for Discourse embed
* DEV: Hide class_name from EmbeddableHost
* DEV: Deprecate class_name field of EmbeddableHost
* FEATURE: Use either author or discourse-username meta tag
* DEV: Deprecate discourse_username parameter
* DEV: Improve embed code sample
The JS component definition is in the admin bundle, but the template was in the main bundle. This was identified while attempting to colocate component templates in the discourse/app directory
1. The events table had broken styling, making each row overflow
2. It had confusing routes: `/:id` for "edit" and `/:id/events` for "show" (now it's `/:id/edit` and `/:id` respectively)
3. There previously was an unused backend action (`#edit`) - now it is used (and `web_hooks/:id/events` route has been removed)
4. There was outdated/misplaced/duplicated CSS
5. And more
* FEATURE: Show similar users when penalizing a user
Moderators will be notified if other users with the same IP address
exist before penalizing a user.
* FEATURE: Allow staff to penalize multiple users
This allows staff members to suspend or silence multiple users belonging
to the same person.
This PR enables the [`no-action-modifiers`](https://github.com/ember-template-lint/ember-template-lint/blob/master/docs/rule/no-action-modifiers.md) template lint rule and removes all usages of the `{{action}}` modifier in core.
In general, instances of `{{action "x"}}` have been replaced with `{{on "click" (action "x")}}`.
In many cases, such as for `a` elements, we also need to prevent default event handling to avoid unwanted side effects. While the `{{action}}` modifier internally calls `event.preventDefault()`, we need to handle these cases more explicitly. For this purpose, this PR also adds the [ember-event-helpers](https://github.com/buschtoens/ember-event-helpers) dependency so we can use the `prevent-default` handler. For instance:
```
<a href {{on "click" (prevent-default (action "x"))}}>Do X</a>
```
Note that `action` has not in general been refactored away as a helper yet. In general, all event handlers should be methods on the corresponding component and referenced directly (e.g. `{{on "click" this.doSomething}}`). However, the `action` helper is used extensively throughout the codebase and often references methods in the `actions` hash on controllers or routes. Thus this refactor will also be extensive and probably deserves a separate PR.
Note: This work was done to complement #17767 by minimizing the potential impact of the `action` modifier override, which uses private API and arguably should be replaced with an AST transform.
This is a followup to #18333, which had to be reverted because it did not account for the default treatment of modifier keys by the {{action}} modifier.
Commits:
* Enable `no-action-modifiers` template lint rule
* Replace {{action "x"}} with {{on "click" (action "x")}}
* Remove unnecessary action helper usage
* Remove ctl+click tests for user-menu
These tests now break in Chrome when used with addEventListener. As per the comment, they can probably be safely removed.
* Prevent default event handlers to avoid unwanted side effects
Uses `event.preventDefault()` in event handlers to prevent default event handling. This had been done automatically by the `action` modifier, but is not always desirable or necessary.
* Restore UserCardContents#showUser action to avoid regression
By keeping the `showUser` action, we can avoid a breaking change for plugins that rely upon it, while not interfering with the `showUser` argument that's been passed.
* Revert EditCategoryTab#selectTab -> EditCategoryTab#select
Avoid potential breaking change in themes / plugins
* Restore GroupCardContents#showGroup action to avoid regression
By keeping the `showGroup` action, we can avoid a breaking change for plugins that rely upon it, while not interfering with the `showGroup` argument that's been passed.
* Restore SecondFactorAddTotp#showSecondFactorKey action to avoid regression
By keeping the `showSecondFactorKey` action, we can avoid a breaking change for plugins that rely upon it, while not interfering with the `showSecondFactorKey` property that's maintained on the controller.
* Refactor away from `actions` hash in ChooseMessage component
* Modernize EmojiPicker#onCategorySelection usage
* Modernize SearchResultEntry#logClick usage
* Modernize Discovery::Categories#showInserted usage
* Modernize Preferences::Account#resendConfirmationEmail usage
* Modernize MultiSelect::SelectedCategory#onSelectedNameClick usage
* Favor fn over action in SelectedChoice component
* Modernize WizardStep event handlers
* Favor fn over action usage in buttons
* Restore Login#forgotPassword action to avoid possible regression
* Introduce modKeysPressed utility
Returns an array of modifier keys that are pressed during a given `MouseEvent` or `KeyboardEvent`.
* Don't interfere with click events on links with `href` values when modifier keys are pressed
This PR enables the [`no-action-modifiers`](https://github.com/ember-template-lint/ember-template-lint/blob/master/docs/rule/no-action-modifiers.md) template lint rule and removes all usages of the `{{action}}` modifier in core.
In general, instances of `{{action "x"}}` have been replaced with `{{on "click" (action "x")}}`.
In many cases, such as for `a` elements, we also need to prevent default event handling to avoid unwanted side effects. While the `{{action}}` modifier internally calls `event.preventDefault()`, we need to handle these cases more explicitly. For this purpose, this PR also adds the [ember-event-helpers](https://github.com/buschtoens/ember-event-helpers) dependency so we can use the `prevent-default` handler. For instance:
```
<a href {{on "click" (prevent-default (action "x"))}}>Do X</a>
```
Note that `action` has not in general been refactored away as a helper yet. In general, all event handlers should be methods on the corresponding component and referenced directly (e.g. `{{on "click" this.doSomething}}`). However, the `action` helper is used extensively throughout the codebase and often references methods in the `actions` hash on controllers or routes. Thus this refactor will also be extensive and probably deserves a separate PR.
Note: This work was done to complement #17767 by minimizing the potential impact of the `action` modifier override, which uses private API and arguably should be replaced with an AST transform.
Commits:
* Enable `no-action-modifiers` template lint rule
* Replace {{action "x"}} with {{on "click" (action "x")}}
* Remove unnecessary action helper usage
* Remove ctl+click tests for user-menu
These tests now break in Chrome when used with addEventListener. As per the comment, they can probably be safely removed.
* Prevent default event handlers to avoid unwanted side effects
Uses `event.preventDefault()` in event handlers to prevent default event handling. This had been done automatically by the `action` modifier, but is not always desirable or necessary.
* Restore UserCardContents#showUser action to avoid regression
By keeping the `showUser` action, we can avoid a breaking change for plugins that rely upon it, while not interfering with the `showUser` argument that's been passed.
* Revert EditCategoryTab#selectTab -> EditCategoryTab#select
Avoid potential breaking change in themes / plugins
* Restore GroupCardContents#showGroup action to avoid regression
By keeping the `showGroup` action, we can avoid a breaking change for plugins that rely upon it, while not interfering with the `showGroup` argument that's been passed.
* Restore SecondFactorAddTotp#showSecondFactorKey action to avoid regression
By keeping the `showSecondFactorKey` action, we can avoid a breaking change for plugins that rely upon it, while not interfering with the `showSecondFactorKey` property that's maintained on the controller.
* Refactor away from `actions` hash in ChooseMessage component
* Modernize EmojiPicker#onCategorySelection usage
* Modernize SearchResultEntry#logClick usage
* Modernize Discovery::Categories#showInserted usage
* Modernize Preferences::Account#resendConfirmationEmail usage
* Modernize MultiSelect::SelectedCategory#onSelectedNameClick usage
* Favor fn over action in SelectedChoice component
* Modernize WizardStep event handlers
* Favor fn over action usage in buttons
* Restore Login#forgotPassword action to avoid possible regression
Currently we can’t add a case-sensitive watched word if another one
exists with a different case. For example, the existing watched word
`Meta` has been created and is case-sensitive. Now an admin tries to add
`metA` while marking it as case-sensitive too, this won’t work and the
word won’t be added.
This patch changes this behavior by allowing to add same words that have
different cases, so the example above will now work as expected.
We still check for uniqueness but case-sensitivy is now taken
into account. It means that if the watched word `meta` already exists
and is not case-sensitive then it will not be possible to add `Meta`
(case-sensitive or not) as `meta` already matches every possible
variations of this word.
* FEATURE: Add case-sensitivity flag to watched_words
Currently, all watched words are matched case-insensitively. This flag
allows a watched word to be flagged for case-sensitive matching.
To allow allow for backwards compatibility the flag is set to false by
default.
* FEATURE: Support case-sensitive creation of Watched Words via API
Extend admin creation and upload of Watched Words to support case
sensitive flag. This lays the ground work for supporting
case-insensitive matching of Watched Words.
Support for an extra column has also been introduced for the Watched
Words upload CSV file. The new column structure is as follows:
word,replacement,case_sentive
* FEATURE: Enable case-sensitive matching of Watched Words
WordWatcher's word_matcher_regexp now returns a list of regular
expressions instead of one case-insensitive regular expression.
With the ability to flag a Watched Word as case-sensitive, an action
can have words of both sensitivities.This makes the use of the global
Regexp::IGNORECASE flag added to all words problematic.
To get around platform limitations around the use of subexpression level
switches/flags, a list of regular expressions is returned instead, one for each
case sensitivity.
Word matching has also been updated to use this list of regular expressions
instead of one.
* FEATURE: Use case-sensitive regular expressions for Watched Words
Update Watched Words regular expressions matching and processing to handle
the extra metadata which comes along with the introduction of
case-sensitive Watched Words.
This allows case-sensitive Watched Words to matched as such.
* DEV: Simplify type casting of case-sensitive flag from uploads
Use builtin semantics instead of a custom method for converting
string case flags in uploaded Watched Words to boolean.
* UX: Add case-sensitivity details to Admin Watched Words UI
Update Watched Word form to include a toggle for case-sensitivity.
This also adds support for, case-sensitive testing and matching of Watched Word
in the admin UI.
* DEV: Code improvements from review feedback
- Extract watched word regex creation out to a utility function
- Make JS array presence check more explicit and readable
* DEV: Extract Watched Word regex creation to utility function
Clean-up work from review feedback. Reduce code duplication.
* DEV: Rename word_matcher_regexp to word_matcher_regexp_list
Since a list is returned now instead of a single regular expression,
change `word_matcher_regexp` to `word_matcher_regexp_list` to better communicate
this change.
* DEV: Incorporate WordWatcher updates from upstream
Resolve conflicts and ensure apply_to_text does not remove non-word characters in matches
that aren't at the beginning of the line.
Also, the change in insert-hyperlink (from `this.linkUrl.indexOf("http") === -1` to `!this.linkUrl.startsWith("http")`) was intentional fix: we don't want to prevent users from looking up topics with http in their titles.
This switches us to use the modern ember resolver package, and re-implements a number of our custom resolution rules within it. The legacy resolver remains for now, and is used as a fallback if the modern resolver is unable to resolve a package. When this happens, a warning will be printed to the console.
Co-authored-by: Peter Wagenet <peter.wagenet@gmail.com>
```sh
npx ember-holy-futuristic-template-namespacing-batman-codemod ensure-template-only-has-backing-class
```
We would like to colocate templates but, when no backing class exists, colocated templates extend `templateOnly` instead of `Ember.Component`. Generating the backing class helps avoid any behavioral changes.
We can also run the `tagless-ember-components-codemod` to put the tags into the templates at which point we could convert these back to template-only components.
* FIX: Make watched words uploads work as intended
Currently when we upload a file containing watched words, it will always
add the words to the action that was initially selected: this is the
`block` action by default but if changing manually the action in the URL
to `flag` for example, then this action will be selected and uploaded
watched words will be categorised as `flag` no matter what.
The problem lies with how the component works: it’s an Uppy object where
extra data is defined to provide an action key to the server but when
navigating to another listed action, while this action key is properly
updated on the component itself, the underlying Uppy object has already
been created and doesn’t care about the new value.
This patch solves this by using the `_perFileData` method instead of
`data`: the former is merged just before uploading a file whereas the
latter is used when the Uppy object is created.