This commit fixes a bug where the silence button is incorrectly displayed on the admin page of a staff user. It's not actually possible to silence a staff user because the backend correctly prevents it, but the frontend isn't checking if the button should be displayed.
Another small bug that this commit fixes is the similar users list not showing up inside the silence/suspend modals due to also a bug in the frontend.
I've also changed the way similar users are loaded so that they're not returned by the `admin/users#show` endpoint anymore and moved them into a new endpoint that the penalize modals (suspend and silence) can call directly to retrieve the list of users. This is done because the similar users list is never shown on the admin user page (`/admin/users/:user_id/:username`); they're only needed when the suspend or silence modals are opened.
Internal topic: t/130014.
This commit converts the Backups page in the admin interface
to follow our new admin interface guidelines.
As part of this work, I've also made `AdminPageHeader` and `AdminPageSubheader`
components that can be reused on any admin page for consistency, that handle
the title and action buttons and also breadcrumbs.
Also renamed `AdminPluginFilteredSiteSettings` to `AdminFilteredSiteSettings` since
it can be used generally to show a subset of filtered site settings, not only
settings for a plugin. Not sure if it's ideal to have to define a new route for this
for every config area, but not sure how else to do it right now.
This commit adds a blue dot next to the "What's New"
link in the admin sidebar if the user has not seen the
new features yet, as a followup to 3e5976f843
which removed the tab on the dashboard that had this same
functionality.
When the admin visits the "What's New" page they count
as having seen all the features straight away. This could
be something we want to change, but for now this keeps the
same functionality.
We used to show New Features in a tab on the dashboard,
but this could get pushed down the page especially on
our hosting. In 043117ca13
we made a separate What's New page, so this commit removes
the dashboard tab and changes the admin notification to
send the admin to /admin/whats-new instead of the dashboard
tab.
This commit fixes a number of bugs in `file_size_restriction` settings and does a little of refactoring to reduce duplicated code in site setting types (the refactoring is necessary to fix one of the bugs).
The bugs in `file_size_restriction` settings that are fixed in this commit:
1. Save/cancel buttons next to a `file_size_restriction` setting are shown upon navigating to the settings page without changes being made to the setting
2. Cancel button that discards changes made to the setting doesn't work
3. Reset button that resets the setting to its default doesn't work
4. Validation error message isn't cleared when resetting/cancelling changes
To repro those bugs, navigate to `/admin/site_settings/category/files` and observe the top 2 settings in the page (`max image size kb` and `max attachment size kb`).
Internal topic: t/134726.
This commit fixes a bug in the redesigned about page where if there's no banner image configured for the page, the top of the page where the banner goes is occupied with large white space. Additionally, this commit also fixes a related bug in the admin config area for the /about page where it's not possible to remove the uploaded banner image.
Very similar to move up/down flag problem fixed here - https://github.com/discourse/discourse/pull/28272
Those are the steps to toggle the flag:
1. click toggle - `saving` CSS class is added;
2. request to backend;
3. `saving` CSS class is removed.
And check if the flag was toggle was:
```ruby
def has_saved_flag?(key)
has_css?(".admin-flag-item.#{key}.saving")
has_no_css?(".admin-flag-item.#{key}.saving")
end
```
If the save action is very fast, then the saving class is removed before the first check.
Therefore I decided to invert it, and once action is finished add `saved` CSS class.
Then we can have a quick positive check:
```ruby
def has_saved_flag?(key)
has_css?(".admin-flag-item.#{key}.saved")
end
```
This commit adds two new getters to the category model:
- `displayName`
- `descriptionText`
These getters are used instead of `name` and `description_text` where appropriate.
On top of this two transformers have been added to allow plugins to alter these getters:
```javascript
api.registerValueTransformer(
"category-display-name",
({ value, context }) =>
value + "-" + context.category.id + "-transformed"
);
```
```javascript
api.registerValueTransformer(
"category-description-text",
({ value, context }) =>
value + "-" + context.category.id + "-transformed"
);
```
Those are the steps to move the flag:
1. open menu;
2. click move up - `saving` CSS class is added;
3. request to backend;
4. `saving` CSS class is removed.
To check if the action was finished we are using this method:
```
def move_up(key)
open_flag_menu(key)
find(".admin-flag-item__move-up").click
has_saved_flag?(key)
self
end
def has_saved_flag?(key)
has_css?(".admin-flag-item.#{key}.saving")
has_no_css?(".admin-flag-item.#{key}.saving")
end
```
However, sometimes specs were failing with `expected to find CSS ".admin-flag-item.spam.saving" but there were no matches`
I think that the problem is with those 2 lines:
```
find(".admin-flag-item__move-up").click
has_closed_flag_menu?
```
If the save action is very fast, then the `saving` class is removed before the first check.
Therefore, to determine that the move action is finished, I am checking if the menu is closed.
During our refactoring of admin badges we decided to link to:
`adminSiteText.edit locale=locale`
Instead of:
`adminSiteText q=key`
After feedback from the community we are reverting this change.
A recent change in FormKit has changed the syntax of this specific component. It's also better to use `<CheckboxGroup />` for this use case too.
Im mixed on writing tests for labels, it's a lot of tests to write for a rather low value.
This commit also slightly tweaks the width of the icon picker, from medium to small.
Admin can create up to 50 custom flags. It is limited for performance reasons.
When the limit is reached "Add button" is disabled and backend is protected by guardian.
The Safari 15 bugfix has been rolled into @babel/preset-env in the most recent version, so we no longer need to carry our vendored copy.
This commit updates @babel/preset-env, runs npx yarn-deduplicate yarn.lock, and removes the vendored transform.
This commit also refactors our theme transpiler to use @babel/preset-env, with the same list of target browsers as our ember-cli build uses. This means we no longer need to maintain a separate list of babel transforms for themes.
In the formkit conversion in 2ca06ba236
we missed setting a type for the UppyImageUploader for badges. Also,
we were not passing down the `image_url` as form data, so when we used
`data.image` for that field the badge was not updating in the UI after
page loads and the image URL was not loading for preview.
Co-authored-by: Joffrey JAFFEUX <j.jaffeux@gmail.com>
Ember's legacy mixin system does not support native-class syntax, so we have to use the non-decorator syntaxes for `action()` and `computed()`.
Eventually, we will need to refactor things to remove these mixins... but today is not that day.
Followup 4aea12fdcb
In certain config areas (like About) we want to be able
to fetch specific site settings by name. In this case,
sometimes we need to be able to fetch hidden settings,
in cases where a config area is still experimental.
Splitting out a different endpoint for this purpose
allows us to be stricter with what we return for config
areas without affecting the main site settings UI, revealing
hidden settings before they are ready.
Form Kit is our new form library/framework for unifying the way forms look across Discourse. The admin config area for the /about page is a new form that isn't currently used, so it makes sense for it to be one of the first forms to be migrated to Form Kit to test the library.
Co-authored-by: Joffrey JAFFEUX <j.jaffeux@gmail.com>
* `@ember/owner` instead of `@ember/application`
* `discourse-i18n` instead of `I18n`
* `{ service } from "@ember/service"` instead of `inject as service`
Followup dd30463276
We missed the explicit `return` when we changed to
async/await, so the model ends up being null on admin
backups.
This means we also have no tests for the backup UI, that
will be fixed in a subsequent PR.
Allow admin to create custom flag which requires an additional message.
I decided to rename the old `custom_flag` into `require_message` as it is more descriptive.
This PR introduces FormKit, a component-based form library designed to simplify form creation and management. This library provides a single `Form` component, various field components, controls, validation mechanisms, and customization options. Additionally, it includes helpers to facilitate testing and writing specifications for forms.
1. **Form Component**:
- The main component that encapsulates form logic and structure.
- Yields various utilities like `Field`, `Submit`, `Alert`, etc.
**Example Usage**:
```gjs
import Form from "discourse/form";
<template>
<Form as |form|>
<form.Field
@name="username"
@title="Username"
@validation="required"
as |field|
>
<field.Input />
</form.Field>
<form.Field @name="age" @title="Age" as |field|>
<field.Input @type="number" />
</form.Field>
<form.Submit />
</Form>
</template>
```
2. **Validation**:
- Built-in validation rules such as `required`, `number`, `length`, and `url`.
- Custom validation callbacks for more complex validation logic.
**Example Usage**:
```javascript
validateUsername(name, value, data, { addError }) {
if (data.bar / 2 === value) {
addError(name, "That's not how maths work.");
}
}
```
```hbs
<form.Field @name="username" @validate={{this.validateUsername}} />
```
3. **Customization**:
- Plugin outlets for extending form functionality.
- Styling capabilities through propagated attributes.
- Custom controls with properties provided by `form` and `field`.
**Example Usage**:
```hbs
<Form class="my-form" as |form|>
<form.Field class="my-field" as |field|>
<MyCustomControl id={{field.id}} @onChange={{field.set}} />
</form.Field>
</Form>
```
4. **Helpers for Testing**:
- Test assertions for form and field validation.
**Example usage**:
```javascript
assert.form().hasErrors("the form shows errors");
assert.form().field("foo").hasValue("bar", "user has set the value");
```
- Helper for interacting with he form
**Example usage**:
```javascript
await formKit().field("foo").fillIn("bar");
```
5. **Page Object for System Specs**:
- Page objects for interacting with forms in system specs.
- Methods for submitting forms, checking alerts, and interacting with fields.
**Example Usage**:
```ruby
form = PageObjects::Components::FormKit.new(".my-form")
form.submit
expect(form).to have_an_alert("message")
```
**Field Interactions**:
```ruby
field = form.field("foo")
expect(field).to have_value("bar")
field.fill_in("bar")
```
6. **Collections handling**:
- A specific component to handle array of objects
**Example Usage**:
```gjs
<Form @data={{hash foo=(array (hash bar=1) (hash bar=2))}} as |form|>
<form.Collection @name="foo" as |collection|>
<collection.Field @name="bar" @title="Bar" as |field|>
<field.Input />
</collection.Field>
</form.Collection>
</Form>
```
Followup 560e8aff75
GitHub auth tokens cannot be made with permissions to
access multiple organisations. This is quite limiting.
This commit changes the site setting to be a "secret list"
type, which allows for a key/value mapping where the value
is treated like a password in the UI.
Now when a GitHub URL is requested for oneboxing, the
org name from the URL is used to determine which token
to use for the request.
Just in case anyone used the old site setting already,
there is a migration to create a `default` entry
with that token in the new list setting, and for
a period of time we will consider that token valid to
use for all GitHub oneboxes as well.
Allow admin to create custom flag which requires an additional message.
I decided to rename the old `custom_flag` into `require_message` as it is more descriptive.
Followup db993cf8fd
Since in the above commit we converted integer site settings
to actual integers then set that as the new `buffered.value`,
the overridden indicator technically thinks the value has changed,
even if the user sets it back to the default:
```
overridden: propertyNotEqual("setting.default", "buffered.value"),
```
We can fix this by converting the parsed integer back to a string
before setting the buffered setting value.
- set in constructor so they're guaranteed to be present, even if async-import hasn't finished yet
- ensure they're all cleaned up properly
- combine two cleanup methods into one
- Delete vendored copy
- Create a JS entrypoint under `static/` which imports all the modes/themes/extensions we need
- Create an async `load-ace-editor` entrypoint
- Update `<AceEditor` component to use the new entrypoint
- De-jquery-ify `<AceEditor`
- Bump `v1.4.13` -> `v1.35.2`
Background:
In order to redrive failed webhook events, an operator has to go through and click on each. This PR is adding a mechanism to retry all failed events to help resolve issues quickly once the underlying failure has been resolved.
What is the change?:
Previously, we had to redeliver each webhook event. This merge is adding a 'Redeliver Failed' button next to the webhook event filter to redeliver all failed events. If there is no failed webhook events to redeliver, 'Redeliver Failed' gets disabled. If you click it, a window pops up to confirm the operator. Failed webhook events will be added to the queue and webhook event list will show the redelivering progress. Every minute, a job will be ran to go through 20 events to redeliver. Every hour, a job will cleanup the redelivering events which have been stored more than 8 hours.
Example:
```hbs
<DBreadcrumbItem
@path="/admin/plugins/{{@plugin.name}}"
@label={{@plugin.nameTitleized}}
/>
```
Using `@path` instead of `@route`+`@model` combo makes it impossible to pass temporarily unresolvable routes.
This fixes a bug with navigating from a model-based route to a parent route.
The AdminPlugin JS model uses a similar pattern to chat models,
where it is a plain JS class manually converting provided
snake_case attributes from the serializer to JS camelCase.
However this doesn't work when it comes to using `add_to_serializer`
in plugins since core does not know about these new attributes.
Instead, we can use a JS function to convert snake_case to camelCase
and use that when initializing AdminPlugin. This commit also moves
similar functions to a new case-converter.js file in
discourse-common/lib.
Followup to e113eff663
We previously sanitized input for integer site settings
on the server side only, which was a bit confusing when
users would enter e.g. 100.5 and end up with 1005, and
not see this reflected in the UI.
Now that we are using native number inputs for these settings,
we can improve the experience a bit by not allowing `.` or `,`
in the input, because it should be whole numbers only, and
add a step size of 1. All other characters are already prevented
in this native number input.
Before checking if flags were reordered on the topic page, we need to ensure that the reorder action was finished. To achieve it "saving" CSS is added and removed when AJAX call is completed.
This commit continues work laid out by ffec8163b0 for the admin config page for the /about page. The last commit set up the user interface, and this one sets up all the wiring needed to make the input fields and save buttons actually work.
Internal topic: t/128544.
We want to allow admins to make new required fields apply to existing users. In order for this to work we need to have a way to make those users fill up the fields on their next page load. This is very similar to how adding a 2FA requirement post-fact works. Users will be redirected to a page where they can fill up the remaining required fields, and until they do that they won't be able to do anything else.
Adds a checkbox to filter untranslated text strings in the admin UI, behind a hidden and default `false` site setting `admin_allow_filter_untranslated_text`.
* Removed the link from the title, so the settings can only be accessed via the settings button on the right
* Added an icon to the "Learn more" link to indicate that it opens a new window
* Made various styling adjustments
Many site settings can be distructive or have huge side-effects
for a site that the admin may not be aware of when changing it.
This commit introduces a `requires_confirmation` attribute that
can be added to any site setting. When it is true, a confirmation
dialog will open if that setting is changed in the admin UI,
optionally with a custom message that is defined in client.en.yml.
If the admin does not confirm, we reset the setting to its previous
clean value and do not save the new value.
When we turn on settings automatically for customers,
we sometimes use `.set_and_log` which will make a staff
action log for the site setting change. This is fine, but
there is no context for customers.
This change allows setting a message with `.set_and_log`, which
will be stored in the `details` column of the staff action log
created, which will show up on `/admin/logs/staff_action_logs`
---------
Co-authored-by: Kelv <kelv@discourse.org>
decorator-transforms (https://github.com/ef4/decorator-transforms) is a modern replacement for babel's plugin-proposal-decorators. It provides a decorator implementation using modern browser features, without needing to enable babel's full suite of class feature transformations. This improves the developer experience and performance.
In local testing with Google's 'tachometer' tool, this reduces Discourse's 'init-to-render' time by around 3-4% (230ms -> 222ms).
It reduces our initial gzip'd JS payloads by 3.2% (2.43MB -> 2.35MB), or 7.5% (14.5MB -> 13.4MB) uncompressed.
This was previously reverted in 97847f6. This version includes a babel transformation which works around the bug in Safari <= 15.
For Cloudflare compatibility issues, check https://meta.discourse.org/t/311390
Inline the helper functions, avoid creating and then immediately destructuring arrays, use complete strings instead of string interpolation, Map instead of a pojo.
* FEATURE: Add Filter for Webhook Events by Status
* Fixing multiple issues
* Lint
* Fixing multiple issues
* Change the range of the status for webhook events
Really fully authored by Jarek, I only made the PR :)
The `DBreadcrumbItem` and `DBreadcrumbContainer` components
introduced in 1239178f49 have
some limitations, mainly that the container has no awareness of
its items, so nothing that requires positional knowledge can
be used. This is needed to use `aria-current` on the last breadcrumb
item, see https://www.w3.org/WAI/ARIA/apg/patterns/breadcrumb/examples/breadcrumb/.
We change `DBreadcrumbItem` to always be a link, removing
the need for `LinkTo`. Then, we introduce a service to keep
track of containers and items (since all items are rendered into
all containers) and make the item itself responsible for registering
to the service, and introduce the needed `aria-current` behaviour.
---------
Co-authored-by: Jarek Radosz <jradosz@gmail.com>
This commit introduces the initial UI for the admin config area for the /about page. The UI isn't wired and doesn't do anything yet, but we're going to iterate on it in future commits.
Internal topic: t/128544.
Continued work on moderate flags UI.
In this PR admins are allowed to change the order of flags. The notify user flag is always on top but all other flags can be moved.
This commit removes the `/admin-revamp` routes which were introduced as a part of an experiment to revamp the admin pages. We still want to improve the admin/staff experience, but we're going to do them within the existing `/admin` routes instead of introducing a completely new route.
Our initial efforts to improve the Discourse admin experience is this commit which introduces the foundation for a new subroute `/admin/config` which will house various new pages for configuring Discourse. The first new page (or "config area") will be `/admin/config/about` that will house all the settings and controls for configuring the `/about` page of Discourse.
Internal topic: t/128544
Followup 73c6bb2593
The admin sidebar was also disappearing on another
child admin route (in this case the docker_manager
plugin update page). Instead of relying on the route
name which is flaky, we can set a boolean when the
sidebar is forced in the root admin route, then
turn it off when leaving admin.
This uses a new nav style with the heirarchy:
```
Breadcrumbs
|- Title
|- Description
|- Third-Level Navigation
```
The navigation bar uses the transparent red-underlined
buttons similar to the user activity page.
Over time all admin pages will use this, but this starts
with the new plugin show page.
---------
Co-authored-by: Ella <ella.estigoy@gmail.com>
We're planning to implement a feature that allows adding required fields for existing users. This PR does some preparatory refactoring to make that possible. There should be no changes to existing behaviour. Just a small update to the admin UI.
For plugins with only an "enabled" site setting, it doesn't
make sense to take them to the site settings page, since the
toggle switch in the list can be used to change enabled/disabled.
This will not be the case for plugins that have their own custom
config page (like Automation), but we will deal with this when
we actually overhaul this plugin to use the new show page.
Also adds another rspec fixture of a test plugin.
Followup 4e7a75a7ec
Several plugins (Gamification, AI) now use the new
plugin show route. Any plugins that are using it can
now redirect to this page via the Settings button in
the plugin list, rather than taking the user to the
old site settings page filtered by category.
This commit introduces the following components:
* DBreadcrumbsContainer - The wrapper template-only component,
which renders all DBreadcrumbsItem components on the page.
* DBreadcrumbsItem - The component that registers a LinkTo
for the breadcrumb trail. The breadcrumb > trail > will
show based on the order these items are rendered on the page.
* BreadcrumbsService - Manages the DBreadcrumbsContainer elements
on the page via DBreadcrumbsContainerModifier.
* DBreadcrumbsContainerModifier - Handles registering DBreadcrumbsContainer
elements with the BreadcrumbsService and deregistering them.
For now, we will only use these breadcrumbs in the admin section
of Discourse, and this initial commit only uses them in admin/plugins.
This is heavily based off of
https://github.com/Bagaar/ember-breadcrumbs,
but will be further modified for our needs.
This reverts commit 0f4520867b.
This has led to two problems:
1. An incompatibility with Cloudflare's "auto minify" feature. They've deprecated this feature because of incompatibility with modern JS syntax. But unfortunately it will remain enabled on existing properties until 2024-08-05.
2. Discourse fails to boot in Safari 15. This is strange, because Safari does support all the required features in our production JS bundles. Even more strangely, things start working as soon as you open the developer tools. That suggests the cause could be a Safari bug rather than a simple incompatibility.
Reverting while we work out a path forward on both those issues.
decorator-transforms (https://github.com/ef4/decorator-transforms) is a modern replacement for babel's plugin-proposal-decorators. It provides a decorator implementation using modern browser features, without needing to enable babel's full suite of class feature transformations. This improves the developer experience and performance.
In local testing with Google's 'tachometer' tool, this reduces Discourse's 'init-to-render' time by around 3-4% (230ms -> 222ms).
It reduces our initial gzip'd JS payloads by 3.2% (2.43MB -> 2.35MB), or 7.5% (14.5MB -> 13.4MB) uncompressed.
* Simplify config nav link generation to always inject the Settings
tab
* Auto-redirect to the first non-settings config link (if there is one)
when the user lands on /admin/plugins/:plugin_id
* Add `extras` to admin plugin serializer so plugins can add more
data on first load
* Add PikadayCalendar page object for system specs, extracted from the
CalendarDateTimePicker to make it more generic.
Those were all low hanging fruits - all were already glimmer components, so this was mostly merging js and hbs files and adding imports.
(occasionally also adds/fixes class names)
At the moment, there is no way to create a group of related watched words together. If a user needed a set of words to be created together, they'll have to create them individually one at a time.
This change attempts to allow related watched words to be created as a group. The idea here is to have a list of words be tied together via a common `WatchedWordGroup` record. Given a list of words, a `WatchedWordGroup` record is created and assigned to each `WatchedWord` record. The existing WatchedWord creation behaviour remains largely unchanged.
Co-authored-by: Selase Krakani <skrakani@gmail.com>
Co-authored-by: Martin Brennan <martin@discourse.org>
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>
This commit ensures that additional keywords for admin
sidebar links (which are also stored in the admin sidebar state
manager) are translated with I18n, which was discussed
in https://meta.discourse.org/t/introducing-experimental-admin-sidebar-navigation/289281/58?u=martin
This also changes the admin sidebar state manager keywords to
not be a TrackedObject -- this is not necessary as keywords are
only set once, and it was causing rendering issues because
the keywords were being set at the same time they were read.
Finally this adds a "theme" keyword to the "Components" link
because we often refer to components as Theme Components
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`.
Include categories when fetching admin/web_hooks and make
'extras' more useful. 'extras' is the mechanism we use to provide
context for rest objects.
However, previously:
* When you fetched many objects, extras was only set on the ResultSet,
not on each object,
* If you need derived data from extras, there wasn't a sensible place to
put this code. Now, you can create an 'ExtrasClass' static field on
your rest model and this class will be used for your extras data,
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.
Why this change?
Instead of dealing with a generic object for `Theme#settings`, we want
to always be dealing with `ThemeSettings` objects.` Previously, we
converted the generic objects to `ThemeSettings` objects in the theme's
adapter `afterFindAll` function. This is not correct because updating
or saving the theme individual reverted the `Theme#settings` back to an
array of generic object.
To fix this problem, the proper way with our REST models is to overwrite
the static `munge` method and create `ThemeSettings` instances there.
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.
This commit fixes an issue where the following happens:
1. You open /admin as a member of the admin_sidebar_enabled_groups
1. You then click the chat icon in the header when you prefer to have
drawer open, or if you just minimise chat into drawer after it opens
fullscreen
1. You lose the admin sidebar panel, and are reset instead to the main
panel
Also included is a bit of refactoring to make it so the forcing of
admin sidebar state is in one place.
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.
In this PR, the admin panel remembers the previous state and restores it when the admin panel is deactivated.
https://github.com/discourse/discourse/pull/25781
However, it would be better to have a more generic solution. When the panel is changed, the previous state is saved in the sidebarState. When a user returns to the specific panel, a previously remembered state is restored.
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.
We have separated and combined modes for sidebar panels.
Separated means the panels show only their own sections,
combined means sections from all panels are shown.
The admin sidebar only shows its own panels, so it must set
the mode to separated; however when we navigate to chat or
home we must revert to the initial mode setttings.
Affects the following settings:
delete_all_posts_and_topics_allowed_groups
experimental_new_new_view_groups
enable_experimental_admin_ui_groups
custom_summarization_allowed_groups
pm_tags_allowed_for_groups
chat_allowed_groups
direct_message_enabled_groups
chat_message_flag_allowed_groups
This turns off client: true for these group-based settings,
because there is no guarantee that the current user gets all
their group memberships serialized to the client. Better to check
server-side first.
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.
When we show the links to installed plugins in the admin
sidebar (for plugins that have custom admin routes) we were
previously only doing this if you opened /admin, not if you
navigated there from the main forum. We should just always
preload this data if the user is admin.
This commit also changes `admin_sidebar_enabled_groups` to
not be sent to the client as part of ongoing efforts to
not check groups on the client, since not all a user's groups
may be serialized.