Browse Source

Fix mentions for long text and fix some text

pull/1006/head
Sebastian 3 years ago
parent
commit
a3479308de
  1. 2
      backend/i18n/frontend_en.json
  2. 2
      backend/i18n/frontend_fr.json
  3. 2
      backend/i18n/frontend_it.json
  4. 2
      backend/i18n/frontend_nl.json
  5. 2
      backend/i18n/frontend_pt.json
  6. 2
      backend/i18n/frontend_zh.json
  7. 2
      backend/i18n/source/frontend_en.json
  8. 40
      backend/src/Squidex.Domain.Apps.Entities/Comments/DomainObject/CommentsCommandMiddleware.cs
  9. 20
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Comments/DomainObject/CommentsCommandMiddlewareTests.cs
  10. 2
      frontend/src/app/features/content/shared/forms/chat-dialog.component.html
  11. 2
      frontend/src/app/features/content/shared/forms/chat-dialog.component.scss
  12. 4
      frontend/src/app/features/content/shared/forms/chat-dialog.component.ts

2
backend/i18n/frontend_en.json

@ -166,6 +166,8 @@
"backups.started": "Backup started, it can take several minutes to complete.", "backups.started": "Backup started, it can take several minutes to complete.",
"backups.startedLabel": "Started", "backups.startedLabel": "Started",
"backups.startFailed": "Failed to start backup.", "backups.startFailed": "Failed to start backup.",
"chat.answers": "Answers",
"chat.answersEmpty": "The ChatBot does not provide an answer or has not been configured yet.",
"chat.ask": "Ask", "chat.ask": "Ask",
"chat.description": "Use the ChatBot (usually OpenAI) to generate content. Just write a prompt and describe, what you need.\n\n\nAlso add the desired format (for example Markdown or HTML) to your prompt, dependending on the editor that you use.", "chat.description": "Use the ChatBot (usually OpenAI) to generate content. Just write a prompt and describe, what you need.\n\n\nAlso add the desired format (for example Markdown or HTML) to your prompt, dependending on the editor that you use.",
"chat.prompt": "Describe the content you want to generate", "chat.prompt": "Describe the content you want to generate",

2
backend/i18n/frontend_fr.json

@ -166,6 +166,8 @@
"backups.started": "La sauvegarde a commencé, cela peut prendre plusieurs minutes.", "backups.started": "La sauvegarde a commencé, cela peut prendre plusieurs minutes.",
"backups.startedLabel": "Commencé", "backups.startedLabel": "Commencé",
"backups.startFailed": "Échec du démarrage de la sauvegarde.", "backups.startFailed": "Échec du démarrage de la sauvegarde.",
"chat.answers": "Answers",
"chat.answersEmpty": "The ChatBot does not provide an answer or has not been configured yet.",
"chat.ask": "Ask", "chat.ask": "Ask",
"chat.description": "Use the ChatBot (usually OpenAI) to generate content. Just write a prompt and describe, what you need.\n\n\nAlso add the desired format (for example Markdown or HTML) to your prompt, dependending on the editor that you use.", "chat.description": "Use the ChatBot (usually OpenAI) to generate content. Just write a prompt and describe, what you need.\n\n\nAlso add the desired format (for example Markdown or HTML) to your prompt, dependending on the editor that you use.",
"chat.prompt": "Describe the content you want to generate", "chat.prompt": "Describe the content you want to generate",

2
backend/i18n/frontend_it.json

@ -166,6 +166,8 @@
"backups.started": "Backup avviato, il suo completamento potrebbe richiedere alcuni minuti.", "backups.started": "Backup avviato, il suo completamento potrebbe richiedere alcuni minuti.",
"backups.startedLabel": "Avviato", "backups.startedLabel": "Avviato",
"backups.startFailed": "Non è stato possibile avviare il backup.", "backups.startFailed": "Non è stato possibile avviare il backup.",
"chat.answers": "Answers",
"chat.answersEmpty": "The ChatBot does not provide an answer or has not been configured yet.",
"chat.ask": "Ask", "chat.ask": "Ask",
"chat.description": "Use the ChatBot (usually OpenAI) to generate content. Just write a prompt and describe, what you need.\n\n\nAlso add the desired format (for example Markdown or HTML) to your prompt, dependending on the editor that you use.", "chat.description": "Use the ChatBot (usually OpenAI) to generate content. Just write a prompt and describe, what you need.\n\n\nAlso add the desired format (for example Markdown or HTML) to your prompt, dependending on the editor that you use.",
"chat.prompt": "Describe the content you want to generate", "chat.prompt": "Describe the content you want to generate",

2
backend/i18n/frontend_nl.json

