When an installed component doesn't have a description in its locale
files, we should fallback to the description that core has for the
component if it's one of the popular components that core features.
On sites with many components, serializing and rendering all components
in one-go on a page can take quite a bit of time. The new components
listing page that was introduced in
https://github.com/discourse/discourse/pull/32164 currently loads all
components in one-go, so this commit implements infinite-scrolling
pagination for the page to address this performance issue for sites with
many components.
Theme/component description is fetched via the `locale_fields` and
`theme_translation_overrides` associations on the `Theme` model. We're
currently not preloading these associations when serializing
themes/components, which causes an N+1 performance issue when accessing
the themes/components listing pages.
The `DMultiSelect` component provides a customizable multi-select
dropdown with support for both mouse and keyboard interactions.

### Parameters
#### `@loadFn` (required)
An async function that returns the data to populate the dropdown
options.
```javascript
const loadFn = async () => {
return [
{ id: 1, name: "Option 1" },
{ id: 2, name: "Option 2" },
];
};
```
#### `@compareFn`
A function used to determine equality between items. This is
particularly useful when working with complex objects. By default, `id`
will be used.
```javascript
const compareFn = (a, b) => {
return a.name === b.name;
};
```
#### `@selection`
An array of pre-selected items that will be displayed as selected when
the component renders.
```javascript
const selection = [
{ id: 1, name: "Option 1" },
{ id: 2, name: "Option 2" },
];
```
#### `@label`
Text label displayed in the trigger element when no items are selected.
```javascript
@label="Select options"
```
### Named Blocks
#### :selection
Block for customizing how selected items appear in the trigger.
```javascript
<:selection as |result|>{{result.name}}</:selection>
```
#### :result
Block for customizing how items appear in the dropdown list.
```javascript
<:result as |result|>{{result.name}}</:result>
```
#### :result
Block for customizing how errors appear in the component.
```javascript
<:error as |error|>{{error}}</:error>
```
### Example Usage
```javascript
<DMultiSelect
@loadFn={{this.loadOptions}}
@selection={{this.selectedItems}}
@compareFn={{this.compareItems}}
@label="Select options">
<:selection as |result|>{{result.name}}</:selection>
<:result as |result|>{{result.name}}</:result>
<:error as |error|>{{error}}</:error>
</DMultiSelect>
```
Co-Authored-By: Jordan Vidrine
<30537603+jordanvidrine@users.noreply.github.com>
---------
Co-authored-by: Jordan Vidrine <30537603+jordanvidrine@users.noreply.github.com>
Adding some changes to site.rb, and seeing this error:
```
Failure/Error: raise "Clearing modifiers during a plugin spec run will affect all future specs. Use unregister_modifier instead."
```
This is a standalone PR to update the usage here so that my future PR
won't be affected.
Adds a plugin outlet below the login buttons in the login-required
splash screen.
Use case: adding a custom footer to the splash screen with links to tos
and privacy policy.
This makes two tweaks to the setup wizard:
1. Move the branding (site logo) step to after styling (look & feel).
2. Remove the corporate (your organization) step.
This commit removes the Ctrl+F search shortcut, which hijacks the
browser search shortcut in Discourse. We are doing this because there
has been many years of complaints around this behaviour, and now that
we have the new header search it has become even more annoying.
We originally added this because we lazy load posts in a topic, and it
might not have been immediately clear to users that they are not
searching
all the posts in the topic when pressing Ctrl+F. However, that was 10+
years
ago, most people are very familiar with lazy loading now, it doesn't
make sense
to keep this additional hijack for this one topic use case.
Search is still accessible by pressing the `/` shortcut.
When we do replaceText in the ProseMirror TextManipulation lib,
we are creating a regex for the provided markdown. However this markdown
can have things like * (which is valid for a markdown list), which also
doubles as a regex symbol. We can escape the markdown provided to
the regex first to fix the issue.
It takes a moment to sync site settings. Therefore, it is better to pass
new values to `refreshPage` function.
Also, it was not working for some fonts like `JetBrains Mono`.
SiteSetting key is `jet_brains_mono` but font family value should be
`JetBrains Mono`.
`PreviewBase#drawPills` expects a `homepageStyle` option, but on the logo wizard page we weren't passing any. In this change we pass one of the possible values: `hot`.
Instead of using the matched string, this PR uses the actual sliced
content from the ProseMirror document range as the content when creating
the footnote node.
New lines on `alt`/`title` embedded media are not allowed, causing an
invalid serialized Markdown which is not supposed to contain new lines
for these attributes.
This PR removes them during HTML parsing – we are not creating this new
line scenario otherwise.
Previously, there was only those helpers in `crawler.html.erb` as we
added it in https://github.com/discourse/discourse/pull/32259
However, to keep it consistent, we need to add it in
`application.html.erb` as well.
Our `insertBlock` implementation was only taking the `firstChild` into
consideration.
We didn't notice this before because there's only one use of this in
core, quoting from a post, which has a single child.
This fix is necessary to support the `insert-block` call that the
https://github.com/discourse/discourse-templates plugin makes when
inserting a template.
Continues the work done on
https://github.com/discourse/discourse/pull/30815.
Adds a `footnote` node, parser, `^[inline]` input rule, toolbar button
item, and serializer.
Also adds a NodeView with an internal ProseMirror editor to edit the
footnote content.
`pos` is the exact position of the click in the entire document
`nodePos` is the position of the clicked node itself
The idea is that we want the click to be the first position **within the
node**.
The previous code was checking for the first 2 positions of the entire
document.
I'd love to add a test for this, but it's very tricky.
When using a html block within the rich editor (currently only possible
after parsing it from Markdown), it would get serialized with the
default escape=true processing.
Additionally, html blocks are a continuous block, if a `\n\n` is seen
during cooking the block is closed, so we make sure at most one
continuous `\n` is seen in the html block node on the ProseMirror doc.
EDIT: It turns out, it's not so simple. I'm merging this as is, but it's
important to link the actual behavior to close a paragraph from
markdown-it:
0fe7ccb4b7/lib/rules_block/html_block.mjs (L6-L17)
On some cases during serialization (like with headings), the previous
node is still "open" when it's the "turn" of the node we're serializing.
In this case, checking the boundaries before writing was getting the
wrong state, because the `write` call uses `flushClose()`, which makes
sure we have the newlines from closing the previous node.
This would create scenarios like (notice the space before each node
below the heading)
```markdown
# Heading
🎉
# Heading
@mention
# Heading
#hashtag
```
This PR makes sure we call flushClose() before checking boundaries, and
adds tests for that.
Repro steps:
1. Go to `/admin/customize/site_texts`
2. Click edit on any translation
3. Go back by clicking on "Back to search"
4. Click edit on another translation
5. Change the text field in any way
Expected results:
The disabled state on the "Save changes" button is removed and you're
able to click it
Actual results:
The "Save changes" button remains disabled
This happens because the computed property for the button's disabled
state doesn't get re-evaluated when navigating between translation
strings because it doesn't include on the `siteText` property in its
dependent properties, so changing the site text doesn't invalidate the
old value for the disabled state and it always stays the same.
Meta topic:
https://meta.discourse.org/t/i-cant-save-edit-on-site-texts/360990?u=osama
Followup 198dc813750d7a0de98cc94372dea1222b97743b
Indicate the shortcut in the tooltip for the rich/markdown
editor toggle, and also add the control translation for mac
in `translateModKey`
## Requirements
Initially defined in
https://meta.discourse.org/t/software-engineer-frontend-ember-js-yuriy-kurant/353612/14?u=yaran.
1. On mobile devices and tablets, users can open the search input field
by tapping the search icon
2. When opened, the search input takes over the entire header area:
- Users can tap the sliders icon to navigate to the advanced search page
(/search)
- Users can tap Cancel to close search input
3. After submitting a search, results area will take over the entire
screen:
- Users can tap the X icon to clear the search term from the input field
- Users can tap Cancel to close search results area and return to their
previous page (i.e. search area overlays content)
## Implementation
1. When opened, the search input takes over the entire header area:
- changed panel width from `90vw` to `100vw`
- on initial render (when search input is empty), search panel hovers over the header section only (doesn't cover main content below)
- quick tip and recent searches lists are not displayed on mobile view
2. Tap on the sliders icon navigates to the advanced search page
(`/search`)
3. Tap on the **Cancel** button:
- closes search menu
- if the search term is present, it is cleared
4. Tap on the left-hand side **Search** icon triggers a topics search
## Dev notes
1. Added `// TODO` questioning `search` service `noResults` default value of `false`
2. Added animation on toggling header search panel (created `delayed-destroy` custom modifier)
3. Extracted in-context search filters into a standalone component `search-menu/active-filters`:
- mobile: active filters below search input
- desktop: active filters inside search input
3. Removed unnecessary top padding when search results are empty
4. Added `data-test-` attrs for Ember tests. Benefits:
- semantically `data-test-` attrs indicate that these parts of the layout are covered with tests
- decouples selector dependency on `id/class` names for testing purposes - eliminates risk of broken tests due to `id/class` name changes
Our service worker concatenates `baseUrl` with `url` coming from the
payload:
e8f4433872/app/views/static/service-worker.js.erb (L96)
This PRs strips the base path before sending `url` to the push
notification to avoid having a URL with the base path duplicated,
causing a 404.