This PR makes the secondary sidebar in the admin UI more consistent
navigation experience:
* Added a coloured background for links on hover
* Replaced the bold text and line style with a distinct background
highlight, ensuring it complements the admin sidebar while maintaining
its own identity
* Bringing in arrow indicators to match the active navigation state in
the category settings
### Before
<img width="488" alt="image"
src="https://github.com/user-attachments/assets/aa843766-0ed7-435a-8880-6f0598aa4782"
/>
### After
<img width="475" alt="image"
src="https://github.com/user-attachments/assets/ec31bab9-0f51-4757-ab06-95a961ae17ee"
/>
Refactors the Singleton mixin into a class decorator that directly mutates target classes with the same static property & functions as the mixin. This maintains the public interface of such singleton classes.
Classes refactored to use the singleton class decorator:
Session
User
Site
I removed singleton functionality from LogsNotice since services are already singletons and what we had previously defined in its customized createCurrent method could be replaced by directly injecting the relevant services into the class. This also allowed us to get rid of the logs-notice initializer.
We are adding a deprecation warning to the Singleton mixin instead of deleting since there are plugins that could still be using it.
Followup 3135f472e2
Fixes an issue where the wizard branding step would
error if SiteSetting.logo was null, this did not come
up during testing because in our testing discourse-logo-sketch-small.png
is used for the logo settings.
This commit contains various quality improvements to
our site setup wizard, along with some rearrangement of
steps to improve the admin setup experience and encourage
admins to customize the site early to avoid "all sites look the
same" sentiment.
#### Step rearrangement
* “Your site is ready” from 3 → 4
* “Logos” from 4 → 5
* “Look and feel” from 5 → 3
#### Font selector improvements
Changes the wizard font selector dropdown to show
a preview of all fonts with a CSS class so you don't
have to choose the font to get a preview.
Also makes the fonts appear in alphabetical order.
#### Preview improvements
Placeholder text changed from lorem ipsum to actual topic titles,
category names, and post content. This makes it feel more "real".
Fixes "undefined" categories. Added a date to the topic timeline.
Fixes button rectangles and other UI elements not changing in
size when the font changed, leading to cut off text which looked super
messy. Also fixed some font color issues.
Fixed table header alignment for Latest topic list.
#### Homepage style selector improvements
Limited the big list of homepage styles to Latest, Hot, Categories with latest topics,
and Category boxes based on research into the most common options.
#### Preview header
Changed the preview header to move the hamburger to the left
and add a chat icon
#### And more!
Changed the background of the wizard to use our branded blob style.
For consistency, we are updating all sidebar links that
point to an /admin/customize/site_settings URL to their
own config pages, in preparation for more focused config
pages in future. This will mitigate the issue we have now,
which is that every sidebar link you click showing a different
UI to admins.
This commit moves admin/config/login-and-authentication to
establish the pattern.
The customize routes add CSS classes that make these admin
config pages look different from the ones under /admin/config.
We want all config routes to be under /admin/config as well.
This commit moves the emoji, user fields, and permalinks pages
out of customize and into config, updating all references and
adding more rails routes as needed.
Also renames admin emojis route to emoji, emoji is singular and plural.
This commit replaces the `full_name_required` setting with a new `full_name_requirement` setting to allow more flexibility with the name field in the signup form. The new setting has 2 options, "Required at signup" and "Optional at signup", which are equivalent to the true/false possibilities of the old setting, and a third option "Hidden at signup" that hides the name field from the signup form, making it effectively optional too.
New sites will have the "Hidden at signup" option as the default option, and existing site will continue to use the option that maps to their current configuration.
Internal topic: t/136746.
This commit adds `showLogin` as an available action to the post menu buttons. They can use this action to show the login form when there is no user logged in.
It also adds a small CSS tweak to prevent the content from the post menu to being user selectable. This was causing small UX issues in touch devices.
This will make the 'auto' glimmer-topic-list feature aware of these modifications, so that the new topic-list will not be enabled until they're resolved.
- Remove JS
- Remove "Loading..." text. This has been been broken for a while due to some conflicting discourse-ai CSS. Also, animating the `content:` property like this requires the browser to repaint/reflow, which cannot be done while JS is executing.
- Replace animated SVG with divs animated via CSS. When JS is executing, browsers pause animations of transform properties inside SVGs. This limitation does not exist on regular CSS animations. So with this change, the animation continues smoothly even you run an infinite loop in JS.
To ensure the splash screen remains "contentful" for LCP purposes, an SVG background-image is used
There is no change to the visual look of the animation
I think the log messages were used for initial production trials but the
log messages are actually not very useful in the grand scheme of things.
If the timing of the job is important information, one can get it by
enabling Sidekiq logging and obtain the information from there. There is
no need for us to flood the logs with these messages.
Also the messages will contain at most 100 ids so it is just alot of
noise in general.
We currently query the posts table without an order when notifying users of moved posts. Generally the query will return the lowest post number post (b/c ID correlates with post_number in most cases) but not always. This adds an order to the post query in notify_moved_posts job.
Also I removed some if statement nesting with early returns / guard clauses.
Admins and moderators can see a user's deleted posts via the `/u/:username/deleted-posts` route. Admins can always see any post on the site, but that's not always the case for moderators, e.g., they can't see all PMs. So, this route accounts for that and excludes posts that a moderator wouldn't be allowed to see if they were not deleted.
However, there's currently a problem with that logic where admins who also have moderation privileges, are treated the same way as moderators and prevented from seeing posts that pure moderators can't see. This commit fixes that problem and only applies the permission checks to moderators who don't have admin privileges.
Internal topic: t/143107.
This commit makes the `contact_url` in the /about page behave as an absolute URL instead of a relative one if it doesn't explicitly start with a slash or a protocol. This prevents situation where, e.g., `www.example.com` is specified in the setting and the contact URL anchor tag ends up with a `href` that navigates to `<site address>/www.example.com` instead of just `www.example.com`. We prevent this by adding 2 leading slashes `//` to `contact_url` which makes the `href` resolves to the specified `contact_url` using the same protocol as the current site's.
Internal topic: t/143907.
When lurking on a Discourse as anonymous, if the sidebar is enabled, and a section contains only secondary links that are not visible to anonymous users, we should not display the "more..." button.
Otherwise it feels broken because clicking on it does nothing, since there are no "visible" links to be shown.
Internal ref t/144716
* wip: return full name in /notifications.json
* DEV: test for full name
* DEV: add test for enable_names=true
* DEV: add notification6, cleanup
* DEV: fix tests
This PR involves cleaning up the codebase from my (@keegangeorge's) todos.
In particular:
- Remove Form Template related todos (these are no longer in the roadmap)
- Remove old left-over AI summarization related code after moving to AI (https://github.com/discourse/discourse-ai/pull/658)
- Update one form template related spec
Followup 203f93bcaf
This commit makes sure the background for all the admin
site settings filters (including the filter input and
override checkbox) is consistent no matter what the theme,
as it currently changes based on theme.
This update adds a ✨ _new_ `<PostList />` component, along with it's child components (`<PostListItem/>` and `<PostListItemDetails />`). This new generic component can be used to show a list of posts.
It can be used like so:
```js
/**
* A component that renders a list of posts
*
* @component PostList
*
* @args {Array<Object>} posts - The array of post objects to display
* @args {Function} fetchMorePosts - A function that fetches more posts. Must return a Promise that resolves to an array of new posts.
* @args {String} emptyText (optional) - Custom text to display when there are no posts
* @args {String|Array} additionalItemClasses (optional) - Additional classes to add to each post list item
* @args {String} titleAriaLabel (optional) - Custom Aria label for the post title
*
*/
```
```hbs
<PostList
@posts={{this.posts}}
@fetchMorePosts={{this.loadMorePosts}}
@emptyText={{i18n "custom_identifier.empty"}}
@additionalItemClasses="custom-class"
/>
```
Setting tab should be added to permalinks so admins do not need to have left `/permalinks`.
A new component called `AreaSetting` was added to avoid duplications and
simplify adding settings to other sections.
This allows plugins to skip the "posted" notifications for watching users, when posts get moved. The specs are kind of wild looking, as this unit tests a private method. This is difficult to isolate otherwise, with lots of trickery needed to make sure that this actually works.
I opted to unit test just this method instead.
This commit reimplements how we monitor Sidekiq processes that are
forked from the Unicorn master process. Prior to this change, we rely on
`Jobs::Heartbeat` to enqueue a `Jobs::RunHeartbeat` job every 3 minutes.
The `Jobs::RunHeartbeat` job then sets a Redis key with a timestamp. In
the Unicorn master process, we then fetch the timestamp that has been set
by the job from Redis every 30 minutes. If the timestamp has not been
updated for more than 30 minutes, we restart the Sidekiq process. The
fundamental flaw with this approach is that it fails to consider
deployments with multiple hosts and multiple Sidekiq processes. A
sidekiq process on a host may be in a bad state but the heartbeat check
will not restart the process because the `Jobs::RunHeartbeat` job is
still being executed by the working Sidekiq processes on other hosts.
In order to properly ensure that stuck Sidekiq processs are restarted,
we now rely on the [Sidekiq::ProcessSet](https://github.com/sidekiq/sidekiq/wiki/API#processes)
API that is supported by Sidekiq. The API provides us with "near real-time (updated every 5 sec)
info about the current set of Sidekiq processes running". The API
provides useful information like the hostname, pid and also when Sidekiq
last did its own heartbeat check. With that information, we can easily
determine if a Sidekiq process needs to be restarted from the Unicorn
master process.
* port CanCheckEmails mixin to helper class with explicit dependencies
* move isCurrentUser getter to components
* anonymous users should not be able to see sensitive information
This converts the `<AdminPageHeader />` component and the
`<AdminPageSubheader />` components into new components
that can be used outside of admin, and updates the CSS classes.
Also introduces a `<DPageActionButton />` component and child
components for the header action buttons.
I have to keep the old admin-only components around for
now until plugins are updated, then we can remove it,
and remove the re-exports that are done within
admin-page-action-button.gjs
When freeze_original option is passed to PostMover, and we are moving all posts there is an issue. We attempt to put the small_action right after the last moved post. The issue is when there is an existing small action after the last moved "real" post. We then try to put the moderator post at the same location of the existing small action, which causes an index conflict and the move fails.
This makes sure that we place the moderator post at the verrrrrry end of the topic :)
* UX: Apply admin table classes for consistent mobile styling on the web hooks page
* DEV: Remove icon on the status component; update status classes
* DEV: Update tests for webhook status component
* DEV: add space var with a smaller value
* DEV: Add styling for different status labels
When using FK select, we include a "None" option automatically. However, for required select fields, "None" isn't a valid option, so we exclude it instead.
We're changing the default of hide_email_address_taken to true. This is a trade-off we want to make, as it prevents account enumeration with minimal impact on legitimate users. If you forget you have an account and try to sign up again with the same e-mail you'll receive an e-mail letting you know.
Add flag reason filter and improve handling of deleted content in review queue
This commit enhances the review queue with several key improvements:
1. Adds a new "Reason" filter to allow filtering flags by their score type
2. Improves UI for deleted content by:
- Adding visual indication for deleted posts (red background)
- Properly handling deleted content visibility for staff (category mods can not see deleted content)
3. Refactors reviewable score type handling for better code organization
4. Adds tests for trashed topics/posts visibility
This change will help moderators more efficiently manage the review queue by
being able to focus on specific types of flags and better identify deleted
content.
Using the (array) helper creates an array instance, passes it to applyValueTransformer, which then allows themes/plugins to mutate it.
When the helper is re-computed, the **same array instance** is passed to the transformers again. Any elements added in the last run are still there.
This commit moves applyValueTransformer to a getter, so that it's run with a brand new array each time.
This commit introduces <NotificationsTracking /> which is a wrapper component around <DMenu /> which replaces the select-kit component <TopicNotificationsButton />.
Each tracking case has its dedicated component:
- topic -> `<TopicNotificationsTracking />`
- group -> `<GroupNotificationsTracking />`
- tag -> `<TagNotificationsTracking />`
- category -> `<CategoryNotificationsTracking />`
- chat thread -> `<ThreadNotificationsTracking />`
Previously, theme hbr files were compiled to an IIFE, which would be executed before the app is booted. That is causing silenced deprecations to be printed, because the deprecation-workflow isn't set up when the IIFE is run.
This commit updates the theme compiler so that it matches the ember-cli-based raw-hbs compiler. Templates are output to normal modules, which will then be loaded by the existing `eager-load-raw-templates` initializer. This runs after the app has started booting.
* DEV: add db consistency check for UserEmail
* DEV: add db consistency check for UserAvatar
* DEV: ignore inconsistent data related to user avatars when deciding whether to rebake old posts
Co-authored-by: Alan Guo Xiang Tan <gxtan1990@gmail.com>
---------
Co-authored-by: Alan Guo Xiang Tan <gxtan1990@gmail.com>
This feature writes a stack trace as part of the message. That means it is not sourcemapped by the browser, and you have further to scroll to find the real backtrace.
In the past we avoided this feature with our production 'deprecation shim', but that was removed as part of our Ember 5.12 upgrade.
When viewing your own user profile, we offer the ability to expand / collapse your user info.
By default, the info are collapsed and the button to toggle it only worked once. Meaning you could expand the info but not collapse it back.
This fixes the issue by using `toggleProperty()` instead of directly `set()`-ing a value.
Also added an acceptance test to ensure it doesn't regress.
Was reported in https://meta.discourse.org/t/342254
Collections were an existing concept in FormKit but didn't allow nesting. You can now do infinite nesting:
```gjs
<Form
@data={{hash
foo=(array
(hash bar=(array (hash baz=1))) (hash bar=(array (hash baz=2)))
)
}}
as |form|
>
<form.Collection @name="foo" as |parent parentIndex|>
<parent.Collection @name="bar" as |child childIndex|>
<child.Field @name="baz" @title="Baz" as |field|>
<field.Input />
</child.Field>
</parent.Collection>
</form.Collection>
</Form>
```
On top of this a new component has been added: `Object`. It allows you to represent objects in your form data. Collections are basically handling arrays, and Objects are objects.
This is useful if you form data has this shape for example:
```javascript
{ foo: { bar: 1, baz: 2 } }
```
This can now be mapped in your form using this syntax:
```gjs
<Form @data={{hash foo=(hash bar=1 baz=2)}} as |form|>
<form.Object @name="foo" as |object name|>
<object.Field @name={{name}} @title={{name}} as |field|>
<field.Input />
</object.Field>
</form.Object>
</Form>
```
Objects accept nested collections and nested objects. Just like Collections.
A small addition has also been made to `Collection`, they now support a custom `@tagName`, it's useful if each item of your collection is the row of a table for example.
`<DSelect />` is a wrapper similar to our existing `<DButton />` over the html element `<select>`. The code is ported from form kit which is now directly using `<DSelect />`. Note this component has also been used in edit topic timer modal.
This component is recommended for a small list of text items (no icons, no rich formatting...).
Usage:
```gjs
<DSelect class="my-select" @onChange={{this.handleChange}} as |select|>
<select.Option @value="foo" class="my-favorite-option">Foo</select.Option>
<select.Option @value="bar">Bar</select.Option>
</DSelect>
```
This commit comes with a set of assertions:
```gjs
import dselect from "discourse/tests/helpers/d-select-helper";
import { select } from "@ember/test-helpers";
assert
.dselect(".my-select")
.hasOption({ value: "bar", label: "Bar" })
.hasOption({ value: "foo", label: "Foo" })
.hasNoOption("baz");
await select(".my-select", "foo");
assert.dselect(".my-select").hasSelectedOption({value: "foo", label: "Foo"});
```
Introduces a new component used to show a grid of stats
on any page, mostly used for dashboards and config pages.
This component yields a hash with a `Tile` component property,
and the caller can loop through their stats and display them
using this component.
Each stat needs a @label and a @value at minimum, but can
also pass in a @tooltip and a @url.
This commit starts the rollout of the Glimmer post menu:
- default to `auto`: after the upgrade, it will be enabled on all discourse instances that do not have incompatible customizations
- unsilence the deprecation messages in the console
- removes the setting `glimmer_post_menu_groups` as it's no longer in the test phase
This commit improves some tests to using both the glimmer post menu and the widget version.
It also addresses some small issues in the Glimmer Post Menu:
- Deprecated Font Awesome icon in the Edit button
- Set correctly `aria-pressed` in the Like Count when the list of people who liked is visible
- Display the user tip for the Show More button
This commit adds a new column full_move to the moved_posts table. This is useful to look back at history and determine if a whole topic was moved or partial.
This commit also adds an apply_modifier to skip the creation of the moved posts small action.
On mobile, in the topic footer buttons, instead of showing all the
buttons, we "merge" some of then into a dropdown.
If the dropdown has only one "option", then it doesn't make sense to
show the "ellipsis" button. Instead, we directly show the button of the
only available option. Saving a click on the way.
* UX: increase button sizes and timeline size
* UX: bring back tracking btn on topic timeline desktop
* Scope flexing topic-navigation area to mobile + make all buttons same font-size
This was fixed previously but must have regressed, we
are showing a darker grey background around the
"Only show overridden" checkbox for our Settings tab
in config pages.
This PR fixes a recent regression in e37952c9db that reverted a fix made in 1c4d5dae1c, which allowed for async calls to finish first before removing in progress uploads.
We now extensively reference the `{ i18n }` named export of the `discourse-i18n` package, instead of calling `I18n.t` directly. That means that mutations of `I18n.t` no longer have any impact on most of the app.
This commit updates the verbose localisation logic to be switched by a boolean instead of a method mutation.
When a post containing an apostrophe (') is being cooked, the apostrophe is being converted to the "typographic" version (’) (because we enable markdown-it's **typographer** mode by default in Discourse)
When you select text that contains such apostrophe and then try to save your fast edit, it fails miserably without any error.
That's because when you select text from the DOM, it uses the cooked version which has the typographic apostrophe.
When you save your fast edit, we fetch the raw version of the post, which has the "regular" apostrophe. Thus doing `raw.replace(selectedText, editedText)` doesn't work because `raw` has the regular apostrophe but `selectedText` has the typographic apostrophe.
Since it's somewhat complicated to handle all typographic characters, we would basically have to reverse the process done in `custom-typographer-replacements.js`, we instead bail out and show the composer when we detect such character in the selection.
Internal ref - t/143836