@ -166,6 +166,8 @@
"backups.started": "Back-up gestart, het kan enkele minuten duren om te voltooien.", "backups.started": "Back-up gestart, het kan enkele minuten duren om te voltooien.",
"backups.startedLabel": "Gestart", "backups.startedLabel": "Gestart",
"backups.startFailed": "Starten van back-up is mislukt.", "backups.startFailed": "Starten van back-up is mislukt.",
"chat.answers": "Answers",
"chat.answersEmpty": "The ChatBot does not provide an answer or has not been configured yet.",
"chat.ask": "Ask", "chat.ask": "Ask",
"chat.description": "Use the ChatBot (usually OpenAI) to generate content. Just write a prompt and describe, what you need.\n\n\nAlso add the desired format (for example Markdown or HTML) to your prompt, dependending on the editor that you use.", "chat.description": "Use the ChatBot (usually OpenAI) to generate content. Just write a prompt and describe, what you need.\n\n\nAlso add the desired format (for example Markdown or HTML) to your prompt, dependending on the editor that you use.",
"chat.prompt": "Describe the content you want to generate", "chat.prompt": "Describe the content you want to generate",

2
backend/i18n/frontend_pt.json

@ -166,6 +166,8 @@
"backups.started": "O reforço começou, pode levar vários minutos para ser concluído.", "backups.started": "O reforço começou, pode levar vários minutos para ser concluído.",
"backups.startedLabel": "Começou", "backups.startedLabel": "Começou",
"backups.startFailed": "Falhou em começar o backup.", "backups.startFailed": "Falhou em começar o backup.",
"chat.answers": "Answers",
"chat.answersEmpty": "The ChatBot does not provide an answer or has not been configured yet.",
"chat.ask": "Ask", "chat.ask": "Ask",
"chat.description": "Use the ChatBot (usually OpenAI) to generate content. Just write a prompt and describe, what you need.\n\n\nAlso add the desired format (for example Markdown or HTML) to your prompt, dependending on the editor that you use.", "chat.description": "Use the ChatBot (usually OpenAI) to generate content. Just write a prompt and describe, what you need.\n\n\nAlso add the desired format (for example Markdown or HTML) to your prompt, dependending on the editor that you use.",
"chat.prompt": "Describe the content you want to generate", "chat.prompt": "Describe the content you want to generate",

2
backend/i18n/frontend_zh.json

@ -166,6 +166,8 @@
"backups.started": "备份已开始,可能需要几分钟才能完成。", "backups.started": "备份已开始,可能需要几分钟才能完成。",
"backups.startedLabel": "开始", "backups.startedLabel": "开始",
"backups.startFailed": "启动备份失败。", "backups.startFailed": "启动备份失败。",
"chat.answers": "Answers",
"chat.answersEmpty": "The ChatBot does not provide an answer or has not been configured yet.",
"chat.ask": "Ask", "chat.ask": "Ask",
"chat.description": "Use the ChatBot (usually OpenAI) to generate content. Just write a prompt and describe, what you need.\n\n\nAlso add the desired format (for example Markdown or HTML) to your prompt, dependending on the editor that you use.", "chat.description": "Use the ChatBot (usually OpenAI) to generate content. Just write a prompt and describe, what you need.\n\n\nAlso add the desired format (for example Markdown or HTML) to your prompt, dependending on the editor that you use.",
"chat.prompt": "Describe the content you want to generate", "chat.prompt": "Describe the content you want to generate",

2
backend/i18n/source/frontend_en.json

@ -166,6 +166,8 @@
"backups.started": "Backup started, it can take several minutes to complete.", "backups.started": "Backup started, it can take several minutes to complete.",
"backups.startedLabel": "Started", "backups.startedLabel": "Started",
"backups.startFailed": "Failed to start backup.", "backups.startFailed": "Failed to start backup.",
"chat.answers": "Answers",
"chat.answersEmpty": "The ChatBot does not provide an answer or has not been configured yet.",
"chat.ask": "Ask", "chat.ask": "Ask",
"chat.description": "Use the ChatBot (usually OpenAI) to generate content. Just write a prompt and describe, what you need.\n\n\nAlso add the desired format (for example Markdown or HTML) to your prompt, dependending on the editor that you use.", "chat.description": "Use the ChatBot (usually OpenAI) to generate content. Just write a prompt and describe, what you need.\n\n\nAlso add the desired format (for example Markdown or HTML) to your prompt, dependending on the editor that you use.",
"chat.prompt": "Describe the content you want to generate", "chat.prompt": "Describe the content you want to generate",

40
backend/src/Squidex.Domain.Apps.Entities/Comments/DomainObject/CommentsCommandMiddleware.cs

