From e93c8cd6ef43b52d23d78c65a81eebd38b026e2e Mon Sep 17 00:00:00 2001 From: CR4567 Date: Thu, 14 Mar 2024 17:02:17 +0100 Subject: [PATCH 01/10] fixed missing tooltips after package update (#222) Co-authored-by: Chris --- frontend/src/app/App.tsx | 2 +- frontend/src/app/pages/events/EventsPage.tsx | 2 +- .../app/pages/integrations/IntegrationDialog.tsx | 2 +- .../app/pages/integrations/IntegrationsPage.tsx | 2 +- frontend/src/app/pages/log/LogPage.tsx | 2 +- frontend/src/app/pages/media/MediaPage.tsx | 2 +- .../src/app/pages/system-users/SystemUserRow.tsx | 8 ++++---- .../src/app/pages/system-users/SystemUsersPage.tsx | 2 +- frontend/src/app/pages/templates/TemplateRow.tsx | 6 +++--- frontend/src/app/pages/templates/TemplatesList.tsx | 2 +- frontend/src/app/pages/topics/TopicRow.tsx | 4 ++-- frontend/src/app/pages/topics/TopicsPage.tsx | 2 +- frontend/src/app/pages/user/NotificationRow.tsx | 14 +++++++------- frontend/src/app/pages/user/Notifications.tsx | 4 ++-- frontend/src/app/pages/user/SubscriptionRow.tsx | 6 +++--- frontend/src/app/pages/user/Subscriptions.tsx | 2 +- frontend/src/app/pages/users/UserRow.tsx | 6 +++--- frontend/src/app/pages/users/UsersPage.tsx | 2 +- frontend/src/app/shared/components/MediaCard.tsx | 2 +- frontend/src/app/shared/components/MediaPicker.tsx | 2 +- .../src/app/shared/components/StatisticsLabel.tsx | 2 +- 21 files changed, 38 insertions(+), 38 deletions(-) diff --git a/frontend/src/app/App.tsx b/frontend/src/app/App.tsx index 17933419..feb6bf8e 100644 --- a/frontend/src/app/App.tsx +++ b/frontend/src/app/App.tsx @@ -40,7 +40,7 @@ export const App = () => { element={} /> - + diff --git a/frontend/src/app/pages/events/EventsPage.tsx b/frontend/src/app/pages/events/EventsPage.tsx index c76fa764..2d5cc521 100644 --- a/frontend/src/app/pages/events/EventsPage.tsx +++ b/frontend/src/app/pages/events/EventsPage.tsx @@ -52,7 +52,7 @@ export const EventsPage = () => { {events.isLoading ? ( ) : ( - )} diff --git a/frontend/src/app/pages/integrations/IntegrationDialog.tsx b/frontend/src/app/pages/integrations/IntegrationDialog.tsx index 6db69c18..0e9c36f3 100644 --- a/frontend/src/app/pages/integrations/IntegrationDialog.tsx +++ b/frontend/src/app/pages/integrations/IntegrationDialog.tsx @@ -230,7 +230,7 @@ export const IntegrationDialog = (props: IntegrationDialogProps) => { {({ onClick }) => ( - )} diff --git a/frontend/src/app/pages/integrations/IntegrationsPage.tsx b/frontend/src/app/pages/integrations/IntegrationsPage.tsx index 0f25b044..436d00ca 100644 --- a/frontend/src/app/pages/integrations/IntegrationsPage.tsx +++ b/frontend/src/app/pages/integrations/IntegrationsPage.tsx @@ -69,7 +69,7 @@ export const IntegrationsPage = () => { {loading ? ( ) : ( - )} diff --git a/frontend/src/app/pages/log/LogPage.tsx b/frontend/src/app/pages/log/LogPage.tsx index c8dd5752..2a993fb6 100644 --- a/frontend/src/app/pages/log/LogPage.tsx +++ b/frontend/src/app/pages/log/LogPage.tsx @@ -57,7 +57,7 @@ export const LogPage = () => { {logEntries.isLoading ? ( ) : ( - )} diff --git a/frontend/src/app/pages/media/MediaPage.tsx b/frontend/src/app/pages/media/MediaPage.tsx index 4e80198a..4947807b 100644 --- a/frontend/src/app/pages/media/MediaPage.tsx +++ b/frontend/src/app/pages/media/MediaPage.tsx @@ -55,7 +55,7 @@ export const MediaPage = () => { {media.isLoading ? ( ) : ( - )} diff --git a/frontend/src/app/pages/system-users/SystemUserRow.tsx b/frontend/src/app/pages/system-users/SystemUserRow.tsx index 46d88be4..f4555fea 100644 --- a/frontend/src/app/pages/system-users/SystemUserRow.tsx +++ b/frontend/src/app/pages/system-users/SystemUserRow.tsx @@ -69,24 +69,24 @@ export const SystemUserRow = React.memo((props: SystemUserRowProps) => { {user.canUpdate && <> {!user.isLocked && - } {user.isLocked && - } - {({ onClick }) => ( - )} diff --git a/frontend/src/app/pages/system-users/SystemUsersPage.tsx b/frontend/src/app/pages/system-users/SystemUsersPage.tsx index e1d1f855..8815992a 100644 --- a/frontend/src/app/pages/system-users/SystemUsersPage.tsx +++ b/frontend/src/app/pages/system-users/SystemUsersPage.tsx @@ -66,7 +66,7 @@ export const SystemUsersPage = () => { {systemUsers.isLoading ? ( ) : ( - )} diff --git a/frontend/src/app/pages/templates/TemplateRow.tsx b/frontend/src/app/pages/templates/TemplateRow.tsx index 4c815405..481c83c6 100644 --- a/frontend/src/app/pages/templates/TemplateRow.tsx +++ b/frontend/src/app/pages/templates/TemplateRow.tsx @@ -57,17 +57,17 @@ export const TemplateRow = React.memo((props: TemplateRowProps) => { {template.code} - - {({ onClick }) => ( - )} diff --git a/frontend/src/app/pages/templates/TemplatesList.tsx b/frontend/src/app/pages/templates/TemplatesList.tsx index 7fa96b65..8cbc772e 100644 --- a/frontend/src/app/pages/templates/TemplatesList.tsx +++ b/frontend/src/app/pages/templates/TemplatesList.tsx @@ -66,7 +66,7 @@ export const TemplatesList = (props: TemplateListProps) => { {templates.isLoading ? ( ) : ( - )} diff --git a/frontend/src/app/pages/topics/TopicRow.tsx b/frontend/src/app/pages/topics/TopicRow.tsx index fec84854..5937d1a4 100644 --- a/frontend/src/app/pages/topics/TopicRow.tsx +++ b/frontend/src/app/pages/topics/TopicRow.tsx @@ -64,13 +64,13 @@ export const TopicRow = React.memo((props: TopicRowProps) => { {topic.isExplicit && <> - {({ onClick }) => ( - )} diff --git a/frontend/src/app/pages/topics/TopicsPage.tsx b/frontend/src/app/pages/topics/TopicsPage.tsx index 1ebcf003..53c5c41d 100644 --- a/frontend/src/app/pages/topics/TopicsPage.tsx +++ b/frontend/src/app/pages/topics/TopicsPage.tsx @@ -78,7 +78,7 @@ export const TopicsPage = () => { {topics.isLoading ? ( ) : ( - )} diff --git a/frontend/src/app/pages/user/NotificationRow.tsx b/frontend/src/app/pages/user/NotificationRow.tsx index c10a5637..f794b1bc 100644 --- a/frontend/src/app/pages/user/NotificationRow.tsx +++ b/frontend/src/app/pages/user/NotificationRow.tsx @@ -43,25 +43,25 @@ export const NotificationRow = React.memo((props: NotificationRowProps) => { {notification.subject} - + {numSkipped || '-'} - + {numFailed || '-'} - + {numSent || '-'} - + {numHandled || '-'} - + {numFirstDelivered || '-'} - + {numFirstSeen || '-'} - + {numFirstConfirmed || '-'} diff --git a/frontend/src/app/pages/user/Notifications.tsx b/frontend/src/app/pages/user/Notifications.tsx index 8d3cc7af..30e3102b 100644 --- a/frontend/src/app/pages/user/Notifications.tsx +++ b/frontend/src/app/pages/user/Notifications.tsx @@ -71,7 +71,7 @@ export const Notifications = (props: NotificationsProps) => { {notifications.isLoading ? ( ) : ( - )} @@ -110,7 +110,7 @@ export const Notifications = (props: NotificationsProps) => { {texts.common.subject} - + {texts.common.status} diff --git a/frontend/src/app/pages/user/SubscriptionRow.tsx b/frontend/src/app/pages/user/SubscriptionRow.tsx index 4794a0de..a4f3aa5c 100644 --- a/frontend/src/app/pages/user/SubscriptionRow.tsx +++ b/frontend/src/app/pages/user/SubscriptionRow.tsx @@ -46,17 +46,17 @@ export const SubscriptionRow = React.memo((props: SubscriptionRowProps) => { {subscription.topicPrefix} - - {({ onClick }) => ( - )} diff --git a/frontend/src/app/pages/user/Subscriptions.tsx b/frontend/src/app/pages/user/Subscriptions.tsx index 6cc3da7f..ce356ac5 100644 --- a/frontend/src/app/pages/user/Subscriptions.tsx +++ b/frontend/src/app/pages/user/Subscriptions.tsx @@ -83,7 +83,7 @@ export const Subscriptions = (props: SubscriptionsProps) => { {subscriptions.isLoading ? ( ) : ( - )} diff --git a/frontend/src/app/pages/users/UserRow.tsx b/frontend/src/app/pages/users/UserRow.tsx index 0843ec27..1e2a7000 100644 --- a/frontend/src/app/pages/users/UserRow.tsx +++ b/frontend/src/app/pages/users/UserRow.tsx @@ -76,17 +76,17 @@ export const UserRow = React.memo((props: UserRowProps) => { - - {({ onClick }) => ( - )} diff --git a/frontend/src/app/pages/users/UsersPage.tsx b/frontend/src/app/pages/users/UsersPage.tsx index b35e2b79..8589ca0c 100644 --- a/frontend/src/app/pages/users/UsersPage.tsx +++ b/frontend/src/app/pages/users/UsersPage.tsx @@ -64,7 +64,7 @@ export const UsersPage = () => { {users.isLoading ? ( ) : ( - )} diff --git a/frontend/src/app/shared/components/MediaCard.tsx b/frontend/src/app/shared/components/MediaCard.tsx index 1ca68697..0345e39b 100644 --- a/frontend/src/app/shared/components/MediaCard.tsx +++ b/frontend/src/app/shared/components/MediaCard.tsx @@ -63,7 +63,7 @@ export const MediaCard = React.memo((props: MediaCardProps) => { {onDelete && {({ onClick }) => ( - )} diff --git a/frontend/src/app/shared/components/MediaPicker.tsx b/frontend/src/app/shared/components/MediaPicker.tsx index 20d76079..987f37bf 100644 --- a/frontend/src/app/shared/components/MediaPicker.tsx +++ b/frontend/src/app/shared/components/MediaPicker.tsx @@ -74,7 +74,7 @@ export const MediaPicker = (props: MediaPickerProps) => { {medias.isLoading ? ( ) : ( - )} diff --git a/frontend/src/app/shared/components/StatisticsLabel.tsx b/frontend/src/app/shared/components/StatisticsLabel.tsx index ae83d3e5..1064005f 100644 --- a/frontend/src/app/shared/components/StatisticsLabel.tsx +++ b/frontend/src/app/shared/components/StatisticsLabel.tsx @@ -36,7 +36,7 @@ export const StatisticsLabel = React.memo((props: StatisticsLabelProps) => { } = props; return ( - + From 27244c6d01cce2cf7f7019fcd9ff7d51d3d805c4 Mon Sep 17 00:00:00 2001 From: Sebastian Stehle Date: Thu, 21 Mar 2024 20:44:37 +0100 Subject: [PATCH 02/10] Indented (#227) * Indented * Update packages again. --- ...fo.Domain.Integrations.Abstractions.csproj | 2 +- .../Notifo.Domain.Integrations.csproj | 14 +++---- .../Twilio/TwilioSmsIntegration.Sms.cs | 9 +++-- .../Twilio/TwilioSmsIntegration.cs | 7 +--- .../src/Notifo.Domain/Notifo.Domain.csproj | 12 +++--- .../Notifo.Identity/Notifo.Identity.csproj | 8 ++-- .../Caching/CachingServiceExtensions.cs | 6 +-- .../src/Notifo.Infrastructure/NodaPatterns.cs | 2 +- .../Notifo.Infrastructure.csproj | 40 +++++++++---------- .../Controllers/Media/MediaBaseController.cs | 4 +- backend/src/Notifo/Notifo.csproj | 20 +++++----- backend/tests/Benchmarks/Benchmarks.csproj | 2 +- .../Channels/Email/MjmlSchemaTests.cs | 10 +++-- .../Notifo.Domain.Tests.csproj | 6 +-- .../Notifo.Identity.Tests.csproj | 4 +- .../Notifo.Infrastructure.Tests.csproj | 6 +-- 16 files changed, 74 insertions(+), 78 deletions(-) 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 445dfd0b..a623775f 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 217aff9c..aa858ad7 100644 --- a/backend/src/Notifo.Domain.Integrations/Notifo.Domain.Integrations.csproj +++ b/backend/src/Notifo.Domain.Integrations/Notifo.Domain.Integrations.csproj @@ -9,22 +9,22 @@ - + - - + + - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + @@ -32,7 +32,7 @@ - + diff --git a/backend/src/Notifo.Domain.Integrations/Twilio/TwilioSmsIntegration.Sms.cs b/backend/src/Notifo.Domain.Integrations/Twilio/TwilioSmsIntegration.Sms.cs index fce8c324..20af2ae8 100644 --- a/backend/src/Notifo.Domain.Integrations/Twilio/TwilioSmsIntegration.Sms.cs +++ b/backend/src/Notifo.Domain.Integrations/Twilio/TwilioSmsIntegration.Sms.cs @@ -29,10 +29,13 @@ public async Task SendAsync(IntegrationContext context, SmsMessa var to = message.To; var result = await MessageResource.CreateAsync( - ConvertPhoneNumber(to), null, - ConvertPhoneNumber(phoneNumber), null, + ConvertPhoneNumber(to), + null, + ConvertPhoneNumber(phoneNumber.ToString(CultureInfo.InvariantCulture)), + null, message.Text, - statusCallback: new Uri(BuildCallbackUrl(context, message)), client: client); + statusCallback: new Uri(BuildCallbackUrl(context, message)), + client: client); if (!string.IsNullOrWhiteSpace(result.ErrorMessage)) { diff --git a/backend/src/Notifo.Domain.Integrations/Twilio/TwilioSmsIntegration.cs b/backend/src/Notifo.Domain.Integrations/Twilio/TwilioSmsIntegration.cs index 006b352c..697d7602 100644 --- a/backend/src/Notifo.Domain.Integrations/Twilio/TwilioSmsIntegration.cs +++ b/backend/src/Notifo.Domain.Integrations/Twilio/TwilioSmsIntegration.cs @@ -74,7 +74,7 @@ public async Task OnConfiguredAsync(IntegrationContext contex { var client = clientPool.GetServer(accountSid, accountToken); - await PhoneNumberResource.FetchAsync(ConvertPhoneNumber(phoneNumber), client: client); + await PhoneNumberResource.FetchAsync(new FetchPhoneNumberOptions($"+{phoneNumber}"), client: client); } catch { @@ -83,9 +83,4 @@ public async Task OnConfiguredAsync(IntegrationContext contex return IntegrationStatus.Verified; } - - private static PhoneNumber ConvertPhoneNumber(long number) - { - return new PhoneNumber($"+{number}"); - } } diff --git a/backend/src/Notifo.Domain/Notifo.Domain.csproj b/backend/src/Notifo.Domain/Notifo.Domain.csproj index 50758ae4..514a664d 100644 --- a/backend/src/Notifo.Domain/Notifo.Domain.csproj +++ b/backend/src/Notifo.Domain/Notifo.Domain.csproj @@ -20,18 +20,18 @@ - - - - + + + + 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 5a86adbf..bf0df667 100644 --- a/backend/src/Notifo.Identity/Notifo.Identity.csproj +++ b/backend/src/Notifo.Identity/Notifo.Identity.csproj @@ -10,14 +10,14 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + - + diff --git a/backend/src/Notifo.Infrastructure/Caching/CachingServiceExtensions.cs b/backend/src/Notifo.Infrastructure/Caching/CachingServiceExtensions.cs index d3c17cad..2f12f757 100644 --- a/backend/src/Notifo.Infrastructure/Caching/CachingServiceExtensions.cs +++ b/backend/src/Notifo.Infrastructure/Caching/CachingServiceExtensions.cs @@ -11,11 +11,7 @@ public static class CachingServiceExtensions { public static void AddMyCaching(this IServiceCollection services) { - services.AddReplicatedCache(options => - { - options.Enable = true; - }); - + services.AddReplicatedCache(); services.AddAsyncLocalCache(); } } diff --git a/backend/src/Notifo.Infrastructure/NodaPatterns.cs b/backend/src/Notifo.Infrastructure/NodaPatterns.cs index 373f7dfd..68c47421 100644 --- a/backend/src/Notifo.Infrastructure/NodaPatterns.cs +++ b/backend/src/Notifo.Infrastructure/NodaPatterns.cs @@ -15,7 +15,7 @@ public static class NodaPatterns public static readonly LocalTimePattern HourIsoPatternImpl = LocalTimePattern.CreateWithInvariantCulture("HH"); - public static readonly LocalTimePattern HourMinuteIsoPatternImpl = + public static readonly LocalTimePattern HourMinuteIsoPatternImpl = LocalTimePattern.CreateWithInvariantCulture("HH':'mm"); public static readonly IPattern VariablePrecisionIso = new CompositePatternBuilder diff --git a/backend/src/Notifo.Infrastructure/Notifo.Infrastructure.csproj b/backend/src/Notifo.Infrastructure/Notifo.Infrastructure.csproj index 0222e060..c90f54b1 100644 --- a/backend/src/Notifo.Infrastructure/Notifo.Infrastructure.csproj +++ b/backend/src/Notifo.Infrastructure/Notifo.Infrastructure.csproj @@ -10,39 +10,39 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + - + - + - + - + - - - - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/backend/src/Notifo/Areas/Api/Controllers/Media/MediaBaseController.cs b/backend/src/Notifo/Areas/Api/Controllers/Media/MediaBaseController.cs index 872882bf..ae3cd20e 100644 --- a/backend/src/Notifo/Areas/Api/Controllers/Media/MediaBaseController.cs +++ b/backend/src/Notifo/Areas/Api/Controllers/Media/MediaBaseController.cs @@ -114,8 +114,8 @@ private async Task ResizeAsync(ResizeSource source, string destinationContentTyp #pragma warning disable MA0040 // Flow the cancellation token using var activity = Telemetry.Activities.StartActivity("Resize"); - await using var assetOriginal = new TempAssetFile(source.FileName, source.MimeType, 0); - await using var assetResized = new TempAssetFile(source.FileName, destinationContentType, 0); + await using var assetOriginal = new TempAssetFile(source.FileName, source.MimeType); + await using var assetResized = new TempAssetFile(source.FileName, destinationContentType); using (Telemetry.Activities.StartActivity("Read")) { diff --git a/backend/src/Notifo/Notifo.csproj b/backend/src/Notifo/Notifo.csproj index 6090f4eb..d06f3d13 100644 --- a/backend/src/Notifo/Notifo.csproj +++ b/backend/src/Notifo/Notifo.csproj @@ -10,18 +10,18 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - + + + + + - + @@ -30,10 +30,10 @@ - + - + diff --git a/backend/tests/Benchmarks/Benchmarks.csproj b/backend/tests/Benchmarks/Benchmarks.csproj index c99a09cb..972d5d11 100644 --- a/backend/tests/Benchmarks/Benchmarks.csproj +++ b/backend/tests/Benchmarks/Benchmarks.csproj @@ -12,7 +12,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/backend/tests/Notifo.Domain.Tests/Channels/Email/MjmlSchemaTests.cs b/backend/tests/Notifo.Domain.Tests/Channels/Email/MjmlSchemaTests.cs index f1d42e72..962487b2 100644 --- a/backend/tests/Notifo.Domain.Tests/Channels/Email/MjmlSchemaTests.cs +++ b/backend/tests/Notifo.Domain.Tests/Channels/Email/MjmlSchemaTests.cs @@ -13,6 +13,11 @@ namespace Notifo.Domain.Channels.Email; public class MjmlSchemaTests { + private static readonly JsonSerializerOptions Indented = new JsonSerializerOptions + { + WriteIndented = true + }; + private readonly IMjmlRenderer mjmlRenderer = new MjmlRenderer(); [Fact] @@ -26,10 +31,7 @@ public async Task Should_build_schema() [Fact] public async Task Should_build_schema_as_json() { - var json = JsonSerializer.Serialize(MjmlSchema.Build(mjmlRenderer), new JsonSerializerOptions - { - WriteIndented = true - }); + var json = JsonSerializer.Serialize(MjmlSchema.Build(mjmlRenderer), Indented); await Verify(json); } diff --git a/backend/tests/Notifo.Domain.Tests/Notifo.Domain.Tests.csproj b/backend/tests/Notifo.Domain.Tests/Notifo.Domain.Tests.csproj index 88bd5466..39da70a2 100644 --- a/backend/tests/Notifo.Domain.Tests/Notifo.Domain.Tests.csproj +++ b/backend/tests/Notifo.Domain.Tests/Notifo.Domain.Tests.csproj @@ -13,19 +13,19 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + 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 b6ae2ce8..28654a3a 100644 --- a/backend/tests/Notifo.Identity.Tests/Notifo.Identity.Tests.csproj +++ b/backend/tests/Notifo.Identity.Tests/Notifo.Identity.Tests.csproj @@ -11,7 +11,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -21,7 +21,7 @@ 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 b1b0a565..85831ce6 100644 --- a/backend/tests/Notifo.Infrastructure.Tests/Notifo.Infrastructure.Tests.csproj +++ b/backend/tests/Notifo.Infrastructure.Tests/Notifo.Infrastructure.Tests.csproj @@ -11,18 +11,18 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive From 9dce26aa8e6a09429adccf772841229625a20775 Mon Sep 17 00:00:00 2001 From: Sebastian Stehle Date: Sun, 24 Mar 2024 15:53:16 +0100 Subject: [PATCH 03/10] Update libs (#228) * Indented * Update packages again. * Update libs again. --- .../Notifo.Domain.Integrations.csproj | 2 +- .../Events/EventsServiceExtensions.cs | 3 +- .../UserEvents/UserEventsServiceExtensions.cs | 12 ++++--- .../UserNotificationsServiceExtensions.cs | 18 +++++----- .../Notifo.Infrastructure.csproj | 28 +++++++-------- backend/src/Notifo/Notifo.csproj | 4 +-- backend/src/Notifo/ServiceExtensions.cs | 35 ++++++++++++------- backend/src/Notifo/Startup.cs | 4 +-- 8 files changed, 59 insertions(+), 47 deletions(-) diff --git a/backend/src/Notifo.Domain.Integrations/Notifo.Domain.Integrations.csproj b/backend/src/Notifo.Domain.Integrations/Notifo.Domain.Integrations.csproj index aa858ad7..f9c03620 100644 --- a/backend/src/Notifo.Domain.Integrations/Notifo.Domain.Integrations.csproj +++ b/backend/src/Notifo.Domain.Integrations/Notifo.Domain.Integrations.csproj @@ -9,7 +9,7 @@ - + diff --git a/backend/src/Notifo.Domain/Events/EventsServiceExtensions.cs b/backend/src/Notifo.Domain/Events/EventsServiceExtensions.cs index f5cf8e50..0070e9f7 100644 --- a/backend/src/Notifo.Domain/Events/EventsServiceExtensions.cs +++ b/backend/src/Notifo.Domain/Events/EventsServiceExtensions.cs @@ -22,7 +22,8 @@ public static void AddMyEvents(this IServiceCollection services, IConfiguration services.ConfigureAndValidate(config, "events"); - services.AddMessaging(new ChannelName(options.ChannelName), true); + services.AddMessaging() + .AddChannel(new ChannelName(options.ChannelName), true); services.Configure(messaging => { diff --git a/backend/src/Notifo.Domain/UserEvents/UserEventsServiceExtensions.cs b/backend/src/Notifo.Domain/UserEvents/UserEventsServiceExtensions.cs index 1a616d49..4349ac08 100644 --- a/backend/src/Notifo.Domain/UserEvents/UserEventsServiceExtensions.cs +++ b/backend/src/Notifo.Domain/UserEvents/UserEventsServiceExtensions.cs @@ -14,21 +14,23 @@ namespace Microsoft.Extensions.DependencyInjection; public static class UserEventsServiceExtensions { - public static void AddMyUserEvents(this IServiceCollection services, IConfiguration config) + public static MessagingBuilder AddMyUserEvents(this MessagingBuilder builder, IConfiguration config) { var options = config.GetSection("pipeline:userEvents").Get() ?? new UserEventPipelineOptions(); - services.AddMessaging(new ChannelName(options.ChannelName), true); + builder.AddChannel(new ChannelName(options.ChannelName), true); - services.Configure(messaging => + builder.Configure(messaging => { messaging.Routing.Add(x => x is UserEventMessage, options.ChannelName); }); - services.AddSingletonAs() + builder.Services.AddSingletonAs() .AsSelf().As(); - services.AddSingletonAs() + builder.Services.AddSingletonAs() .As(); + + return builder; } } diff --git a/backend/src/Notifo.Domain/UserNotifications/UserNotificationsServiceExtensions.cs b/backend/src/Notifo.Domain/UserNotifications/UserNotificationsServiceExtensions.cs index 3c522e79..af4853b5 100644 --- a/backend/src/Notifo.Domain/UserNotifications/UserNotificationsServiceExtensions.cs +++ b/backend/src/Notifo.Domain/UserNotifications/UserNotificationsServiceExtensions.cs @@ -16,29 +16,31 @@ namespace Microsoft.Extensions.DependencyInjection; public static class UserNotificationsServiceExtensions { - public static void AddMyUserNotifications(this IServiceCollection services, IConfiguration config) + public static MessagingBuilder AddMyUserNotifications(this MessagingBuilder builder, IConfiguration config) { var options = config.GetSection("pipeline:confirms").Get() ?? new ConfirmPipelineOptions(); - services.ConfigureAndValidate(config, "notifications"); + builder.Services.ConfigureAndValidate(config, "notifications"); - services.AddMessaging(new ChannelName(options.ChannelName), true); + builder.AddChannel(new ChannelName(options.ChannelName), true); - services.Configure(messaging => + builder.Configure(messaging => { messaging.Routing.Add(x => x is ConfirmMessage, options.ChannelName); }); - services.AddSingletonAs() + builder.Services.AddSingletonAs() .As(); - services.AddSingletonAs() + builder.Services.AddSingletonAs() .As(); - services.AddSingletonAs() + builder.Services.AddSingletonAs() .As().AsSelf().As>().As(); - services.AddScheduler("UserNotifications"); + builder.Services.AddScheduler("UserNotifications"); + + return builder; } public static void AddMyMongoUserNotifications(this IServiceCollection services) diff --git a/backend/src/Notifo.Infrastructure/Notifo.Infrastructure.csproj b/backend/src/Notifo.Infrastructure/Notifo.Infrastructure.csproj index c90f54b1..fd04691e 100644 --- a/backend/src/Notifo.Infrastructure/Notifo.Infrastructure.csproj +++ b/backend/src/Notifo.Infrastructure/Notifo.Infrastructure.csproj @@ -29,20 +29,20 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/backend/src/Notifo/Notifo.csproj b/backend/src/Notifo/Notifo.csproj index d06f3d13..7e72a779 100644 --- a/backend/src/Notifo/Notifo.csproj +++ b/backend/src/Notifo/Notifo.csproj @@ -23,14 +23,14 @@ - + - + diff --git a/backend/src/Notifo/ServiceExtensions.cs b/backend/src/Notifo/ServiceExtensions.cs index e32ee724..87c5f6ab 100644 --- a/backend/src/Notifo/ServiceExtensions.cs +++ b/backend/src/Notifo/ServiceExtensions.cs @@ -62,6 +62,14 @@ public static void AddMyStorage(this IServiceCollection services, IConfiguration }); } + public static void AddMyMessaging(this IServiceCollection services, IConfiguration config) + { + services.AddMessaging() + .AddTransport(config) + .AddMyUserEvents(config) + .AddMyUserNotifications(config); + } + public static void AddMyClustering(this IServiceCollection services, IConfiguration config, SignalROptions signalROptions) { config.ConfigureByOption("clustering:type", new Alternatives @@ -79,22 +87,23 @@ public static void AddMyClustering(this IServiceCollection services, IConfigurat }); } - services.AddRedisTransport(config, options => - { - options.ConnectionFactory = connection.ConnectAsync; - }); - - services.AddReplicatedCacheMessaging(true, options => - { - options.TransportSelector = (transports, name) => transports.First(x => x is RedisTransport); - }); + services.AddMessaging() + .AddRedisTransport(config, options => + { + options.ConnectionFactory = connection.ConnectAsync; + }) + .AddReplicatedCache(true, options => + { + options.TransportSelector = (transports, name) => transports.First(x => x is RedisTransport); + }); }, ["None"] = () => { - services.AddReplicatedCacheMessaging(false, options => - { - options.TransportSelector = (transports, name) => transports.First(x => x is NullTransport); - }); + services.AddMessaging() + .AddReplicatedCache(false, options => + { + options.TransportSelector = (transports, name) => transports.First(x => x is NullTransport); + }); } }); } diff --git a/backend/src/Notifo/Startup.cs b/backend/src/Notifo/Startup.cs index 1bcffd6c..bc71307f 100644 --- a/backend/src/Notifo/Startup.cs +++ b/backend/src/Notifo/Startup.cs @@ -127,7 +127,7 @@ public void ConfigureServices(IServiceCollection services) services.AddMyJson(ConfigureJson); services.AddMyLog(); services.AddMyMedia(); - services.AddMessagingTransport(config); + services.AddMyMessaging(config); services.AddMyMessagingChannel(); services.AddMyMobilePushChannel(); services.AddMyNodaTime(); @@ -138,8 +138,6 @@ public void ConfigureServices(IServiceCollection services) services.AddMyTelemetry(config); services.AddMyTemplates(); services.AddMyTopics(); - services.AddMyUserEvents(config); - services.AddMyUserNotifications(config); services.AddMyUsers(); services.AddMyUtils(); services.AddMyWebChannel(); From 1196e5f4e142829b97adee1f40a12017804014ce Mon Sep 17 00:00:00 2001 From: Sebastian Date: Mon, 1 Apr 2024 22:46:02 +0200 Subject: [PATCH 04/10] Fix validation problems. --- backend/src/Notifo.Domain/Liquid/LiquidApp.cs | 9 +-- .../src/Notifo.Domain/Liquid/LiquidContext.cs | 2 +- .../Liquid/LiquidNotification.cs | 30 ++++++-- .../Liquid/LiquidNotificationBase.cs | 18 +++++ .../Liquid/LiquidPropertiesProvider.cs | 36 ++++++++++ .../Notifo.Domain/Liquid/LiquidProperty.cs | 69 +++++++++++++++++++ .../src/Notifo.Domain/Liquid/LiquidUser.cs | 15 ++-- frontend/src/app/pages/app/AppPage.tsx | 2 +- frontend/src/app/pages/app/AppSettings.tsx | 2 +- .../pages/email-templates/EmailTemplate.tsx | 2 +- .../email-templates/EmailTemplateName.tsx | 14 ++-- .../MessagingTemplatePage.tsx | 17 ++--- .../src/app/pages/publish/PublishDialog.tsx | 17 +++-- .../pages/sms-templates/SmsTemplatePage.tsx | 18 ++--- .../pages/system-users/SystemUserDialog.tsx | 10 ++- .../src/app/pages/templates/TemplateForm.tsx | 8 +-- frontend/src/app/pages/topics/TopicDialog.tsx | 12 ++-- .../src/app/pages/user/SubscriptionDialog.tsx | 8 +-- frontend/src/app/pages/users/UserDialog.tsx | 8 +-- frontend/src/app/shared/components/Forms.tsx | 23 +++---- 20 files changed, 237 insertions(+), 83 deletions(-) create mode 100644 backend/src/Notifo.Domain/Liquid/LiquidPropertiesProvider.cs create mode 100644 backend/src/Notifo.Domain/Liquid/LiquidProperty.cs diff --git a/backend/src/Notifo.Domain/Liquid/LiquidApp.cs b/backend/src/Notifo.Domain/Liquid/LiquidApp.cs index 02218d53..cbaf726e 100644 --- a/backend/src/Notifo.Domain/Liquid/LiquidApp.cs +++ b/backend/src/Notifo.Domain/Liquid/LiquidApp.cs @@ -10,14 +10,15 @@ namespace Notifo.Domain.Liquid; -public sealed class LiquidApp +public sealed class LiquidApp(App app) { - private readonly App app; + private readonly App app = app; public string? Name => app.Name.OrNull(); - public LiquidApp(App app) + public static void Describe(LiquidProperties properties) { - this.app = app; + properties.AddString("name", + "The name of the app."); } } diff --git a/backend/src/Notifo.Domain/Liquid/LiquidContext.cs b/backend/src/Notifo.Domain/Liquid/LiquidContext.cs index cdf49d96..cfd31c4b 100644 --- a/backend/src/Notifo.Domain/Liquid/LiquidContext.cs +++ b/backend/src/Notifo.Domain/Liquid/LiquidContext.cs @@ -63,9 +63,9 @@ public static LiquidContext Create(IEnumerable<(BaseUserNotification Notificatio } context.SetValue("app", new LiquidApp(app)); + context.SetValue("user", new LiquidUser(user)); context.SetValue("notification", notifications[0]); context.SetValue("notifications", notifications); - context.SetValue("user", new LiquidUser(user)); return context; } diff --git a/backend/src/Notifo.Domain/Liquid/LiquidNotification.cs b/backend/src/Notifo.Domain/Liquid/LiquidNotification.cs index a8b251a2..d4c4e13f 100644 --- a/backend/src/Notifo.Domain/Liquid/LiquidNotification.cs +++ b/backend/src/Notifo.Domain/Liquid/LiquidNotification.cs @@ -24,11 +24,6 @@ public sealed class LiquidNotification : LiquidNotificationBase private string? trackSeenUrl; private LiquidChildNotification[]? children; - public string? ConfirmText - { - get => notification.Formatting.ConfirmText.OrNull(); - } - public string? TrackSeenUrl { get => trackSeenUrl ??= notification.ComputeTrackSeenUrl(channel, configurationId); @@ -39,6 +34,11 @@ public string? TrackDeliveredUrl get => trackDeliveredUrl ??= notification.ComputeTrackDeliveredUrl(channel, configurationId); } + public string? ConfirmText + { + get => notification.Formatting.ConfirmText.OrNull(); + } + public string? ConfirmUrl { get => confirmUrl ??= notification.ComputeConfirmUrl(channel, configurationId); @@ -72,4 +72,24 @@ public LiquidNotification( this.imageFormatter = imageFormatter; this.configurationId = configurationId; } + + public static void Describe(LiquidProperties properties) + { + DescribeBase(properties); + + properties.AddString("trackSeenUrl", + "The tracking URL to mark the notification as seen."); + + properties.AddString("trackDeliveredUrl", + "The tracking URL to mark the notification as delivered."); + + properties.AddString("confirmUrl", + "The tracking URL to mark the notification as confirmed."); + + properties.AddString("confirmText", + "The text for confirmation buttons."); + + properties.AddArray("children", + "The child notifications if the notifications have been grouped together."); + } } diff --git a/backend/src/Notifo.Domain/Liquid/LiquidNotificationBase.cs b/backend/src/Notifo.Domain/Liquid/LiquidNotificationBase.cs index dd0bdaba..7e3e2ef6 100644 --- a/backend/src/Notifo.Domain/Liquid/LiquidNotificationBase.cs +++ b/backend/src/Notifo.Domain/Liquid/LiquidNotificationBase.cs @@ -48,4 +48,22 @@ protected LiquidNotificationBase( this.imagePresetLarge = imagePresetLarge; this.formatting = formatting; } + + protected static void DescribeBase(LiquidProperties properties) + { + properties.AddString("subject", + "The notification subject."); + + properties.AddString("body", + "The notification body. Can be null."); + + properties.AddString("linkUrl", + "The link URL. Can be null."); + + properties.AddString("imageSmall", + "The URL to the small image. Optimized for the current use case (e.g. emails). Can be null."); + + properties.AddString("imageLarge", + "The URL to the large image. Optimized for the current use case (e.g. emails). Can be null."); + } } diff --git a/backend/src/Notifo.Domain/Liquid/LiquidPropertiesProvider.cs b/backend/src/Notifo.Domain/Liquid/LiquidPropertiesProvider.cs new file mode 100644 index 00000000..e8b3cd94 --- /dev/null +++ b/backend/src/Notifo.Domain/Liquid/LiquidPropertiesProvider.cs @@ -0,0 +1,36 @@ +// ========================================================================== +// Notifo.io +// ========================================================================== +// Copyright (c) Sebastian Stehle +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +namespace Notifo.Domain.Liquid; + +public sealed class LiquidPropertiesProvider +{ + public LiquidProperties GetProperties() + { + var properties = new LiquidProperties(); + + properties.AddObject("app", () => + { + LiquidApp.Describe(properties); + }, "The current app."); + + properties.AddObject("user", () => + { + LiquidUser.Describe(properties); + }, "The current user."); + + properties.AddObject("notification", () => + { + LiquidNotification.Describe(properties); + }, "The first and usually single notifications. For emails multiple notifications can be grouped in one template."); + + properties.AddArray("notifications", + "The list of notifications. Usually it is only one, but for emails multiple notifications can be grouped in one template."); + + return properties; + } +} diff --git a/backend/src/Notifo.Domain/Liquid/LiquidProperty.cs b/backend/src/Notifo.Domain/Liquid/LiquidProperty.cs new file mode 100644 index 00000000..c9728579 --- /dev/null +++ b/backend/src/Notifo.Domain/Liquid/LiquidProperty.cs @@ -0,0 +1,69 @@ +// ========================================================================== +// Notifo.io +// ========================================================================== +// Copyright (c) Sebastian Stehle +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +#pragma warning disable SA1313 // Parameter names should begin with lower-case letter +#pragma warning disable MA0048 // File name must match type name + +namespace Notifo.Domain.Liquid; + +public sealed class LiquidProperties : List +{ + private readonly Stack pathStack = new Stack(); + + public void AddArray(string path, string? description = null) + { + Add(new LiquidProperty(FullPath(path), LiquidPropertyType.Array, description)); + } + + public void AddString(string path, string? description = null) + { + Add(new LiquidProperty(FullPath(path), LiquidPropertyType.String, description)); + } + + public void AddNumber(string path, string? description = null) + { + Add(new LiquidProperty(FullPath(path), LiquidPropertyType.Number, description)); + } + + public void AddBoolean(string path, string? description = null) + { + Add(new LiquidProperty(FullPath(path), LiquidPropertyType.Boolean, description)); + } + + public void AddObject(string path, Action inner, string? description = null) + { + pathStack.Push(path); + + Add(new LiquidProperty(FullPath(path), LiquidPropertyType.Object, description)); + inner(); + + pathStack.Pop(); + } + + private string FullPath(string path) + { + if (pathStack.Count > 0) + { + path = $"{string.Join('.', pathStack)}.{path}"; + } + + return path; + } +} + +public sealed record LiquidProperty(string Path, LiquidPropertyType Type, string? Description) +{ +} + +public enum LiquidPropertyType +{ + Array, + String, + Number, + Boolean, + Object +} diff --git a/backend/src/Notifo.Domain/Liquid/LiquidUser.cs b/backend/src/Notifo.Domain/Liquid/LiquidUser.cs index 250b1db0..c23eeeee 100644 --- a/backend/src/Notifo.Domain/Liquid/LiquidUser.cs +++ b/backend/src/Notifo.Domain/Liquid/LiquidUser.cs @@ -10,9 +10,9 @@ namespace Notifo.Domain.Liquid; -public sealed class LiquidUser +public sealed class LiquidUser(User user) { - private readonly User user; + private readonly User user = user; public string? FullName => user.FullName.OrNull(); @@ -20,8 +20,15 @@ public sealed class LiquidUser public string? PhoneNumber => user.PhoneNumber.OrNull(); - public LiquidUser(User user) + public static void Describe(LiquidProperties properties) { - this.user = user; + properties.AddString("fullName", + "The full name of the user."); + + properties.AddString("emailAddress", + "The email address of the user."); + + properties.AddString("phoneNumber", + "The phone number of the user."); } } diff --git a/frontend/src/app/pages/app/AppPage.tsx b/frontend/src/app/pages/app/AppPage.tsx index b6fa9f61..839807e4 100644 --- a/frontend/src/app/pages/app/AppPage.tsx +++ b/frontend/src/app/pages/app/AppPage.tsx @@ -207,7 +207,7 @@ export const AppPage = () => { } /> - } /> { dispatch(upsertApp({ appId: appDetails.id, params })); }); - const form = useForm({ resolver: yupResolver(FormSchema), defaultValues: appDetails, mode: 'onChange' }); + const form = useForm({ resolver: yupResolver(FormSchema), mode: 'onChange' }); React.useEffect(() => { form.reset(appDetails); diff --git a/frontend/src/app/pages/email-templates/EmailTemplate.tsx b/frontend/src/app/pages/email-templates/EmailTemplate.tsx index a7338dc3..86cd70d7 100644 --- a/frontend/src/app/pages/email-templates/EmailTemplate.tsx +++ b/frontend/src/app/pages/email-templates/EmailTemplate.tsx @@ -103,7 +103,7 @@ export const EmailTemplate = (props: EmailTemplateProps) => { dispatch(updateEmailTemplateLanguage({ appId, id, language, template: params })); }); - const form = useForm({ resolver: yupResolver(FormSchema), defaultValues: template, mode: 'onChange' }); + const form = useForm({ resolver: yupResolver(FormSchema), mode: 'onChange' }); React.useEffect(() => { form.reset(template); diff --git a/frontend/src/app/pages/email-templates/EmailTemplateName.tsx b/frontend/src/app/pages/email-templates/EmailTemplateName.tsx index e82565ae..62692e90 100644 --- a/frontend/src/app/pages/email-templates/EmailTemplateName.tsx +++ b/frontend/src/app/pages/email-templates/EmailTemplateName.tsx @@ -25,35 +25,35 @@ export const EmailTemplateName = (props: EmailTemplateNameProps) => { const { appId, template } = props; const dispatch = useDispatch(); - const [name, setName] = React.useState(); + const [name, setName] = React.useState<{ text: string; stale: boolean }>(); React.useEffect(() => { - setName(template?.name || ''); + setName({ text: template?.name || '', stale: false }); }, [template]); const doSave = useEventCallback((event: React.FormEvent) => { if (template?.id) { - dispatch(updateEmailTemplate({ appId, id: template.id, update: { name } })); + dispatch(updateEmailTemplate({ appId, id: template.id, update: { name: name?.text } })); } event.preventDefault(); }); const doCancel = useEventCallback(() => { - setName(template?.name || ''); + setName({ text: template?.name || '', stale: false }); }); const doSetName = useEventCallback((event: React.ChangeEvent) => { - setName(event.target.value); + setName({ text: event.target.value, stale: true }); }); return (
- + - {template && name !== template?.name && + {(template && name?.text !== template?.name && name?.stale) && <>
); +}; + +const AppEmailAddress = () => { + const { watch } = useFormContext(); + const domain = watch('domain'); + + const email = React.useMemo(() => { + const actualDomain = domain || 'empty.com'; + + return `name@${actualDomain}`; + }, [domain]); + + return ( + +
+ {texts.auth.emailLabel}: {email} +
+
+ ); +}; + +const AuthTestButton = () => { + const { watch } = useFormContext(); + const formValues = watch(); + + const url = React.useMemo(() => { + const q = new URLSearchParams({ + domain: formValues.domain, + displayName: formValues.displayName, + clientId: formValues.clientId, + clientSecret: formValues.clientSecret, + authority: formValues.authority, + }); + + const url = combineUrl(getApiUrl(), `/account/logintest?${q.toString()}`); + + return url; + }, [formValues]); + + return ( + + {texts.auth.testLogin} + + ); }; \ No newline at end of file diff --git a/frontend/src/app/pages/app/AppSettings.tsx b/frontend/src/app/pages/app/AppSettings.tsx index d6be51cb..fd59e7bc 100644 --- a/frontend/src/app/pages/app/AppSettings.tsx +++ b/frontend/src/app/pages/app/AppSettings.tsx @@ -84,7 +84,7 @@ export const AppSettings = (props: AppSettingsProps) => {
-
diff --git a/frontend/src/app/service/service.ts b/frontend/src/app/service/service.ts index e60de631..71a55d5c 100644 --- a/frontend/src/app/service/service.ts +++ b/frontend/src/app/service/service.ts @@ -5901,7 +5901,7 @@ export class AppsClient { * @param appId The ID of the app. * @return App auth settings returned. */ - getAuthScheme(appId: string, signal?: AbortSignal): Promise { + getAuthScheme(appId: string, signal?: AbortSignal): Promise { let url_ = this.baseUrl + "/api/apps/{appId}/auth"; if (appId === undefined || appId === null) throw new Error("The parameter 'appId' must be defined."); @@ -5921,13 +5921,13 @@ export class AppsClient { }); } - protected processGetAuthScheme(response: Response): Promise { + protected processGetAuthScheme(response: Response): Promise { const status = response.status; let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; if (status === 200) { return response.text().then((_responseText) => { let result200: any = null; - result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as AuthSchemeResponseDto; + result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as AuthSchemeValueDto; return result200; }); } else if (status === 404) { @@ -5945,7 +5945,7 @@ export class AppsClient { return throwException("An unexpected server error occurred.", status, _responseText, _headers); }); } - return Promise.resolve(null as any); + return Promise.resolve(null as any); } /** @@ -5954,7 +5954,7 @@ export class AppsClient { * @param request The request object. * @return App auth settings returned. */ - upsertAuthScheme(appId: string, request: AuthSchemeDto, signal?: AbortSignal): Promise { + upsertAuthScheme(appId: string, request: AuthSchemeValueDto, signal?: AbortSignal): Promise { let url_ = this.baseUrl + "/api/apps/{appId}/auth"; if (appId === undefined || appId === null) throw new Error("The parameter 'appId' must be defined."); @@ -5978,13 +5978,13 @@ export class AppsClient { }); } - protected processUpsertAuthScheme(response: Response): Promise { + protected processUpsertAuthScheme(response: Response): Promise { const status = response.status; let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; if (status === 200) { return response.text().then((_responseText) => { let result200: any = null; - result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as AuthSchemeResponseDto; + result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as AuthSchemeValueDto; return result200; }); } else if (status === 404) { @@ -6008,61 +6008,7 @@ export class AppsClient { return throwException("An unexpected server error occurred.", status, _responseText, _headers); }); } - return Promise.resolve(null as any); - } - - /** - * Deletes the auth settings of the app. - * @param appId The ID of the app. - */ - deleteAuthScheme(appId: string, signal?: AbortSignal): Promise { - let url_ = this.baseUrl + "/api/apps/{appId}/auth"; - if (appId === undefined || appId === null) - throw new Error("The parameter 'appId' must be defined."); - url_ = url_.replace("{appId}", encodeURIComponent("" + appId)); - url_ = url_.replace(/[?&]$/, ""); - - let options_: RequestInit = { - method: "DELETE", - signal, - headers: { - } - }; - - return this.http.fetch(url_, options_).then((_response: Response) => { - return this.processDeleteAuthScheme(_response); - }); - } - - protected processDeleteAuthScheme(response: Response): Promise { - const status = response.status; - let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; - if (status === 204) { - return response.text().then((_responseText) => { - return; - }); - } else if (status === 404) { - return response.text().then((_responseText) => { - return throwException("App not found.", status, _responseText, _headers); - }); - } else if (status === 400) { - return response.text().then((_responseText) => { - let result400: any = null; - result400 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as ErrorDto; - return throwException("Validation error.", status, _responseText, _headers, result400); - }); - } else if (status === 500) { - return response.text().then((_responseText) => { - let result500: any = null; - result500 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as ErrorDto; - return throwException("Operation failed.", status, _responseText, _headers, result500); - }); - } else if (status !== 200 && status !== 204) { - return response.text().then((_responseText) => { - return throwException("An unexpected server error occurred.", status, _responseText, _headers); - }); - } - return Promise.resolve(null as any); + return Promise.resolve(null as any); } /** @@ -7370,14 +7316,14 @@ export interface AppContributorDto { role: string; } -export interface AuthSchemeResponseDto { +export interface AuthSchemeValueDto { /** The auth scheme if configured. */ scheme?: AuthSchemeDto | undefined; } export interface AuthSchemeDto { /** The domain name of your user accounts. */ - domain?: string; + domain: string; /** The display name for buttons. */ displayName: string; /** The client ID. */ diff --git a/frontend/src/app/state/apps/actions.ts b/frontend/src/app/state/apps/actions.ts index 464be445..bd8630ed 100644 --- a/frontend/src/app/state/apps/actions.ts +++ b/frontend/src/app/state/apps/actions.ts @@ -80,7 +80,7 @@ export const removeContributor = createMutation('updatingContributors export const upsertAuth = createMutation('updatingAuth').with({ name: 'apps/auth/upsert', mutateFn: (arg: { appId: string; params: AuthSchemeDto }) => { - return Clients.Apps.upsertAuthScheme(arg.appId, arg.params); + return Clients.Apps.upsertAuthScheme(arg.appId, { scheme: arg.params }); }, updateFn(state, action) { state.auth = action.payload; @@ -90,7 +90,7 @@ export const upsertAuth = createMutation('updatingAuth').with({ export const removeAuth = createMutation('updatingAuth').with({ name: 'apps/auth/remove', mutateFn: (arg: { appId: string }) =>{ - return Clients.Apps.deleteAuthScheme(arg.appId); + return Clients.Apps.upsertAuthScheme(arg.appId, { scheme: undefined }); }, updateFn(state) { state.auth = undefined; diff --git a/frontend/src/app/style/_common.scss b/frontend/src/app/style/_common.scss index 75fce699..cd8ee5f1 100644 --- a/frontend/src/app/style/_common.scss +++ b/frontend/src/app/style/_common.scss @@ -1163,18 +1163,26 @@ em-emoji-picker { } } +.text-icon { + font-size: 1.25rem; +} + .text-sm { font-size: $font-size-sm; } -.text-icon { - font-size: 1.25rem; +.text-xs { + font-size: $font-size-xs; } .text-lg { font-size: 1.25rem; } +.text-xxl { + font-size: 3rem; +} + .truncate { @include truncate; } diff --git a/frontend/src/app/style/_vars.scss b/frontend/src/app/style/_vars.scss index 92366197..368c5b96 100644 --- a/frontend/src/app/style/_vars.scss +++ b/frontend/src/app/style/_vars.scss @@ -15,6 +15,9 @@ $color-input: #cad1d7; $color-table: #dee2e6; $font-size-sm: .875rem; +$font-size-xs: .8rem; + +$small-font-size: $font-size-xs; $input-color: darken($color-text, 10%); diff --git a/frontend/src/app/texts/en.ts b/frontend/src/app/texts/en.ts index 1e56724c..57f6d443 100644 --- a/frontend/src/app/texts/en.ts +++ b/frontend/src/app/texts/en.ts @@ -33,15 +33,19 @@ export const EN = { }, auth: { authority: 'Authority', + authorityHints: 'The URL to your authority server.', clientId: 'Client ID', clientSecret: 'Client Secret', description: 'Define the configuration to your custom OIDC server.', displayName: 'Display Name', domain: 'Domain', + domainHints: 'The domain is used to identity your users. When they enter their email address and the domain matches to your settings they will redirected to your authentication server.', + emailLabel: 'Email Format', enable: 'Use custom OIDC server', redirectUrl: 'Redirect URL', redirectUrlHint: 'You have to allow this URL in your authentication server.', signoutRedirectUrl: 'Signout Redirect URL', + testLogin: 'Test Login', title: 'Custom Auth', }, code: 'en', diff --git a/tools/sdk/Notifo.SDK/Generated.cs b/tools/sdk/Notifo.SDK/Generated.cs index 49f6ba7c..9c778de3 100644 --- a/tools/sdk/Notifo.SDK/Generated.cs +++ b/tools/sdk/Notifo.SDK/Generated.cs @@ -13211,7 +13211,7 @@ public partial interface IAppsClient /// The ID of the app. /// App auth settings returned. /// A server side error occurred. - System.Threading.Tasks.Task GetAuthSchemeAsync(string appId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)); + System.Threading.Tasks.Task GetAuthSchemeAsync(string appId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)); /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// @@ -13221,15 +13221,7 @@ public partial interface IAppsClient /// The request object. /// App auth settings returned. /// A server side error occurred. - System.Threading.Tasks.Task UpsertAuthSchemeAsync(string appId, AuthSchemeDto request, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)); - - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. - /// - /// Deletes the auth settings of the app. - /// - /// The ID of the app. - /// A server side error occurred. - System.Threading.Tasks.Task DeleteAuthSchemeAsync(string appId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)); + System.Threading.Tasks.Task UpsertAuthSchemeAsync(string appId, AuthSchemeValueDto request, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)); /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// @@ -13724,7 +13716,7 @@ private static Newtonsoft.Json.JsonSerializerSettings CreateSerializerSettings() /// The ID of the app. /// App auth settings returned. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task GetAuthSchemeAsync(string appId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) + public virtual async System.Threading.Tasks.Task GetAuthSchemeAsync(string appId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { if (appId == null) throw new System.ArgumentNullException("appId"); @@ -13772,7 +13764,7 @@ private static Newtonsoft.Json.JsonSerializerSettings CreateSerializerSettings() var status_ = (int)response_.StatusCode; if (status_ == 200 || status_ == 201) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new NotifoException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -13822,7 +13814,7 @@ private static Newtonsoft.Json.JsonSerializerSettings CreateSerializerSettings() /// The request object. /// App auth settings returned. /// A server side error occurred. - public virtual async System.Threading.Tasks.Task UpsertAuthSchemeAsync(string appId, AuthSchemeDto request, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) + public virtual async System.Threading.Tasks.Task UpsertAuthSchemeAsync(string appId, AuthSchemeValueDto request, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { if (appId == null) throw new System.ArgumentNullException("appId"); @@ -13877,7 +13869,7 @@ private static Newtonsoft.Json.JsonSerializerSettings CreateSerializerSettings() var status_ = (int)response_.StatusCode; if (status_ == 200 || status_ == 201) { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); if (objectResponse_.Object == null) { throw new NotifoException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); @@ -13929,106 +13921,6 @@ private static Newtonsoft.Json.JsonSerializerSettings CreateSerializerSettings() } } - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. - /// - /// Deletes the auth settings of the app. - /// - /// The ID of the app. - /// A server side error occurred. - public virtual async System.Threading.Tasks.Task DeleteAuthSchemeAsync(string appId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) - { - if (appId == null) - throw new System.ArgumentNullException("appId"); - - var client_ = _httpClientProvider.Get(); - #pragma warning disable CS0219 // Variable is assigned but its value is never used - var disposeClient_ = false; - #pragma warning restore CS0219 // Variable is assigned but its value is never used - try - { - using (var request_ = new System.Net.Http.HttpRequestMessage()) - { - request_.Method = new System.Net.Http.HttpMethod("DELETE"); - - var urlBuilder_ = new System.Text.StringBuilder(); - - // Operation Path: "api/apps/{appId}/auth" - urlBuilder_.Append("api/apps/"); - urlBuilder_.Append(System.Uri.EscapeDataString(ConvertToString(appId, System.Globalization.CultureInfo.InvariantCulture))); - urlBuilder_.Append("/auth"); - - PrepareRequest(client_, request_, urlBuilder_); - - var url_ = urlBuilder_.ToString(); - request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); - - PrepareRequest(client_, request_, url_); - - var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); - var disposeResponse_ = true; - try - { - var headers_ = new System.Collections.Generic.Dictionary>(); - foreach (var item_ in response_.Headers) - headers_[item_.Key] = item_.Value; - if (response_.Content != null && response_.Content.Headers != null) - { - foreach (var item_ in response_.Content.Headers) - headers_[item_.Key] = item_.Value; - } - - ProcessResponse(client_, response_); - - var status_ = (int)response_.StatusCode; - if (status_ == 204) - { - return; - } - else - if (status_ == 404) - { - string responseText_ = ( response_.Content == null ) ? string.Empty : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new NotifoException("App not found.", status_, responseText_, headers_, null); - } - else - if (status_ == 400) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new NotifoException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); - } - throw new NotifoException("Validation error.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); - } - else - if (status_ == 500) - { - var objectResponse_ = await ReadObjectResponseAsync(response_, headers_, cancellationToken).ConfigureAwait(false); - if (objectResponse_.Object == null) - { - throw new NotifoException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); - } - throw new NotifoException("Operation failed.", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); - } - else - { - var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); - throw new NotifoException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); - } - } - finally - { - if (disposeResponse_) - response_.Dispose(); - } - } - } - finally - { - _httpClientProvider.Return(client_); - } - } - /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. /// /// Add an app contributor. @@ -17622,7 +17514,7 @@ public partial class AppContributorDto } [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "14.0.3.0 (NJsonSchema v11.0.0.0 (Newtonsoft.Json v13.0.0.0))")] - public partial class AuthSchemeResponseDto + public partial class AuthSchemeValueDto { /// /// The auth scheme if configured. @@ -17639,6 +17531,7 @@ public partial class AuthSchemeDto /// The domain name of your user accounts. /// [Newtonsoft.Json.JsonProperty("domain", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [System.ComponentModel.DataAnnotations.Required] public string Domain { get; set; } ///