This optimizes a hot path when users are being removed from one or more groups since we use the `on(:user_removed_from_group)` event to call the `Chat::AutoLeaveChannels` with a `user_id` parameter. In such case, we don't need to clear the membership of all users, just that one user.
DEBUG: Also added a "-- event = <event>" comment on top of the SQL queries used by the "AutoLeaveChannels" so they show up in the logs and hopefully facilitate any performance issues that might arise in the future.
* Remove unused `report_progress_in_percent` option from step
* Remove `use_custom_progress_increment` option from the step because we can figure it out by looking at the progress
* Introduce `StepTracker` to for logging warnings and errors and tracking step progress
* Make it easier to log warnings and errors in all methods of `Step` without the need to pass around a `stats` object
The previous approach of splitting Thor commands into multiple files caused problems when the same method name was used in multiple commands.
This also loads the Rails environment only for commands that need it. That makes the CLI boot faster for most commands or when the help should be shown. That's also why we can't use `Rails.root` in the CLI.
This spec helper was introduced as a temporary solution to the problem
of mismatched types between primary key and foreign key columns. All
plugins have been migrated and the only remaining use of this helper is
in core Discourse.
In some rare cases, this was causing the input to be invisible. The
change here means the input will have a smaller max height, but since
here we are limiting this to 25% of the viewport height, it should be
more than fine.
It's also not necessary to include the `chat-header-offset`, it ends up
being only a few pixels' difference (since, again, it is divided by 4).
This patch adds a new step to services named `try`.
It’s useful to rescue exceptions that some steps could raise. That way,
if an exception is caught, the service will stop its execution and can
be inspected like with any other steps.
Just wrap the steps that can raise with a `try` block:
```ruby
try do
step :step_that_can_raise
step :another_step_that_can_raise
end
```
By default, `try` will catch any exception inheriting from
`StandardError`, but we can specify what exceptions to catch:
```ruby
try(ArgumentError, RuntimeError) do
step :will_raise
end
```
An outcome matcher has been added: `on_exceptions`. By default it will
be executed for any exception caught by the `try` step.
Here also, we can specify what exceptions to catch:
```ruby
on_exceptions(ArgumentError, RuntimeError) do |exception|
…
end
```
Finally, an RSpec matcher has been added:
```ruby
it { is_expected.to fail_with_exception }
# or
it { is_expected.to fail_with_exception(ArgumentError) }
```
Because of an oversight in a previous PR, the breadcrumb link when visiting Admin > Emoji > Settings was broken. The correct path is customize, not config.
The current breadcrumb separators are ">" characters that are added as pseudo-elements. These become part of the clickable area for the links, which causes mis-clicks.
This PR does two things:
- Replace the pseudo-element with a DIcon.
- Make sure the separator is not clickable.
Blocks allow BOTS to augment the capacities of a chat message. At the moment only one block is available: `actions`, accepting only one type of element: `button`.
<img width="708" alt="Screenshot 2024-11-15 at 19 14 02" src="https://github.com/user-attachments/assets/63f32a29-05b1-4f32-9edd-8d8e1007d705">
# Usage
```ruby
Chat::CreateMessage.call(
params: {
message: "Welcome!",
chat_channel_id: 2,
blocks: [
{
type: "actions",
elements: [
{ value: "foo", type: "button", text: { text: "How can I install themes?", type: "plain_text" } }
]
}
]
},
guardian: Discourse.system_user.guardian
)
```
# Documentation
## Blocks
### Actions
Holds interactive elements: button.
#### Fields
| Field | Type | Description | Required? |
|--------|--------|--------|--------|
| type | string | For an actions block, type is always `actions` | Yes |
| elements | array | An array of interactive elements, maximum 10 elements | Yes |
| block_id | string | An unique identifier for the block, will be generated if not specified. It has to be unique per message | No |
#### Example
```json
{
"type": "actions",
"block_id": "actions_1",
"elements": [...]
}
```
## Elements
### Button
#### Fields
| Field | Type | Description | Required? |
|--------|--------|--------|--------|
| type | string | For a button, type is always `button` | Yes |
| text | object | A text object holding the type and text. Max 75 characters | Yes |
| value | string | The value returned after the interaction has been validated. Maximum length is 2000 characters | No |
| style | string | Can be `primary` , `success` or `danger` | No |
| action_id | string | An unique identifier for the action, will be generated if not specified. It has to be unique per message | No |
#### Example
```json
{
"type": "actions",
"block_id": "actions_1",
"elements": [
{
"type": "button",
"text": {
"type": "plain_text",
"text": "Ok"
},
"value": "ok",
"action_id": "button_1"
}
]
}
```
## Interactions
When a user interactions with a button the following flow will happen:
- We send an interaction request to the server
- Server checks if the user can make this interaction
- If the user can make this interaction, the server will:
* `DiscourseEvent.trigger(:chat_message_interaction, interaction)`
* return a JSON document
```json
{
"interaction": {
"user": {
"id": 1,
"username": "j.jaffeux"
},
"channel": {
"id": 1,
"title": "Staff"
},
"message": {
"id": 1,
"text": "test",
"user_id": -1
},
"action": {
"text": {
"text": "How to install themes?",
"type": "plain_text"
},
"type": "button",
"value": "click_me_123",
"action_id": "bf4f30b9-de99-4959-b3f5-632a6a1add04"
}
}
}
```
* Fire a `appEvents.trigger("chat:message_interaction", interaction)`
As part of a previous fix we changed which groups are serialized for a user, in order to fix a bug in the default group selector under user preferences.
However, we should only change this when serializing the current user. This change combines the old code-path and the new based on who is serializing.
Non-bundled plugins are gitignore'd, but we want them to show up in search tools / IDEs. Adding a `.ignore` file with a negative glob lets us achieve this.
Previously, it was up to individuals to work out how to configure their editor to do this when working on plugins.
Also adds negative matchers for the vscode config files, so they show up in the file picker & search.