@ -14,7 +14,7 @@ namespace Squidex.Domain.Apps.Entities.Comments.DomainObject;
public sealed class CommentsCommandMiddleware : AggregateCommandMiddleware<CommentsCommandBase, CommentsStream> public sealed class CommentsCommandMiddleware : AggregateCommandMiddleware<CommentsCommandBase, CommentsStream>
{ {
private static readonly Regex MentionRegex = new Regex(@"@(?=.{1,254}$)(?=.{1,64}@)[-!#$%&'*+\/0-9=?A-Z^_`a-z{|}~]+(\.[-!#$%&'*+\/0-9=?A-Z^_`a-z{|}~]+)*@[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?(\.[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?)*", RegexOptions.Compiled | RegexOptions.ExplicitCapture, TimeSpan.FromMilliseconds(100)); private static readonly Regex MentionRegex = new Regex(@"@(?=.{1,64}@)[-!#$%&'*+\/0-9=?A-Z^_`a-z{|}~]+(\.[-!#$%&'*+\/0-9=?A-Z^_`a-z{|}~]+)*@[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?(\.[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?)*", RegexOptions.Compiled | RegexOptions.ExplicitCapture, TimeSpan.FromMilliseconds(100));
private readonly IUserResolver userResolver; private readonly IUserResolver userResolver;
public CommentsCommandMiddleware(IDomainObjectFactory domainObjectFactory, IUserResolver userResolver) public CommentsCommandMiddleware(IDomainObjectFactory domainObjectFactory, IUserResolver userResolver)
@ -44,29 +44,33 @@ public sealed class CommentsCommandMiddleware : AggregateCommandMiddleware<Comme
private async Task MentionUsersAsync(CommentTextCommand command) private async Task MentionUsersAsync(CommentTextCommand command)
{ {
if (!string.IsNullOrWhiteSpace(command.Text)) if (string.IsNullOrWhiteSpace(command.Text))
{ {
var emails = MentionRegex.Matches(command.Text).Select(x => x.Value[1..]).ToArray(); return;
}
if (emails.Length > 0) var emails = MentionRegex.Matches(command.Text).Select(x => x.Value[1..]).ToArray();
{
var mentions = new List<string>(); if (emails.Length == 0)
{
return;
}
foreach (var email in emails) var mentions = new List<string>();
{
var user = await userResolver.FindByIdOrEmailAsync(email);
if (user != null) foreach (var email in emails)
{ {
mentions.Add(user.Id); var user = await userResolver.FindByIdOrEmailAsync(email);
}
}
if (mentions.Count > 0) if (user != null)
{ {
command.Mentions = mentions.ToArray(); mentions.Add(user.Id);
}
} }
} }
if (mentions.Count > 0)
{
command.Mentions = mentions.ToArray();
}
} }
} }

20
backend/tests/Squidex.Domain.Apps.Entities.Tests/Comments/DomainObject/CommentsCommandMiddlewareTests.cs

@ -5,6 +5,7 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using LoremNET;
using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Domain.Apps.Core.TestHelpers;
using Squidex.Domain.Apps.Entities.Comments.Commands; using Squidex.Domain.Apps.Entities.Comments.Commands;
using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Domain.Apps.Entities.TestHelpers;
@ -76,6 +77,25 @@ public class CommentsCommandMiddlewareTests : GivenContext
Assert.Equal(command.Mentions, new[] { "id1", "id2" }); Assert.Equal(command.Mentions, new[] { "id1", "id2" });
} }
[Fact]
public async Task Should_enrich_with_mentioned_user_ids_if_found_and_long_text()
{
SetupUser("id1", "mail1@squidex.io");
SetupUser("id2", "mail2@squidex.io");
var command = CreateCommentsCommand(new CreateComment
{
Text = $"Hi @mail1@squidex.io, @mail2@squidex.io and @notfound@squidex.io {Lorem.Paragraph(200, 10)}",
IsMention = false
});
var context = CrateCommandContext(command);
await sut.HandleAsync(context, CancellationToken);
Assert.Equal(command.Mentions, new[] { "id1", "id2" });
}
[Fact] [Fact]
public async Task Should_not_invoke_commands_for_mentioned_users() public async Task Should_not_invoke_commands_for_mentioned_users()
{ {

2
frontend/src/app/features/content/shared/forms/chat-dialog.component.html

@ -31,7 +31,7 @@
<h4 class="mt-4">{{ 'chat.answers' | sqxTranslate }}</h4> <h4 class="mt-4">{{ 'chat.answers' | sqxTranslate }}</h4>
<div *ngIf="snapshot.chatAnswers?.length === 0"> <div *ngIf="snapshot.chatAnswers?.length === 0">
{{ 'chat.noAnswers' | sqxTranslate }} <small class="text-muted">{{ 'chat.answersEmpty' | sqxTranslate }}</small>
</div> </div>
<div class="row g-2 answer" *ngFor="let answer of (snapshot.chatAnswers || [])"> <div class="row g-2 answer" *ngFor="let answer of (snapshot.chatAnswers || [])">

2
frontend/src/app/features/content/shared/forms/chat-dialog.component.scss

@ -2,5 +2,5 @@
@import 'vars'; @import 'vars';
textarea { textarea {
height: 100px; height: 300px;
} }

4
frontend/src/app/features/content/shared/forms/chat-dialog.component.ts

@ -52,10 +52,10 @@ export class ChatDialogComponent extends StatefulComponent<State> {
this.translator.ask(this.appsState.appName, { prompt: this.snapshot.chatQuestion }) this.translator.ask(this.appsState.appName, { prompt: this.snapshot.chatQuestion })
.subscribe({ .subscribe({
next: chatAnswers => { next: chatAnswers => {
this.next({ chatAnswers }); this.next({ chatAnswers, isRunning: false });
}, },
error: () => { error: () => {
this.next({ chatAnswers: [] }); this.next({ chatAnswers: [], isRunning: false });
}, },
complete: () => { complete: () => {
this.next({ isRunning: false }); this.next({ isRunning: false });

Loading…
Cancel
Save