diff --git a/backend/src/Notifo.Domain.Integrations.Abstractions/Notifo.Domain.Integrations.Abstractions.csproj b/backend/src/Notifo.Domain.Integrations.Abstractions/Notifo.Domain.Integrations.Abstractions.csproj index acd1847d..5123080a 100644 --- a/backend/src/Notifo.Domain.Integrations.Abstractions/Notifo.Domain.Integrations.Abstractions.csproj +++ b/backend/src/Notifo.Domain.Integrations.Abstractions/Notifo.Domain.Integrations.Abstractions.csproj @@ -10,7 +10,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/backend/src/Notifo.Domain.Integrations/Notifo.Domain.Integrations.csproj b/backend/src/Notifo.Domain.Integrations/Notifo.Domain.Integrations.csproj index e50419d7..ce4faa1b 100644 --- a/backend/src/Notifo.Domain.Integrations/Notifo.Domain.Integrations.csproj +++ b/backend/src/Notifo.Domain.Integrations/Notifo.Domain.Integrations.csproj @@ -9,31 +9,31 @@ - - - - - - - + + + + + + + - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + - + diff --git a/backend/src/Notifo.Domain/Channels/Email/Formatting/EmailFormatterLiquid.cs b/backend/src/Notifo.Domain/Channels/Email/Formatting/EmailFormatterLiquid.cs index 6c7fb819..af3ac2e3 100644 --- a/backend/src/Notifo.Domain/Channels/Email/Formatting/EmailFormatterLiquid.cs +++ b/backend/src/Notifo.Domain/Channels/Email/Formatting/EmailFormatterLiquid.cs @@ -52,32 +52,32 @@ public ValueTask CreateInitialAsync( return new ValueTask(template); } - public ValueTask ParseAsync(EmailTemplate input, bool strict, + public async ValueTask ParseAsync(EmailTemplate input, bool strict, CancellationToken ct = default) { var context = EmailContext.Create(PreviewData.Jobs, PreviewData.App, PreviewData.User, imageFormatter, emailUrl); - Format(input, context, true, strict); + await FormatAsync(input, context, true, strict); if (context.Errors?.Count > 0) { throw new EmailFormattingException(context.Errors); } - return new ValueTask(input); + return input; } - public ValueTask FormatAsync(EmailTemplate input, IReadOnlyList jobs, App app, User user, bool noCache = false, + public async ValueTask FormatAsync(EmailTemplate input, IReadOnlyList jobs, App app, User user, bool noCache = false, CancellationToken ct = default) { var context = EmailContext.Create(jobs, app, user, imageFormatter, emailUrl); - var message = Format(input, context, noCache, false); + var message = await FormatAsync(input, context, noCache, false); - return new ValueTask(new FormattedEmail(message, context.Errors)); + return new FormattedEmail(message, context.Errors); } - private static EmailMessage Format(EmailTemplate template, EmailContext context, bool noCache, bool strict) + private static async Task FormatAsync(EmailTemplate template, EmailContext context, bool noCache, bool strict) { var subject = string.Empty; @@ -97,7 +97,7 @@ private static EmailMessage Format(EmailTemplate template, EmailContext context, if (!string.IsNullOrWhiteSpace(template.BodyHtml)) { - bodyHtml = FormatBodyHtml(template.BodyHtml, context, noCache, strict)!; + bodyHtml = await FormatBodyHtmlAsync(template.BodyHtml, context, noCache, strict)!; } var firstJob = context.Jobs[0]; @@ -135,13 +135,13 @@ private static EmailMessage Format(EmailTemplate template, EmailContext context, return result; } - private static string? FormatBodyHtml(string template, EmailContext context, bool noCache, bool strict) + private static async Task FormatBodyHtmlAsync(string template, EmailContext context, bool noCache, bool strict) { var result = RenderTemplate(template, context, EmailTemplateType.BodyHtml, noCache); context.ValidateTemplate(result, EmailTemplateType.BodyHtml); - var (rendered, errors) = MjmlRenderer.Render(result, strict); + var (rendered, errors) = await MjmlRenderer.RenderAsync(result, strict); foreach (var error in errors.OrEmpty()) { diff --git a/backend/src/Notifo.Domain/Channels/Email/Formatting/MjmlRenderer.cs b/backend/src/Notifo.Domain/Channels/Email/Formatting/MjmlRenderer.cs index c202b17a..8fac4363 100644 --- a/backend/src/Notifo.Domain/Channels/Email/Formatting/MjmlRenderer.cs +++ b/backend/src/Notifo.Domain/Channels/Email/Formatting/MjmlRenderer.cs @@ -16,19 +16,24 @@ namespace Notifo.Domain.Channels.Email.Formatting; internal static class MjmlRenderer { - private static readonly MjmlOptions OptionsOptimized = new MjmlOptions + private static readonly MjmlOptions DefaultOptions = new MjmlOptions(); + + private static readonly MjmlOptions OptionsOptimized = DefaultOptions with { KeepComments = false, }; - private static readonly MjmlOptions OptionsStrict = new MjmlOptions + private static readonly MjmlOptions OptionsStrict = DefaultOptions with { Validator = StrictValidator.Instance, }; - private static readonly MjmlInternalRenderer Renderer = new MjmlInternalRenderer(); + private static readonly IMjmlRenderer Renderer = + new MjmlInternalRenderer() + .AddHtmlAttributes() + .AddList(); - public static (string? Html, List? Errors) Render(string? mjml, bool strict) + public static async ValueTask<(string? Html, List? Errors)> RenderAsync(string? mjml, bool strict) { if (string.IsNullOrWhiteSpace(mjml)) { @@ -48,7 +53,7 @@ public static (string? Html, List? Errors) Render(string? mjml, b OptionsStrict : OptionsOptimized; - (rendered, var mjmlErrors) = Renderer.Render(mjml, options); + (rendered, var mjmlErrors) = await Renderer.RenderAsync(mjml, options); errors = mjmlErrors?.Select(x => new TemplateError( x.Error, diff --git a/backend/src/Notifo.Domain/Integrations/ConditionParser.cs b/backend/src/Notifo.Domain/Integrations/ConditionParser.cs index 71806d85..bc40c29b 100644 --- a/backend/src/Notifo.Domain/Integrations/ConditionParser.cs +++ b/backend/src/Notifo.Domain/Integrations/ConditionParser.cs @@ -5,7 +5,7 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using Esprima.Ast; +using Acornima.Ast; using Jint; using Microsoft.Extensions.Caching.Memory; using Options = Microsoft.Extensions.Options.Options; diff --git a/backend/src/Notifo.Domain/Notifo.Domain.csproj b/backend/src/Notifo.Domain/Notifo.Domain.csproj index 90d89ed7..c61cf148 100644 --- a/backend/src/Notifo.Domain/Notifo.Domain.csproj +++ b/backend/src/Notifo.Domain/Notifo.Domain.csproj @@ -19,20 +19,21 @@ - - - - - + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - + + + + diff --git a/backend/src/Notifo.Identity/Notifo.Identity.csproj b/backend/src/Notifo.Identity/Notifo.Identity.csproj index 96c78bd5..60c8a636 100644 --- a/backend/src/Notifo.Identity/Notifo.Identity.csproj +++ b/backend/src/Notifo.Identity/Notifo.Identity.csproj @@ -9,17 +9,17 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + - - - + + + diff --git a/backend/src/Notifo.Infrastructure/Notifo.Infrastructure.csproj b/backend/src/Notifo.Infrastructure/Notifo.Infrastructure.csproj index 95bb542a..9a304701 100644 --- a/backend/src/Notifo.Infrastructure/Notifo.Infrastructure.csproj +++ b/backend/src/Notifo.Infrastructure/Notifo.Infrastructure.csproj @@ -9,8 +9,8 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -20,31 +20,31 @@ - + - - - + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - + diff --git a/backend/src/Notifo/Notifo.csproj b/backend/src/Notifo/Notifo.csproj index 5f8f0437..948f7a02 100644 --- a/backend/src/Notifo/Notifo.csproj +++ b/backend/src/Notifo/Notifo.csproj @@ -11,29 +11,29 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - - + + + + - + - + - + - + diff --git a/backend/src/Notifo/Pipeline/Telemetry/TelemetryServiceExtensions.cs b/backend/src/Notifo/Pipeline/Telemetry/TelemetryServiceExtensions.cs index 31853189..7ca4f147 100644 --- a/backend/src/Notifo/Pipeline/Telemetry/TelemetryServiceExtensions.cs +++ b/backend/src/Notifo/Pipeline/Telemetry/TelemetryServiceExtensions.cs @@ -7,6 +7,7 @@ using Azure.Monitor.OpenTelemetry.Exporter; using Google.Cloud.Diagnostics.Common; +using MongoDB.Driver.Core.Extensions.DiagnosticSources; using Notifo; using Notifo.Pipeline; using OpenTelemetry.Resources; @@ -33,7 +34,7 @@ public static void AddMyTelemetry(this IServiceCollection services, IConfigurati builder.AddAspNetCoreInstrumentation(); builder.AddHttpClientInstrumentation(); - builder.AddMongoDBInstrumentation(); + builder.AddSource(typeof(DiagnosticsActivityEventSubscriber).Assembly.GetName().Name!); var sampling = config.GetValue("logging:otlp:sampling"); diff --git a/backend/tests/Benchmarks/Benchmarks.csproj b/backend/tests/Benchmarks/Benchmarks.csproj index 65f4f7c8..c2d1a071 100644 --- a/backend/tests/Benchmarks/Benchmarks.csproj +++ b/backend/tests/Benchmarks/Benchmarks.csproj @@ -10,9 +10,9 @@ - + - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/backend/tests/Notifo.Domain.Tests/Channels/Email/MjmlSchemaTests.Should_build_schema.verified.txt b/backend/tests/Notifo.Domain.Tests/Channels/Email/MjmlSchemaTests.Should_build_schema.verified.txt index 428ed4d9..584deac5 100644 --- a/backend/tests/Notifo.Domain.Tests/Channels/Email/MjmlSchemaTests.Should_build_schema.verified.txt +++ b/backend/tests/Notifo.Domain.Tests/Channels/Email/MjmlSchemaTests.Should_build_schema.verified.txt @@ -684,7 +684,9 @@ }, mj-style: { Attributes: { - inline: null + inline: [ + inline + ] } }, mj-table: { @@ -1483,7 +1485,9 @@ }, mj-style: { Attributes: { - inline: null + inline: [ + inline + ] } }, mj-table: { diff --git a/backend/tests/Notifo.Domain.Tests/Channels/Email/MjmlSchemaTests.Should_build_schema_as_json.verified.txt b/backend/tests/Notifo.Domain.Tests/Channels/Email/MjmlSchemaTests.Should_build_schema_as_json.verified.txt index 42a0e6e7..b7cd89ba 100644 --- a/backend/tests/Notifo.Domain.Tests/Channels/Email/MjmlSchemaTests.Should_build_schema_as_json.verified.txt +++ b/backend/tests/Notifo.Domain.Tests/Channels/Email/MjmlSchemaTests.Should_build_schema_as_json.verified.txt @@ -714,7 +714,9 @@ }, "mj-style": { "attrs": { - "inline": null + "inline": [ + "inline" + ] }, "children": null }, diff --git a/backend/tests/Notifo.Domain.Tests/Channels/MobilePush/MobilePushJobTests.cs b/backend/tests/Notifo.Domain.Tests/Channels/MobilePush/MobilePushJobTests.cs index e062eabf..8d1390e5 100644 --- a/backend/tests/Notifo.Domain.Tests/Channels/MobilePush/MobilePushJobTests.cs +++ b/backend/tests/Notifo.Domain.Tests/Channels/MobilePush/MobilePushJobTests.cs @@ -46,6 +46,7 @@ public void Should_serialize_and_deserialize() var serialized = sut.SerializeAndDeserialize(); - serialized.Should().BeEquivalentTo(sut); + serialized.Should().BeEquivalentTo(sut, + options => options.Excluding(member => member.Name == "Properties")); } } diff --git a/backend/tests/Notifo.Domain.Tests/Notifo.Domain.Tests.csproj b/backend/tests/Notifo.Domain.Tests/Notifo.Domain.Tests.csproj index 4909e95f..8d086058 100644 --- a/backend/tests/Notifo.Domain.Tests/Notifo.Domain.Tests.csproj +++ b/backend/tests/Notifo.Domain.Tests/Notifo.Domain.Tests.csproj @@ -18,16 +18,16 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + - - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/backend/tests/Notifo.Identity.Tests/Notifo.Identity.Tests.csproj b/backend/tests/Notifo.Identity.Tests/Notifo.Identity.Tests.csproj index 11836904..2127da13 100644 --- a/backend/tests/Notifo.Identity.Tests/Notifo.Identity.Tests.csproj +++ b/backend/tests/Notifo.Identity.Tests/Notifo.Identity.Tests.csproj @@ -11,13 +11,13 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/backend/tests/Notifo.Infrastructure.Tests/Notifo.Infrastructure.Tests.csproj b/backend/tests/Notifo.Infrastructure.Tests/Notifo.Infrastructure.Tests.csproj index 126da2d0..6c867f31 100644 --- a/backend/tests/Notifo.Infrastructure.Tests/Notifo.Infrastructure.Tests.csproj +++ b/backend/tests/Notifo.Infrastructure.Tests/Notifo.Infrastructure.Tests.csproj @@ -11,14 +11,14 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - - + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/frontend/src/app/App.tsx b/frontend/src/app/App.tsx index feb6bf8e..bb4d66af 100644 --- a/frontend/src/app/App.tsx +++ b/frontend/src/app/App.tsx @@ -30,7 +30,7 @@ export const App = () => { } /> - } /> { const app = useApp()!; const sortedKeys = React.useMemo(() => { - const keys = Object.keys(app.apiKeys).map(x => ([x, app.apiKeys[x]])); + const keys = Object.entries(app.apiKeys).map(x => ({ key: x[0], role: x[1] })); - keys.sort((x, y) => x[1].localeCompare(y[1])); + keys.sort((x, y) => x.role.localeCompare(y.role)); return keys; }, [app]); + const apiKey = sortedKeys.filter(x => x.role === 'WebManager').map(x => x.key)[0]; + return (

{texts.app.welcome(app.name)}

@@ -45,10 +47,10 @@ export const AppDashboardPage = () => { {sortedKeys.map(x => ( - - + + - + ))} @@ -58,7 +60,16 @@ export const AppDashboardPage = () => { - + + + + + + + {texts.common.demo} + + + diff --git a/frontend/src/app/pages/app/AppPage.tsx b/frontend/src/app/pages/app/AppPage.tsx index 839807e4..a017b01d 100644 --- a/frontend/src/app/pages/app/AppPage.tsx +++ b/frontend/src/app/pages/app/AppPage.tsx @@ -30,6 +30,7 @@ import { UserPage } from './../user/UserPage'; import { UsersPage } from './../users/UsersPage'; import { AppDashboardPage } from './AppDashboardPage'; import { AppSettingsPage } from './AppSettingsPage'; +import { DemoPage } from '../user/DemoPage'; const NavDesign = () => { const [isOpen, setIsOpen] = useBoolean(); diff --git a/frontend/src/app/pages/user/DemoPage.tsx b/frontend/src/app/pages/user/DemoPage.tsx index cdb43d2f..39ab5b37 100644 --- a/frontend/src/app/pages/user/DemoPage.tsx +++ b/frontend/src/app/pages/user/DemoPage.tsx @@ -10,32 +10,29 @@ import ReactMarkdown from 'react-markdown'; import { useParams } from 'react-router'; import { Card, CardBody, Col, Container, Row } from 'reactstrap'; import { texts } from '@app/texts'; +import { useSearchParams } from 'react-router-dom'; export const DemoPage = () => { const userToken = useParams().userId!; + const [params] = useSearchParams(); React.useEffect(() => { - if (!userToken) { - return; - } - const notifo = (window as any)['notifo'] || ((window as any)['notifo'] = []); - notifo.push(['init', { + const args = { + linkTarget: '_blank', apiUrl: '/', - + apiKey: params.get('apiKey'), + userToken, onNotification: (notification: any) => { console.log(`Received: ${JSON.stringify(notification, undefined, 2)}`); }, - onConfirm: (notification: any) => { console.log(`Confirmed: ${JSON.stringify(notification, undefined, 2)}`); }, + } - linkTarget: '_blank', - - userToken, - }]); + notifo.push(['init', args]); notifo.push(['show-notifications', 'button1', { style: 'notifo', position: 'bottom-left' }]); diff --git a/frontend/src/sdk/sdk.ts b/frontend/src/sdk/sdk.ts index b589ae67..d54b0863 100644 --- a/frontend/src/sdk/sdk.ts +++ b/frontend/src/sdk/sdk.ts @@ -22,8 +22,8 @@ async function init(value: any) { const options = buildSDKConfig(value, scriptLocation); if (options) { - await apiConnect(options); await apiRegister(options); + await apiConnect(options); queueInit.config = options; }