├── .config └── dotnet-tools.json ├── .github └── workflows │ ├── dotnet-electron.yml │ └── dotnet-maui.yml ├── .gitignore ├── LICENSE.md ├── README.md ├── global.json ├── nuget.config └── src ├── Api └── Host │ ├── ConnectionManagement.cs │ ├── Host.csproj │ ├── Mutations │ ├── MessagingMutationExtensions.cs │ └── QueueMutationExtensions.cs │ ├── Program.cs │ ├── Queries │ ├── MessageQueryExtensions.cs │ ├── QueueQueryExtensions.cs │ ├── SubscriptionQueryExtensions.cs │ └── TopicQueryExtensions.cs │ └── appsettings.json ├── Core ├── Common │ ├── Common.csproj │ ├── ErrorCodes.cs │ └── StringExtensions.cs ├── Management.Contracts │ ├── IConnectionManagement.cs │ ├── Management.Contracts.csproj │ └── ServiceBusConnection.cs ├── Management │ ├── ConnectionManagement.cs │ ├── IManagementStorage.cs │ ├── Management.csproj │ ├── ServiceBusConnectionDoesntExist.cs │ ├── ServiceBusConnectionStringHelper.cs │ └── ServiceCollectionExtensions.cs ├── NotificationHub │ └── NotificationHub.csproj ├── Relay │ └── Relay.csproj ├── ServiceBus.Contracts │ ├── Excepions │ │ ├── MessageTooBigException.cs │ │ ├── ServiceBusOperationException.cs │ │ └── ValidationException.cs │ ├── IMessageService.cs │ ├── IQueueService.cs │ ├── IRuleService.cs │ ├── ISubscriptionService.cs │ ├── ITopicService.cs │ ├── ServiceBus.Contracts.csproj │ └── Types │ │ ├── AccessRights.cs │ │ ├── ApplicationProperty.cs │ │ ├── CreateQueueOptions.cs │ │ ├── CreateSubscriptionOptions.cs │ │ ├── CreateTopicOptions.cs │ │ ├── LockDuration.cs │ │ ├── Message.cs │ │ ├── MessageState.cs │ │ ├── MessageSystemProperties.cs │ │ ├── OperationResult.cs │ │ ├── PurgeResult.cs │ │ ├── QueueDetails.cs │ │ ├── QueueInfo.cs │ │ ├── QueueProperties.cs │ │ ├── QueueSettings.cs │ │ ├── QueueTimeSettings.cs │ │ ├── ReceiveMode.cs │ │ ├── ReceiveType.cs │ │ ├── ResendResult.cs │ │ ├── Result.cs │ │ ├── Rule.cs │ │ ├── RuleType.cs │ │ ├── SendMessage.cs │ │ ├── ServiceBusEntityStatus.cs │ │ ├── SharedAccessAuthorizationRule.cs │ │ ├── SubQueue.cs │ │ ├── SubscriptionDetails.cs │ │ ├── SubscriptionInfo.cs │ │ ├── SubscriptionProperties.cs │ │ ├── SubscriptionSettings.cs │ │ ├── SubscriptionTimeSettings.cs │ │ ├── TopicDetails.cs │ │ ├── TopicInfo.cs │ │ ├── TopicProperties.cs │ │ ├── TopicSettings.cs │ │ ├── TopicStructure.cs │ │ ├── TopicTimeSettings.cs │ │ ├── UpdateQueueOptions.cs │ │ ├── UpdateSubscriptionOptions.cs │ │ ├── UpdateTopicOptions.cs │ │ └── UploadFileType.cs └── ServiceBus │ ├── Extensions │ └── ApplicationPropertyTypeExtensions.cs │ ├── Mappings │ ├── MessageMappings.cs │ ├── QueueMappings.cs │ ├── SubscriptionMappings.cs │ └── TopicMappings.cs │ ├── MessageService.cs │ ├── QueueService.cs │ ├── RuleService.cs │ ├── ServiceBus.csproj │ ├── ServiceCollectionExtensions.cs │ ├── SubscriptionService.cs │ └── TopicService.cs ├── CrossBusExplorer.sln └── Ui ├── Host.Ui ├── App.xaml ├── App.xaml.cs ├── Host.Ui.csproj ├── Main.razor ├── MainPage.xaml ├── MainPage.xaml.cs ├── ManagementStorage.cs ├── Maui.App.sln ├── MauiProgram.cs ├── Platforms │ ├── Android │ │ ├── AndroidManifest.xml │ │ ├── MainActivity.cs │ │ ├── MainApplication.cs │ │ └── Resources │ │ │ └── values │ │ │ └── colors.xml │ ├── MacCatalyst │ │ ├── AppDelegate.cs │ │ ├── Info.plist │ │ └── Program.cs │ ├── Tizen │ │ ├── Main.cs │ │ └── tizen-manifest.xml │ ├── Windows │ │ ├── App.xaml │ │ ├── App.xaml.cs │ │ ├── Package.appxmanifest │ │ └── app.manifest │ └── iOS │ │ ├── AppDelegate.cs │ │ ├── Info.plist │ │ └── Program.cs ├── Resources │ ├── AppIcon │ │ ├── appicon.svg │ │ └── appiconfg.svg │ ├── Fonts │ │ └── OpenSans-Regular.ttf │ ├── Images │ │ └── dotnet_bot.svg │ ├── Raw │ │ └── AboutAssets.txt │ └── Splash │ │ └── splash.svg ├── UserSettingsService.cs ├── _Imports.razor └── wwwroot │ ├── css │ └── custom.css │ ├── favicon.ico │ └── index.html ├── Website.Host ├── App.razor ├── DefaultSettingsService.cs ├── ManagementStorage.cs ├── Pages │ ├── Error.cshtml │ ├── Error.cshtml.cs │ ├── _Host.cshtml │ └── _Layout.cshtml ├── Program.cs ├── Website.Host.csproj ├── _Imports.razor ├── appsettings.Development.json ├── appsettings.json ├── build │ ├── entitlements.mac.inherit.plist │ ├── icon.png │ └── icon512x512.png ├── electron.manifest.json └── wwwroot │ └── favicon.ico └── Website ├── App.razor ├── Exceptions ├── ConverterException.cs └── FolderSettingsForConnectionNotFoundException.cs ├── Extensions ├── DateTimeExtensions.cs ├── IListExtensions.cs ├── INotifyPropertyChangedExtensions.cs ├── StringExtensions.cs └── TimeSpanExtensions.cs ├── FluentValidator.cs ├── ISettingsService.cs ├── Jobs ├── DeleteMessageJob.cs ├── IJob.cs ├── JobCompletedEventHandler.cs ├── JobStatus.cs ├── JobsHelper.cs ├── PurgeMessagesJob.cs └── ResendMessagesJob.cs ├── Mappings ├── MessageMappings.cs ├── QueueMappings.cs ├── SubscriptionMappings.cs └── TopicMappings.cs ├── Models ├── ConnectionFolder.cs ├── ConnectionMenuItem.cs ├── CurrentMessagesEntity.cs ├── DirectionChange.cs ├── FolderSettings.cs ├── KeyValueTypePair.cs ├── MessageDetailsModel.cs ├── MessagesUploadDialogResult.cs ├── OperationType.cs ├── QueueFormModel.cs ├── ReceiveMessagesForm.cs ├── RequeueMessage.cs ├── RuleFormModel.cs ├── SaveConnectionForm.cs ├── ServiceBusConnectionFolder.cs ├── ServiceBusConnectionSettings.cs ├── SubscriptionFormModel.cs ├── TopicFormModel.cs ├── TopicSubscriptionsModel.cs ├── UserSettings.cs └── Validators │ ├── ReceiveMessageFormValidator.cs │ └── RuleFormValidator.cs ├── Pages ├── Connections.razor ├── Messages.razor ├── Monitoring.razor ├── Queue.razor ├── Queues.razor ├── Rules.razor ├── ServiceBus.razor ├── ServiceBus.razor.cs ├── Subscription.razor ├── Topic.razor └── Topics.razor ├── ServiceCollectionExtensions.cs ├── Shared ├── ConfirmDialog.razor ├── Connections │ └── FolderDialog.razor ├── Jobs.razor ├── MainLayout.razor ├── MenuItem.razor ├── Messages │ ├── MessageDetailsDialog.razor │ ├── MessagesUploadDialog.razor │ └── PurgeMessagesDialog.razor ├── Queue │ └── CloneDialog.razor ├── ServiceBusNavMenu.razor ├── TopicNestedMenuItem.razor ├── TopicSubNestedMenuItem.razor └── ViewDialog.razor ├── Validation └── ConnectionStringValidationAttribute.cs ├── ViewModels ├── ConnectionOperationEventHandler.cs ├── ConnectionsViewModel.cs ├── IConnectionsViewModel.cs ├── IJobsViewModel.cs ├── IMessagesViewModel.cs ├── INavigationViewModel.cs ├── IQueueViewModel.cs ├── IRulesViewModel.cs ├── ISubscriptionViewModel.cs ├── ITopicViewModel.cs ├── JobsViewModel.cs ├── MessagesViewModel.cs ├── NavigationViewModel.cs ├── QueueOperationEventHandler.cs ├── QueueViewModel.cs ├── RulesViewModel.cs ├── SubscriptionOperationEventHandler.cs ├── SubscriptionViewModel.cs ├── TopicAddedEventHandler.cs ├── TopicRemovedEventHandler.cs └── TopicViewModel.cs ├── Website.csproj ├── WellKnown.cs └── _Imports.razor /.config/dotnet-tools.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "isRoot": true, 4 | "tools": { 5 | "electronsharp.cli": { 6 | "version": "24.0.0.37423", 7 | "commands": [ 8 | "electron-sharp" 9 | ] 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Mariusz Matysek 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Cross Bus Explorer 2 | 3 | Cross Bus Explorer is a Cross Platform Service Bus Explorer (Windows, McOS and Linux) 4 | 5 | ## Features 6 | 7 | - Create, List, Edit, Delete, Disable of Queues, Topics, Subscriptions 8 | - Subscription rules management (create, edit, update) 9 | - Purge messages 10 | - Requeue messages 11 | - Send messages 12 | - Resend edited messages 13 | 14 | ![chrome_SbCnkRVg9b](https://user-images.githubusercontent.com/13761704/207661917-7f1ea66f-3878-4e88-a771-def3b5c52088.gif) 15 | 16 | ## Known issues 17 | ### Linux snap installer 18 | 19 | The snap package is not signed, to install it run following command: 20 | snap install cross-bus-explorer-0.2.0.snap --dangerous 21 | ![image](https://user-images.githubusercontent.com/6861396/206653698-f1146dad-7d03-4f72-ae0a-c5d55cc3ee6d.png) 22 | 23 | 24 | ### Mac Os 25 | 26 | The app is not signed so it's blocked by default. Please go to Privacy and Security and click 'Open anyway' on the option in 'Security' section. Also above the 'Allow applications downloaded from' option need to be set to: 'App Store and identified developers'. 27 | ![image](https://user-images.githubusercontent.com/6861396/206653511-2584d668-f3fa-47f2-acd4-6242788b9996.png) 28 | -------------------------------------------------------------------------------- /global.json: -------------------------------------------------------------------------------- 1 | { 2 | "sdk": { 3 | "version": "8.0.203" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /nuget.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/Api/Host/ConnectionManagement.cs: -------------------------------------------------------------------------------- 1 | using CrossBusExplorer.Management.Contracts; 2 | namespace CrossBusExplorer.Host; 3 | 4 | public class ConnectionManagement : IConnectionManagement 5 | { 6 | public Task> GetAsync(CancellationToken cancellationToken) 7 | { 8 | throw new NotImplementedException(); 9 | } 10 | public Task GetAsync(string name, CancellationToken cancellationToken) 11 | { 12 | throw new NotImplementedException(); 13 | } 14 | public Task SaveAsync(string name, string connectionString, string folder, 15 | CancellationToken cancellationToken) 16 | { 17 | throw new NotImplementedException(); 18 | } 19 | public Task DeleteAsync(string name, CancellationToken cancellationToken) 20 | { 21 | throw new NotImplementedException(); 22 | } 23 | } -------------------------------------------------------------------------------- /src/Api/Host/Host.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | CrossBusExplorer.Host 8 | CrossBusExplorer.Host 9 | preview 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/Api/Host/Mutations/MessagingMutationExtensions.cs: -------------------------------------------------------------------------------- 1 | using Azure.Messaging.ServiceBus; 2 | using CrossBusExplorer.ServiceBus.Contracts; 3 | using CrossBusExplorer.ServiceBus.Contracts.Types; 4 | using SubQueue = CrossBusExplorer.ServiceBus.Contracts.Types.SubQueue; 5 | namespace CrossBusExplorer.Host.Mutations; 6 | 7 | [ExtendObjectType("Mutation")] 8 | public class MessagingMutationExtensions 9 | { 10 | [Error] 11 | [UseMutationConvention(PayloadFieldName = "result")] 12 | public IAsyncEnumerable PurgeAsync( 13 | [Service] IMessageService messageService, 14 | string connectionName, 15 | string queueOrTopicName, 16 | string? subscriptionName, 17 | SubQueue subQueue, 18 | long totalCount, 19 | CancellationToken cancellationToken) 20 | { 21 | return messageService.PurgeAsync( 22 | connectionName, 23 | queueOrTopicName, 24 | subscriptionName, 25 | subQueue, 26 | totalCount, 27 | cancellationToken); 28 | } 29 | 30 | [Error] 31 | [Error] 32 | [UseMutationConvention(PayloadFieldName = "result")] 33 | public async Task SendMessagesAsync( 34 | [Service] IMessageService messageService, 35 | string connectionName, 36 | string queueOrTopicName, 37 | IReadOnlyList messages, 38 | CancellationToken cancellationToken) 39 | { 40 | return await messageService.SendMessagesAsync( 41 | connectionName, 42 | queueOrTopicName, 43 | messages, 44 | cancellationToken); 45 | } 46 | } -------------------------------------------------------------------------------- /src/Api/Host/Mutations/QueueMutationExtensions.cs: -------------------------------------------------------------------------------- 1 | using Azure.Messaging.ServiceBus; 2 | using CrossBusExplorer.ServiceBus.Contracts; 3 | using CrossBusExplorer.ServiceBus.Contracts.Types; 4 | namespace CrossBusExplorer.Host.Mutations; 5 | 6 | [ExtendObjectType("Mutation")] 7 | public class QueueMutationExtensions 8 | { 9 | [UseMutationConvention(PayloadFieldName = "result")] 10 | [Error] 11 | public async Task DeleteQueueAsync( 12 | [Service] IQueueService queueService, 13 | string connectionName, 14 | string name, 15 | CancellationToken cancellationToken) 16 | { 17 | return await queueService.DeleteAsync(connectionName, name, cancellationToken); 18 | } 19 | 20 | [UseMutationConvention(PayloadFieldName = "result")] 21 | [Error] 22 | public async Task> UpdateQueueAsync( 23 | [Service] IQueueService queueService, 24 | string connectionName, 25 | UpdateQueueOptions options, 26 | CancellationToken cancellationToken) 27 | { 28 | return await queueService.UpdateAsync(connectionName, options, cancellationToken); 29 | } 30 | 31 | [UseMutationConvention(PayloadFieldName = "result")] 32 | [Error] 33 | [Error] 34 | public async Task> CreateQueueAsync( 35 | [Service] IQueueService queueService, 36 | string connectionName, 37 | CreateQueueOptions options, 38 | CancellationToken cancellationToken) 39 | { 40 | return await queueService.CreateAsync(connectionName, options, cancellationToken); 41 | } 42 | 43 | [UseMutationConvention(PayloadFieldName = "result")] 44 | [Error] 45 | public async Task> CloneQueueAsync( 46 | [Service] IQueueService queueService, 47 | string connectionName, 48 | string name, 49 | string sourceName, 50 | CancellationToken cancellationToken) 51 | { 52 | return await queueService.CloneAsync(connectionName, name, sourceName, cancellationToken); 53 | } 54 | } -------------------------------------------------------------------------------- /src/Api/Host/Program.cs: -------------------------------------------------------------------------------- 1 | using CrossBusExplorer.Host; 2 | using CrossBusExplorer.Host.Mutations; 3 | using CrossBusExplorer.Host.Queries; 4 | using CrossBusExplorer.Management.Contracts; 5 | using CrossBusExplorer.ServiceBus; 6 | 7 | var builder = WebApplication.CreateBuilder(args); 8 | 9 | builder.Services 10 | .AddSingleton() 11 | .AddServiceBusServices() 12 | .AddGraphQLServer() 13 | .AddQueryType() 14 | .AddMutationType() 15 | .AddTypeExtension() 16 | .AddTypeExtension() 17 | .AddTypeExtension() 18 | .AddTypeExtension() 19 | .AddTypeExtension() 20 | .AddTypeExtension() 21 | .AddMutationConventions(); 22 | 23 | var app = builder.Build(); 24 | 25 | app.MapGet("/", () => "Hello World!"); 26 | app.UseWebSockets(); 27 | app.MapGraphQL(); 28 | 29 | app.Run(); -------------------------------------------------------------------------------- /src/Api/Host/Queries/MessageQueryExtensions.cs: -------------------------------------------------------------------------------- 1 | using CrossBusExplorer.ServiceBus.Contracts; 2 | using CrossBusExplorer.ServiceBus.Contracts.Types; 3 | namespace CrossBusExplorer.Host.Queries; 4 | 5 | [ExtendObjectType("Query")] 6 | public class MessageQueryExtensions 7 | { 8 | public Task> GetMessagesAsync( 9 | [Service] IMessageService messageService, 10 | string connectionName, 11 | string queueOrTopicName, 12 | string? subscriptionName, 13 | SubQueue subQueue, 14 | ReceiveMode mode, 15 | ReceiveType type, 16 | int? messagesCount, 17 | long? fromSequenceNumber, 18 | CancellationToken cancellationToken) 19 | { 20 | return messageService.GetMessagesAsync( 21 | connectionName, 22 | queueOrTopicName, 23 | subscriptionName, 24 | subQueue, 25 | mode, 26 | type, 27 | messagesCount, 28 | fromSequenceNumber, 29 | cancellationToken); 30 | } 31 | } -------------------------------------------------------------------------------- /src/Api/Host/Queries/QueueQueryExtensions.cs: -------------------------------------------------------------------------------- 1 | using CrossBusExplorer.ServiceBus.Contracts; 2 | using CrossBusExplorer.ServiceBus.Contracts.Types; 3 | namespace CrossBusExplorer.Host.Queries; 4 | 5 | [ExtendObjectType("Query")] 6 | public class QueueQueryExtensions 7 | { 8 | public IAsyncEnumerable GetQueuesAsync( 9 | [Service] IQueueService queueService, 10 | string connectionName, 11 | CancellationToken cancellationToken) 12 | { 13 | return queueService.GetAsync( 14 | connectionName, 15 | cancellationToken); 16 | } 17 | 18 | public Task GetQueueAsync( 19 | [Service] IQueueService queueService, 20 | string connectionName, 21 | string name, 22 | CancellationToken cancellationToken) 23 | { 24 | return queueService.GetAsync( 25 | connectionName, 26 | name, 27 | cancellationToken); 28 | } 29 | } -------------------------------------------------------------------------------- /src/Api/Host/Queries/SubscriptionQueryExtensions.cs: -------------------------------------------------------------------------------- 1 | using CrossBusExplorer.ServiceBus.Contracts; 2 | using CrossBusExplorer.ServiceBus.Contracts.Types; 3 | namespace CrossBusExplorer.Host.Queries; 4 | 5 | [ExtendObjectType("Query")] 6 | public class SubscriptionQueryExtensions 7 | { 8 | public IAsyncEnumerable GetSubscriptionsAsync( 9 | [Service] ISubscriptionService subscriptionService, 10 | string connectionName, 11 | string topicName, 12 | CancellationToken cancellationToken) 13 | { 14 | return subscriptionService.GetAsync( 15 | connectionName, 16 | topicName, 17 | cancellationToken); 18 | } 19 | } -------------------------------------------------------------------------------- /src/Api/Host/Queries/TopicQueryExtensions.cs: -------------------------------------------------------------------------------- 1 | using CrossBusExplorer.ServiceBus.Contracts; 2 | using CrossBusExplorer.ServiceBus.Contracts.Types; 3 | namespace CrossBusExplorer.Host.Queries; 4 | 5 | [ExtendObjectType("Query")] 6 | public class TopicQueryExtensions 7 | { 8 | public IAsyncEnumerable GetTopicsAsync( 9 | [Service] ITopicService topicService, 10 | string connectionName, 11 | CancellationToken cancellationToken) 12 | { 13 | return topicService.GetStructureAsync( 14 | connectionName, 15 | cancellationToken); 16 | } 17 | } -------------------------------------------------------------------------------- /src/Api/Host/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*" 9 | } 10 | -------------------------------------------------------------------------------- /src/Core/Common/Common.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | CrossBusExplorer.Common 8 | CrossBusExplorer.Common 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/Core/Common/ErrorCodes.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.ServiceBus; 2 | 3 | public static class ErrorCodes 4 | { 5 | public static string InvalidArgument => "InvalidArgument"; 6 | public static string InvalidOperation => "InvalidOperation"; 7 | } -------------------------------------------------------------------------------- /src/Core/Common/StringExtensions.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.ServiceBus; 2 | 3 | public static class StringExtensions 4 | { 5 | public static string? RemoveUrl(this string? value) 6 | { 7 | if (string.IsNullOrEmpty(value)) 8 | { 9 | return null; 10 | } 11 | 12 | var uri = new Uri(value); 13 | 14 | return uri.LocalPath.Remove(0,1); 15 | } 16 | } -------------------------------------------------------------------------------- /src/Core/Management.Contracts/IConnectionManagement.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.Management.Contracts; 2 | 3 | public interface IConnectionManagement 4 | { 5 | Task> GetAsync(CancellationToken cancellationToken); 6 | Task GetAsync(string name, CancellationToken cancellationToken); 7 | Task SaveAsync( 8 | string name, 9 | string connectionString, 10 | string folder, 11 | CancellationToken cancellationToken); 12 | Task DeleteAsync(string name, CancellationToken cancellationToken); 13 | } -------------------------------------------------------------------------------- /src/Core/Management.Contracts/Management.Contracts.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | CrossBusExplorer.Management.Contracts 8 | CrossBusExplorer.Management.Contracts 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/Core/Management.Contracts/ServiceBusConnection.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.Management.Contracts; 2 | 3 | public class ServiceBusConnection 4 | { 5 | public ServiceBusConnection( 6 | string name, 7 | string connectionString, 8 | Uri endpoint, 9 | string fullyQualifiedName, 10 | string? entityPath, 11 | string sharedAccessKey, 12 | string sharedAccessSignature, 13 | string sharedAccessKeyName) 14 | { 15 | Name = name; 16 | ConnectionString = connectionString; 17 | Endpoint = endpoint; 18 | FullyQualifiedName = fullyQualifiedName; 19 | EntityPath = entityPath; 20 | SharedAccessKey = sharedAccessKey; 21 | SharedAccessSignature = sharedAccessSignature; 22 | SharedAccessKeyName = sharedAccessKeyName; 23 | } 24 | public string Name { get; } 25 | public string ConnectionString { get; } 26 | public Uri Endpoint { get; } 27 | public string FullyQualifiedName { get; } 28 | public string? EntityPath { get; } 29 | public string SharedAccessKey { get; } 30 | public string SharedAccessSignature { get; } 31 | public string SharedAccessKeyName { get; } 32 | } -------------------------------------------------------------------------------- /src/Core/Management/ConnectionManagement.cs: -------------------------------------------------------------------------------- 1 | using CrossBusExplorer.Management.Contracts; 2 | namespace CrossBusExplorer.Management; 3 | 4 | public class ConnectionManagement : IConnectionManagement 5 | { 6 | private readonly IManagementStorage _managementStorage; 7 | 8 | public ConnectionManagement(IManagementStorage managementStorage) 9 | { 10 | _managementStorage = managementStorage; 11 | } 12 | 13 | public async Task> GetAsync( 14 | CancellationToken cancellationToken) 15 | { 16 | return (await _managementStorage.ReadAsync(cancellationToken)) 17 | .Select(p => p.Value) 18 | .ToList(); 19 | } 20 | 21 | public async Task GetAsync( 22 | string name, 23 | CancellationToken cancellationToken) 24 | { 25 | var connections = await _managementStorage.ReadAsync(cancellationToken); 26 | 27 | if (connections.ContainsKey(name)) 28 | { 29 | return connections[name]; 30 | } 31 | 32 | throw new ServiceBusConnectionDoesntExist(name); 33 | } 34 | 35 | public async Task SaveAsync( 36 | string name, 37 | string connectionString, 38 | string folder, 39 | CancellationToken cancellationToken) 40 | { 41 | IDictionary connections = 42 | await _managementStorage.ReadAsync(cancellationToken); 43 | 44 | var connection = ServiceBusConnectionStringHelper.GetServiceBusConnection( 45 | name, connectionString); 46 | 47 | //TODO: add to folder 48 | 49 | if (connections.ContainsKey(name)) 50 | { 51 | connections[name] = connection; 52 | } 53 | else if (connections.Any(p => p.Value.ConnectionString == connectionString)) 54 | { 55 | var keyToRemove = connections.First(p => p.Value.ConnectionString == connectionString) 56 | .Key; 57 | 58 | connections.Remove(keyToRemove); 59 | connections.Add(name, connection); 60 | } 61 | else 62 | { 63 | connections.Add(name, connection); 64 | } 65 | 66 | await _managementStorage.StoreAsync( 67 | connections, 68 | cancellationToken); 69 | 70 | return connection; 71 | } 72 | 73 | public async Task DeleteAsync(string name, CancellationToken cancellationToken) 74 | { 75 | var connections = await _managementStorage.ReadAsync(cancellationToken); 76 | 77 | if (connections.ContainsKey(name)) 78 | { 79 | connections.Remove(name); 80 | 81 | await _managementStorage.StoreAsync( 82 | connections, 83 | cancellationToken); 84 | } 85 | else 86 | { 87 | throw new ServiceBusConnectionDoesntExist(name); 88 | } 89 | } 90 | } -------------------------------------------------------------------------------- /src/Core/Management/IManagementStorage.cs: -------------------------------------------------------------------------------- 1 | using CrossBusExplorer.Management.Contracts; 2 | namespace CrossBusExplorer.Management; 3 | 4 | public interface IManagementStorage 5 | { 6 | Task StoreAsync( 7 | IDictionary connections, 8 | CancellationToken cancellationToken); 9 | Task> ReadAsync(CancellationToken cancellationToken); 10 | } -------------------------------------------------------------------------------- /src/Core/Management/Management.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | CrossBusExplorer.Management 8 | CrossBusExplorer.Management 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/Core/Management/ServiceBusConnectionDoesntExist.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.Management; 2 | 3 | public class ServiceBusConnectionDoesntExist : Exception 4 | { 5 | public ServiceBusConnectionDoesntExist(string name) : base( 6 | $"Service Bus connection with name {name} doesn't exist.") 7 | { 8 | } 9 | } -------------------------------------------------------------------------------- /src/Core/Management/ServiceBusConnectionStringHelper.cs: -------------------------------------------------------------------------------- 1 | using Azure.Messaging.ServiceBus; 2 | using CrossBusExplorer.Management.Contracts; 3 | namespace CrossBusExplorer.Management; 4 | 5 | public static class ServiceBusConnectionStringHelper 6 | { 7 | public static string? TryGetNameFromConnectionString(string connectionString) 8 | { 9 | try 10 | { 11 | var connectionStringProperties = 12 | ServiceBusConnectionStringProperties.Parse(connectionString); 13 | 14 | if (connectionStringProperties.FullyQualifiedNamespace.IndexOf('.') != -1) 15 | { 16 | return connectionStringProperties.FullyQualifiedNamespace.Split('.')[0]; 17 | } 18 | 19 | return connectionStringProperties.FullyQualifiedNamespace; 20 | } 21 | catch 22 | { 23 | return null; 24 | } 25 | } 26 | 27 | public static bool IsValid(string? connectionString) 28 | { 29 | try 30 | { 31 | ServiceBusConnectionStringProperties.Parse(connectionString); 32 | 33 | return true; 34 | } 35 | catch 36 | { 37 | return false; 38 | } 39 | } 40 | public static ServiceBusConnection GetServiceBusConnection( 41 | string name, 42 | string connectionString) 43 | { 44 | var properties = 45 | ServiceBusConnectionStringProperties.Parse(connectionString); 46 | 47 | return new ServiceBusConnection( 48 | name, 49 | connectionString, 50 | properties.Endpoint, 51 | properties.FullyQualifiedNamespace, 52 | properties.EntityPath, 53 | properties.SharedAccessKey, 54 | properties.SharedAccessSignature, 55 | properties.SharedAccessKeyName); 56 | } 57 | } -------------------------------------------------------------------------------- /src/Core/Management/ServiceCollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using CrossBusExplorer.Management.Contracts; 2 | using Microsoft.Extensions.DependencyInjection; 3 | namespace CrossBusExplorer.Management; 4 | 5 | public static class ServiceCollectionExtensions 6 | { 7 | public static IServiceCollection AddManagement(this IServiceCollection collection) 8 | { 9 | return collection 10 | .AddScoped(); 11 | } 12 | } -------------------------------------------------------------------------------- /src/Core/NotificationHub/NotificationHub.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/Core/Relay/Relay.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/Core/ServiceBus.Contracts/Excepions/MessageTooBigException.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.ServiceBus.Contracts; 2 | 3 | public class MessageTooBigException:Exception 4 | { 5 | 6 | } -------------------------------------------------------------------------------- /src/Core/ServiceBus.Contracts/Excepions/ServiceBusOperationException.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.ServiceBus.Contracts; 2 | 3 | public class ServiceBusOperationException : Exception 4 | { 5 | public ServiceBusOperationException(string code, string message) : base(message) 6 | { 7 | Code = code; 8 | } 9 | 10 | public string Code { get; } 11 | } -------------------------------------------------------------------------------- /src/Core/ServiceBus.Contracts/Excepions/ValidationException.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.ServiceBus.Contracts; 2 | 3 | public class ValidationException: Exception 4 | { 5 | public ValidationException(string code, string message) : base(message) 6 | { 7 | Code = code; 8 | } 9 | 10 | public string Code { get; } 11 | } -------------------------------------------------------------------------------- /src/Core/ServiceBus.Contracts/IMessageService.cs: -------------------------------------------------------------------------------- 1 | using CrossBusExplorer.ServiceBus.Contracts.Types; 2 | namespace CrossBusExplorer.ServiceBus.Contracts; 3 | 4 | public interface IMessageService 5 | { 6 | Task> GetMessagesAsync( 7 | string connectionName, 8 | string queueOrTopicName, 9 | string? subscriptionName, 10 | SubQueue subQueue, 11 | ReceiveMode mode, 12 | ReceiveType type, 13 | int? messagesCount, 14 | long? fromSequenceNumber, 15 | CancellationToken cancellationToken); 16 | 17 | Task SendMessagesAsync( 18 | string connectionName, 19 | string queueOrTopicName, 20 | IReadOnlyList messages, 21 | CancellationToken cancellationToken); 22 | 23 | IAsyncEnumerable PurgeAsync( 24 | string connectionName, 25 | string topicOrQueueName, 26 | string? subscriptionName, 27 | SubQueue subQueue, 28 | long totalCount, 29 | CancellationToken cancellationToken); 30 | 31 | IAsyncEnumerable ResendAsync(string connectionName, 32 | string topicOrQueueName, 33 | string? subscriptionName, 34 | SubQueue subQueue, 35 | string destinationTopicOrQueueName, 36 | long totalCount, 37 | CancellationToken cancellationToken); 38 | 39 | Task DeleteMessage( 40 | string connectionName, 41 | string queueOrTopicName, 42 | string? subscriptionName, 43 | SubQueue subQueue, 44 | long sequenceNumber, 45 | CancellationToken cancellationToken); 46 | } 47 | -------------------------------------------------------------------------------- /src/Core/ServiceBus.Contracts/IQueueService.cs: -------------------------------------------------------------------------------- 1 | using CrossBusExplorer.ServiceBus.Contracts.Types; 2 | namespace CrossBusExplorer.ServiceBus.Contracts 3 | { 4 | public interface IQueueService 5 | { 6 | IAsyncEnumerable GetAsync( 7 | string connectionName, 8 | CancellationToken cancellationToken); 9 | Task GetAsync( 10 | string connectionName, 11 | string name, 12 | CancellationToken cancellationToken); 13 | Task DeleteAsync( 14 | string connectionName, 15 | string name, 16 | CancellationToken cancellationToken); 17 | Task> CreateAsync( 18 | string connectionName, 19 | CreateQueueOptions options, 20 | CancellationToken cancellationToken); 21 | Task> CloneAsync( 22 | string connectionName, 23 | string name, 24 | string sourceName, 25 | CancellationToken cancellationToken); 26 | Task> UpdateAsync( 27 | string connectionName, 28 | UpdateQueueOptions options, 29 | CancellationToken cancellationToken); 30 | } 31 | } -------------------------------------------------------------------------------- /src/Core/ServiceBus.Contracts/IRuleService.cs: -------------------------------------------------------------------------------- 1 | using CrossBusExplorer.ServiceBus.Contracts.Types; 2 | namespace CrossBusExplorer.ServiceBus.Contracts; 3 | 4 | public interface IRuleService 5 | { 6 | IAsyncEnumerable GetAsync( 7 | string connectionName, 8 | string topicName, 9 | string subscriptionName, 10 | CancellationToken cancellationToken); 11 | 12 | Task DeleteAsync( 13 | string connectionName, 14 | string topicName, 15 | string subscriptionName, 16 | string ruleName, 17 | CancellationToken cancellationToken); 18 | 19 | Task> CreateAsync( 20 | string connectionName, 21 | string topicName, 22 | string subscriptionName, 23 | string ruleName, 24 | RuleType type, 25 | string? value, 26 | CancellationToken cancellationToken); 27 | 28 | Task> UpdateAsync( 29 | string connectionName, 30 | string topicName, 31 | string subscriptionName, 32 | string ruleName, 33 | RuleType type, 34 | string? value, 35 | CancellationToken cancellationToken); 36 | } -------------------------------------------------------------------------------- /src/Core/ServiceBus.Contracts/ISubscriptionService.cs: -------------------------------------------------------------------------------- 1 | using CrossBusExplorer.ServiceBus.Contracts.Types; 2 | namespace CrossBusExplorer.ServiceBus.Contracts; 3 | 4 | public interface ISubscriptionService 5 | { 6 | IAsyncEnumerable GetAsync( 7 | string connectionName, 8 | string topicName, 9 | CancellationToken cancellationToken); 10 | 11 | Task GetAsync( 12 | string connectionName, 13 | string topicName, 14 | string subscriptionName, 15 | CancellationToken cancellationToken); 16 | Task DeleteAsync( 17 | string connectionName, 18 | string topicName, 19 | string subscriptionName, 20 | CancellationToken cancellationToken); 21 | Task> CreateAsync( 22 | string connectionName, 23 | CreateSubscriptionOptions options, 24 | CancellationToken cancellationToken); 25 | Task> CloneAsync( 26 | string connectionName, 27 | string subscriptionName, 28 | string sourceTopicName, 29 | string sourceSubscriptionName, 30 | CancellationToken cancellationToken); 31 | Task> UpdateAsync( 32 | string connectionName, 33 | UpdateSubscriptionOptions options, 34 | CancellationToken cancellationToken); 35 | } -------------------------------------------------------------------------------- /src/Core/ServiceBus.Contracts/ITopicService.cs: -------------------------------------------------------------------------------- 1 | using CrossBusExplorer.ServiceBus.Contracts.Types; 2 | namespace CrossBusExplorer.ServiceBus.Contracts; 3 | 4 | public interface ITopicService 5 | { 6 | IAsyncEnumerable GetStructureAsync( 7 | string connectionName, 8 | CancellationToken cancellationToken); 9 | Task GetAsync( 10 | string connectionName, 11 | string name, 12 | CancellationToken cancellationToken); 13 | Task DeleteAsync( 14 | string connectionName, 15 | string name, 16 | CancellationToken cancellationToken); 17 | Task> CreateAsync( 18 | string connectionName, 19 | CreateTopicOptions options, 20 | CancellationToken cancellationToken); 21 | Task> CloneAsync( 22 | string connectionName, 23 | string name, 24 | string sourceName, 25 | CancellationToken cancellationToken); 26 | Task> UpdateAsync( 27 | string connectionName, 28 | UpdateTopicOptions options, 29 | CancellationToken cancellationToken); 30 | } -------------------------------------------------------------------------------- /src/Core/ServiceBus.Contracts/ServiceBus.Contracts.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | CrossBusExplorer.ServiceBus.Contracts 8 | CrossBusExplorer.ServiceBus.Contracts 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/Core/ServiceBus.Contracts/Types/AccessRights.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.ServiceBus.Contracts.Types; 2 | 3 | public enum AccessRights 4 | { 5 | Manage = 0, 6 | Send = 1, 7 | Listen = 2 8 | } -------------------------------------------------------------------------------- /src/Core/ServiceBus.Contracts/Types/ApplicationProperty.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.ServiceBus.Contracts.Types; 2 | 3 | public enum ApplicationPropertyType 4 | { 5 | String, 6 | Bool, 7 | Byte, 8 | Sbyte, 9 | Short, 10 | Ushort, 11 | Int, 12 | Uint, 13 | Long, 14 | Ulong, 15 | Float, 16 | Decimal, 17 | Double, 18 | Char, 19 | Guid, 20 | DateTime, 21 | DateTimeOffset, 22 | Stream, 23 | Uri, 24 | TimeSpan, 25 | } 26 | -------------------------------------------------------------------------------- /src/Core/ServiceBus.Contracts/Types/CreateQueueOptions.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.ServiceBus.Contracts.Types; 2 | 3 | public record CreateQueueOptions( 4 | string Name, 5 | IReadOnlyList? AuthorizationRules, 6 | long? MaxSizeInMegabytes, 7 | TimeSpan? LockDuration, 8 | bool? RequiresSession, 9 | TimeSpan? DefaultMessageTimeToLive, 10 | TimeSpan? AutoDeleteOnIdle, 11 | bool? DeadLetteringOnMessageExpiration, 12 | TimeSpan? DuplicateDetectionHistoryTimeWindow, 13 | int? MaxDeliveryCount, 14 | bool? EnableBatchedOperations, 15 | ServiceBusEntityStatus? Status, 16 | string? ForwardTo, 17 | string? ForwardDeadLetteredMessagesTo, 18 | long? MaxMessageSizeInKilobytes, 19 | string? UserMetadata, 20 | bool? RequiresDuplicateDetection, 21 | bool? EnablePartitioning); -------------------------------------------------------------------------------- /src/Core/ServiceBus.Contracts/Types/CreateSubscriptionOptions.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.ServiceBus.Contracts.Types; 2 | 3 | public record CreateSubscriptionOptions( 4 | string TopicName, 5 | string SubscriptionName, 6 | TimeSpan? LockDuration, 7 | bool? RequiresSession, 8 | TimeSpan? DefaultMessageTimeToLive, 9 | TimeSpan? AutoDeleteOnIdle, 10 | bool? DeadLetteringOnMessageExpiration, 11 | bool? EnableDeadLetteringOnFilterEvaluationExceptions, 12 | int? MaxDeliveryCount, 13 | bool? EnableBatchedOperations, 14 | ServiceBusEntityStatus? Status, 15 | string? ForwardTo, 16 | string? ForwardDeadLetteredMessagesTo, 17 | string? UserMetadata); -------------------------------------------------------------------------------- /src/Core/ServiceBus.Contracts/Types/CreateTopicOptions.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.ServiceBus.Contracts.Types; 2 | 3 | public record CreateTopicOptions( 4 | string Name, 5 | IReadOnlyList? AuthorizationRules, 6 | long? MaxSizeInMegabytes, 7 | TimeSpan? DefaultMessageTimeToLive, 8 | TimeSpan? AutoDeleteOnIdle, 9 | TimeSpan? DuplicateDetectionHistoryTimeWindow, 10 | bool? EnableBatchedOperations, 11 | ServiceBusEntityStatus? Status, 12 | long? MaxMessageSizeInKilobytes, 13 | string? UserMetadata, 14 | bool? RequiresDuplicateDetection, 15 | bool? SupportOrdering, 16 | bool? EnablePartitioning); -------------------------------------------------------------------------------- /src/Core/ServiceBus.Contracts/Types/LockDuration.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.ServiceBus.Contracts.Types; 2 | 3 | public record LockDuration(); -------------------------------------------------------------------------------- /src/Core/ServiceBus.Contracts/Types/Message.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | namespace CrossBusExplorer.ServiceBus.Contracts.Types; 3 | 4 | public record Message( 5 | string Id, 6 | string? Subject, 7 | string Body, 8 | MessageSystemProperties SystemProperties, 9 | IReadOnlyDictionary? ApplicationProperties); 10 | -------------------------------------------------------------------------------- /src/Core/ServiceBus.Contracts/Types/MessageState.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.ServiceBus.Contracts.Types; 2 | 3 | public enum MessageState 4 | { 5 | Active = 0, 6 | Deferred = 1, 7 | Scheduled = 2 8 | } -------------------------------------------------------------------------------- /src/Core/ServiceBus.Contracts/Types/MessageSystemProperties.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.ServiceBus.Contracts.Types; 2 | 3 | public record MessageSystemProperties( 4 | string? ContentType, 5 | string? CorrelationId, 6 | string? DeadLetterSource, 7 | string? DeadLetterReason, 8 | string? DeadLetterErrorDescription, 9 | int DeliveryCount, 10 | long EnqueuedSequenceNumber, 11 | DateTimeOffset EnqueuedTime, 12 | DateTimeOffset ExpiresAt, 13 | DateTimeOffset LockedUntil, 14 | string LockToken, 15 | string? PartitionKey, 16 | string? TransactionPartitionKey, 17 | string? ReplyTo, 18 | string? ReplyToSessionId, 19 | DateTimeOffset? ScheduledEnqueueTime, 20 | long SequenceNumber, 21 | string? SessionId, 22 | MessageState? State, 23 | TimeSpan TimeToLive, 24 | string? To); -------------------------------------------------------------------------------- /src/Core/ServiceBus.Contracts/Types/OperationResult.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.ServiceBus.Contracts.Types; 2 | 3 | public record OperationResult(bool Success); 4 | 5 | public record OperationResult(bool Success, TModel? Data); -------------------------------------------------------------------------------- /src/Core/ServiceBus.Contracts/Types/PurgeResult.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.ServiceBus.Contracts.Types; 2 | 3 | public record PurgeResult(long PurgedCount); -------------------------------------------------------------------------------- /src/Core/ServiceBus.Contracts/Types/QueueDetails.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.ServiceBus.Contracts.Types; 2 | 3 | public record QueueDetails( 4 | QueueInfo Info, 5 | QueueSettings Settings, 6 | QueueTimeSettings TimeSettings, 7 | QueueProperties Properties); -------------------------------------------------------------------------------- /src/Core/ServiceBus.Contracts/Types/QueueInfo.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.ServiceBus.Contracts.Types; 2 | 3 | public record QueueInfo( 4 | string Name, 5 | ServiceBusEntityStatus Status, 6 | long SizeInBytes, 7 | DateTimeOffset CreatedAt, 8 | DateTimeOffset AccessedAt, 9 | DateTimeOffset UpdatedAt, 10 | long ActiveMessagesCount, 11 | long DeadLetterMessagesCount, 12 | long ScheduledMessagesCount, 13 | long InTransferMessagesCount, 14 | long TransferDeadLetterMessagesCount, 15 | long TotalMessagesCount) 16 | { 17 | public long SizeInMB => SizeInBytes / 1024 / 1024; 18 | } -------------------------------------------------------------------------------- /src/Core/ServiceBus.Contracts/Types/QueueProperties.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.ServiceBus.Contracts.Types; 2 | 3 | public record QueueProperties( 4 | long MaxQueueSizeInMegabytes, 5 | long? MaxMessageSizeInKilobytes, 6 | int MaxDeliveryCount, 7 | string? UserMetadata, 8 | string? ForwardTo, 9 | string? ForwardDeadLetteredMessagesTo); -------------------------------------------------------------------------------- /src/Core/ServiceBus.Contracts/Types/QueueSettings.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.ServiceBus.Contracts.Types; 2 | 3 | public record QueueSettings( 4 | bool EnableBatchedOperations, 5 | bool EnableDeadLetteringOnMessageExpiration, 6 | bool EnablePartitioning, 7 | bool RequiresDuplicateDetection, 8 | bool RequiresSession); -------------------------------------------------------------------------------- /src/Core/ServiceBus.Contracts/Types/QueueTimeSettings.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.ServiceBus.Contracts.Types; 2 | 3 | public record QueueTimeSettings( 4 | TimeSpan AutoDeleteOnIdle, 5 | TimeSpan DefaultMessageTimeToLive, 6 | TimeSpan DuplicateDetectionHistoryTimeWindow, 7 | TimeSpan LockDuration); -------------------------------------------------------------------------------- /src/Core/ServiceBus.Contracts/Types/ReceiveMode.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.ServiceBus.Contracts.Types; 2 | 3 | public enum ReceiveMode 4 | { 5 | PeekLock, 6 | ReceiveAndDelete 7 | } -------------------------------------------------------------------------------- /src/Core/ServiceBus.Contracts/Types/ReceiveType.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.ServiceBus.Contracts.Types; 2 | 3 | public enum ReceiveType 4 | { 5 | All, 6 | ByCount 7 | } -------------------------------------------------------------------------------- /src/Core/ServiceBus.Contracts/Types/ResendResult.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.ServiceBus.Contracts.Types; 2 | 3 | public record ResendResult(long ResendCount); -------------------------------------------------------------------------------- /src/Core/ServiceBus.Contracts/Types/Result.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.ServiceBus.Contracts.Types; 2 | 3 | public record Result(long Count); -------------------------------------------------------------------------------- /src/Core/ServiceBus.Contracts/Types/Rule.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.ServiceBus.Contracts.Types; 2 | 3 | public record Rule(string Name, RuleType Type, string? Value); -------------------------------------------------------------------------------- /src/Core/ServiceBus.Contracts/Types/RuleType.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.ServiceBus.Contracts.Types; 2 | 3 | public enum RuleType 4 | { 5 | Sql, 6 | CorrelationId, 7 | TrueFilter, 8 | FalseFilter 9 | } -------------------------------------------------------------------------------- /src/Core/ServiceBus.Contracts/Types/SendMessage.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.ServiceBus.Contracts.Types; 2 | 3 | public record SendMessage( 4 | string Body, 5 | string? Subject, 6 | string? To, 7 | string? ContentType, 8 | string? CorrelationId, 9 | string? Id, 10 | string? PartitionKey, 11 | string? ReplyTo, 12 | string? SessionId, 13 | DateTimeOffset? ScheduledEnqueueTime, 14 | TimeSpan? TimeToLive, 15 | Dictionary? ApplicationProperties) 16 | { 17 | public static SendMessage CreateFromBody(string body) => 18 | new SendMessage(body, null, null, null, null, null, null, null, null, null, null, null); 19 | } 20 | -------------------------------------------------------------------------------- /src/Core/ServiceBus.Contracts/Types/ServiceBusEntityStatus.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.ServiceBus.Contracts.Types; 2 | 3 | public enum ServiceBusEntityStatus 4 | { 5 | Active, 6 | Disabled, 7 | SendDisabled, //TODO: support in ui 8 | ReceiveDisabled //TODO: support in ui 9 | } -------------------------------------------------------------------------------- /src/Core/ServiceBus.Contracts/Types/SharedAccessAuthorizationRule.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.ServiceBus.Contracts.Types; 2 | 3 | public record SharedAccessAuthorizationRule( 4 | string KeyName, 5 | string PrimaryKey, 6 | string SecondaryKey, 7 | IEnumerable Rights); -------------------------------------------------------------------------------- /src/Core/ServiceBus.Contracts/Types/SubQueue.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.ServiceBus.Contracts.Types; 2 | 3 | public enum SubQueue 4 | { 5 | None = 0, 6 | DeadLetter = 1, 7 | TransferDeadLetter = 2 8 | } -------------------------------------------------------------------------------- /src/Core/ServiceBus.Contracts/Types/SubscriptionDetails.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.ServiceBus.Contracts.Types; 2 | 3 | public record SubscriptionDetails( 4 | SubscriptionInfo Info, 5 | SubscriptionSettings Settings, 6 | SubscriptionTimeSettings TimeSettings, 7 | SubscriptionProperties Properties); -------------------------------------------------------------------------------- /src/Core/ServiceBus.Contracts/Types/SubscriptionInfo.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.ServiceBus.Contracts.Types; 2 | 3 | public record SubscriptionInfo( 4 | string TopicName, 5 | string SubscriptionName, 6 | ServiceBusEntityStatus Status, 7 | DateTimeOffset CreatedAt, 8 | DateTimeOffset AccessedAt, 9 | DateTimeOffset UpdatedAt, 10 | long ActiveMessagesCount, 11 | long DeadLetterMessagesCount, 12 | long TransferMessagesCount); -------------------------------------------------------------------------------- /src/Core/ServiceBus.Contracts/Types/SubscriptionProperties.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.ServiceBus.Contracts.Types; 2 | 3 | public record SubscriptionProperties( 4 | int MaxDeliveryCount, 5 | string? UserMetadata, 6 | string? ForwardTo, 7 | string? ForwardDeadLetteredMessagesTo); -------------------------------------------------------------------------------- /src/Core/ServiceBus.Contracts/Types/SubscriptionSettings.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.ServiceBus.Contracts.Types; 2 | 3 | public record SubscriptionSettings( 4 | bool EnableBatchedOperations, 5 | bool EnableDeadLetteringOnMessageExpiration, 6 | bool RequiresSession, 7 | bool EnableDeadLetteringOnFilterEvaluationExceptions); -------------------------------------------------------------------------------- /src/Core/ServiceBus.Contracts/Types/SubscriptionTimeSettings.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.ServiceBus.Contracts.Types; 2 | 3 | public record SubscriptionTimeSettings( 4 | TimeSpan AutoDeleteOnIdle, 5 | TimeSpan DefaultMessageTimeToLive, 6 | TimeSpan LockDuration); -------------------------------------------------------------------------------- /src/Core/ServiceBus.Contracts/Types/TopicDetails.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.ServiceBus.Contracts.Types; 2 | 3 | public record TopicDetails( 4 | TopicInfo Info, 5 | TopicSettings Settings, 6 | TopicTimeSettings TimeSettings, 7 | TopicProperties Properties); -------------------------------------------------------------------------------- /src/Core/ServiceBus.Contracts/Types/TopicInfo.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.ServiceBus.Contracts.Types; 2 | 3 | public record TopicInfo( 4 | string Name, 5 | ServiceBusEntityStatus Status, 6 | long SizeInBytes, 7 | DateTimeOffset CreatedAt, 8 | DateTimeOffset AccessedAt, 9 | DateTimeOffset UpdatedAt, 10 | long ScheduledMessagesCount) 11 | { 12 | public long SizeInMB => SizeInBytes / 1024 / 1024; 13 | } -------------------------------------------------------------------------------- /src/Core/ServiceBus.Contracts/Types/TopicProperties.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.ServiceBus.Contracts.Types; 2 | 3 | public record TopicProperties( 4 | long MaxQueueSizeInMegabytes, 5 | long? MaxMessageSizeInKilobytes, 6 | string? UserMetadata); -------------------------------------------------------------------------------- /src/Core/ServiceBus.Contracts/Types/TopicSettings.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.ServiceBus.Contracts.Types; 2 | 3 | public record TopicSettings( 4 | bool EnableBatchedOperations, 5 | bool EnablePartitioning, 6 | bool RequiresDuplicateDetection, 7 | bool SupportOrdering); -------------------------------------------------------------------------------- /src/Core/ServiceBus.Contracts/Types/TopicStructure.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.ServiceBus.Contracts.Types; 2 | 3 | public record TopicStructure( 4 | string Name, 5 | bool IsFolder, 6 | string? FullName, 7 | IList ChildTopics); -------------------------------------------------------------------------------- /src/Core/ServiceBus.Contracts/Types/TopicTimeSettings.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.ServiceBus.Contracts.Types; 2 | 3 | public record TopicTimeSettings( 4 | TimeSpan AutoDeleteOnIdle, 5 | TimeSpan DefaultMessageTimeToLive, 6 | TimeSpan DuplicateDetectionHistoryTimeWindow); -------------------------------------------------------------------------------- /src/Core/ServiceBus.Contracts/Types/UpdateQueueOptions.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.ServiceBus.Contracts.Types; 2 | 3 | public record UpdateQueueOptions( 4 | string Name, 5 | IReadOnlyList? AuthorizationRules=null, 6 | long? MaxSizeInMegabytes=null, 7 | TimeSpan? LockDuration=null, 8 | bool? RequiresSession=null, 9 | TimeSpan? DefaultMessageTimeToLive=null, 10 | TimeSpan? AutoDeleteOnIdle=null, 11 | bool? DeadLetteringOnMessageExpiration=null, 12 | TimeSpan? DuplicateDetectionHistoryTimeWindow=null, 13 | int? MaxDeliveryCount=null, 14 | bool? EnableBatchedOperations=null, 15 | ServiceBusEntityStatus? Status=null, 16 | string? ForwardTo=null, 17 | string? ForwardDeadLetteredMessagesTo=null, 18 | long? MaxMessageSizeInKilobytes=null, 19 | string? UserMetadata=null); -------------------------------------------------------------------------------- /src/Core/ServiceBus.Contracts/Types/UpdateSubscriptionOptions.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.ServiceBus.Contracts.Types; 2 | 3 | public record UpdateSubscriptionOptions( 4 | string TopicName, 5 | string SubscriptionName, 6 | TimeSpan? LockDuration=null, 7 | bool? RequiresSession=null, 8 | TimeSpan? DefaultMessageTimeToLive=null, 9 | TimeSpan? AutoDeleteOnIdle=null, 10 | bool? DeadLetteringOnMessageExpiration=null, 11 | int? MaxDeliveryCount=null, 12 | bool? EnableBatchedOperations=null, 13 | ServiceBusEntityStatus? Status=null, 14 | string? ForwardTo=null, 15 | string? ForwardDeadLetteredMessagesTo=null, 16 | string? UserMetadata=null); -------------------------------------------------------------------------------- /src/Core/ServiceBus.Contracts/Types/UpdateTopicOptions.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.ServiceBus.Contracts.Types; 2 | 3 | public record UpdateTopicOptions( 4 | string Name, 5 | IReadOnlyList? AuthorizationRules=null, 6 | long? MaxSizeInMegabytes=null, 7 | TimeSpan? DefaultMessageTimeToLive=null, 8 | TimeSpan? AutoDeleteOnIdle=null, 9 | TimeSpan? DuplicateDetectionHistoryTimeWindow=null, 10 | bool? EnableBatchedOperations=null, 11 | bool? SupportOrdering=null, 12 | ServiceBusEntityStatus? Status=null, 13 | long? MaxMessageSizeInKilobytes=null, 14 | string? UserMetadata=null); -------------------------------------------------------------------------------- /src/Core/ServiceBus.Contracts/Types/UploadFileType.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.ServiceBus.Contracts.Types; 2 | 3 | public enum UploadFileType 4 | { 5 | Body = 0, 6 | BodyWithApplicationProperties = 1 7 | } 8 | -------------------------------------------------------------------------------- /src/Core/ServiceBus/ServiceBus.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | CrossBusExplorer.ServiceBus 8 | CrossBusExplorer.ServiceBus 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/Core/ServiceBus/ServiceCollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using CrossBusExplorer.ServiceBus.Contracts; 2 | using Microsoft.Extensions.DependencyInjection; 3 | 4 | namespace CrossBusExplorer.ServiceBus; 5 | 6 | public static class ServiceCollectionExtensions 7 | { 8 | public static IServiceCollection AddServiceBusServices(this IServiceCollection collection) 9 | { 10 | return collection 11 | .AddScoped() 12 | .AddScoped() 13 | .AddScoped() 14 | .AddScoped() 15 | .AddScoped(); 16 | } 17 | } -------------------------------------------------------------------------------- /src/Ui/Host.Ui/App.xaml: -------------------------------------------------------------------------------- 1 |  2 | 5 | 6 | 7 | 8 | #512bdf 9 | White 10 | 11 | 15 | 16 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/Ui/Host.Ui/App.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.Host.Ui; 2 | 3 | public partial class App : Application 4 | { 5 | public App() 6 | { 7 | InitializeComponent(); 8 | 9 | MainPage = new MainPage(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Ui/Host.Ui/Host.Ui.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0-maccatalyst 5 | $(TargetFrameworks);net8.0-windows10.0.19041.0 6 | 7 | Exe 8 | true 9 | true 10 | enable 11 | false 12 | CrossBusExplorer.Host.Ui 13 | Cross Bus Explorer 14 | Cross Bus Explorer 15 | enable 16 | 17 | 18 | Cross Bus Explorer 19 | 20 | 21 | cross.bus.explorer 22 | 275C3E82-3150-4869-89BE-9EE91D783534 23 | 24 | 25 | 0.0.1 26 | 1 27 | 28 | 14.2 29 | 14.0 30 | 24.0 31 | 10.0.17763.0 32 | 10.0.17763.0 33 | 6.5 34 | 35 | 36 | 37 | maccatalyst-x64 38 | x64 39 | 40 | 41 | 42 | true 43 | true 44 | 45 | 46 | $(RuntimeIdentifierOverride) 47 | 48 | 49 | 50 | false 51 | 52 | 53 | 4 54 | 55 | 56 | false 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /src/Ui/Host.Ui/Main.razor: -------------------------------------------------------------------------------- 1 | @using CrossBusExplorer.Website.Shared 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |

Sorry, there's nothing at this address.

10 |
11 |
12 |
13 | -------------------------------------------------------------------------------- /src/Ui/Host.Ui/MainPage.xaml: -------------------------------------------------------------------------------- 1 |  2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/Ui/Host.Ui/MainPage.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.Host.Ui; 2 | 3 | public partial class MainPage : ContentPage 4 | { 5 | public MainPage() 6 | { 7 | InitializeComponent(); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Ui/Host.Ui/ManagementStorage.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.Text; 3 | using System.Text.Json; 4 | using CrossBusExplorer.Management; 5 | using CrossBusExplorer.Management.Contracts; 6 | namespace CrossBusExplorer.Host.Ui; 7 | 8 | public class ManagementStorage : IManagementStorage 9 | { 10 | private const string ServiceBusConnectionsFileName = "servicebusconnections.json"; 11 | 12 | public async Task StoreAsync( 13 | IDictionary connections, 14 | CancellationToken cancellationToken) 15 | { 16 | await File.WriteAllTextAsync( 17 | FilePath, 18 | JsonSerializer.Serialize(connections), 19 | Encoding.UTF8, 20 | cancellationToken); 21 | } 22 | 23 | public async Task> ReadAsync( 24 | CancellationToken cancellationToken) 25 | { 26 | if (File.Exists(FilePath)) 27 | { 28 | var serializedData = await File.ReadAllTextAsync(FilePath, cancellationToken); 29 | 30 | return JsonSerializer.Deserialize>( 31 | serializedData) ?? new Dictionary(); 32 | } 33 | 34 | return new Dictionary(); 35 | } 36 | 37 | private string FilePath => Path.Combine( 38 | FileSystem.AppDataDirectory, 39 | ServiceBusConnectionsFileName); 40 | } -------------------------------------------------------------------------------- /src/Ui/Host.Ui/Maui.App.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.0.31611.283 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Maui", "Maui.csproj", "{8A56795C-D24F-43FF-984D-CEEE1C882A2F}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {8A56795C-D24F-43FF-984D-CEEE1C882A2F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {8A56795C-D24F-43FF-984D-CEEE1C882A2F}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {8A56795C-D24F-43FF-984D-CEEE1C882A2F}.Debug|Any CPU.Deploy.0 = Debug|Any CPU 17 | {8A56795C-D24F-43FF-984D-CEEE1C882A2F}.Release|Any CPU.ActiveCfg = Release|Any CPU 18 | {8A56795C-D24F-43FF-984D-CEEE1C882A2F}.Release|Any CPU.Build.0 = Release|Any CPU 19 | {8A56795C-D24F-43FF-984D-CEEE1C882A2F}.Release|Any CPU.Deploy.0 = Release|Any CPU 20 | EndGlobalSection 21 | GlobalSection(SolutionProperties) = preSolution 22 | HideSolutionNode = FALSE 23 | EndGlobalSection 24 | GlobalSection(ExtensibilityGlobals) = postSolution 25 | SolutionGuid = {61F7FB11-1E47-470C-91E2-47F8143E1572} 26 | EndGlobalSection 27 | EndGlobal 28 | -------------------------------------------------------------------------------- /src/Ui/Host.Ui/MauiProgram.cs: -------------------------------------------------------------------------------- 1 | using CrossBusExplorer.Management; 2 | using CrossBusExplorer.ServiceBus; 3 | using CrossBusExplorer.Website; 4 | using MudBlazor.Services; 5 | namespace CrossBusExplorer.Host.Ui; 6 | 7 | public static class MauiProgram 8 | { 9 | public static MauiApp CreateMauiApp() 10 | { 11 | var builder = MauiApp.CreateBuilder(); 12 | builder 13 | .UseMauiApp() 14 | .ConfigureFonts(fonts => 15 | { 16 | fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); 17 | }); 18 | #if DEBUG 19 | builder.Services.AddBlazorWebViewDeveloperTools(); 20 | builder.Services.AddBlazorWebView(); 21 | #endif 22 | 23 | builder.Services.AddMauiBlazorWebView(); 24 | builder.Services.AddMudServices(); 25 | builder.Services.AddWebsiteServices(); 26 | builder.Services.AddServiceBusServices(); 27 | builder.Services.AddManagement(); 28 | builder.Services.AddSingleton(); 29 | builder.Services.AddSingleton(); 30 | 31 | return builder.Build(); 32 | } 33 | } -------------------------------------------------------------------------------- /src/Ui/Host.Ui/Platforms/Android/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/Ui/Host.Ui/Platforms/Android/MainActivity.cs: -------------------------------------------------------------------------------- 1 | using Android.App; 2 | using Android.Content.PM; 3 | using Android.OS; 4 | 5 | namespace Maui; 6 | 7 | [Activity(Theme = "@style/Maui.SplashTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.Density)] 8 | public class MainActivity : MauiAppCompatActivity 9 | { 10 | } 11 | -------------------------------------------------------------------------------- /src/Ui/Host.Ui/Platforms/Android/MainApplication.cs: -------------------------------------------------------------------------------- 1 | using Android.App; 2 | using Android.Runtime; 3 | 4 | namespace Maui; 5 | 6 | [Application] 7 | public class MainApplication : MauiApplication 8 | { 9 | public MainApplication(IntPtr handle, JniHandleOwnership ownership) 10 | : base(handle, ownership) 11 | { 12 | } 13 | 14 | protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); 15 | } 16 | -------------------------------------------------------------------------------- /src/Ui/Host.Ui/Platforms/Android/Resources/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #512BD4 4 | #2B0B98 5 | #2B0B98 6 | -------------------------------------------------------------------------------- /src/Ui/Host.Ui/Platforms/MacCatalyst/AppDelegate.cs: -------------------------------------------------------------------------------- 1 | using Foundation; 2 | namespace CrossBusExplorer.Host.Ui.Platforms.MacCatalyst; 3 | 4 | [Register("AppDelegate")] 5 | public class AppDelegate : MauiUIApplicationDelegate 6 | { 7 | protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); 8 | } 9 | -------------------------------------------------------------------------------- /src/Ui/Host.Ui/Platforms/MacCatalyst/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | UIDeviceFamily 6 | 7 | 1 8 | 2 9 | 10 | UIRequiredDeviceCapabilities 11 | 12 | arm64 13 | 14 | UISupportedInterfaceOrientations 15 | 16 | UIInterfaceOrientationPortrait 17 | UIInterfaceOrientationLandscapeLeft 18 | UIInterfaceOrientationLandscapeRight 19 | 20 | UISupportedInterfaceOrientations~ipad 21 | 22 | UIInterfaceOrientationPortrait 23 | UIInterfaceOrientationPortraitUpsideDown 24 | UIInterfaceOrientationLandscapeLeft 25 | UIInterfaceOrientationLandscapeRight 26 | 27 | XSAppIconAssets 28 | Assets.xcassets/appicon.appiconset 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/Ui/Host.Ui/Platforms/MacCatalyst/Program.cs: -------------------------------------------------------------------------------- 1 | using UIKit; 2 | namespace CrossBusExplorer.Host.Ui.Platforms.MacCatalyst; 3 | 4 | public class Program 5 | { 6 | // This is the main entry point of the application. 7 | static void Main(string[] args) 8 | { 9 | // if you want to use a different Application Delegate class from "AppDelegate" 10 | // you can specify it here. 11 | UIApplication.Main(args, null, typeof(AppDelegate)); 12 | } 13 | } -------------------------------------------------------------------------------- /src/Ui/Host.Ui/Platforms/Tizen/Main.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Maui; 3 | using Microsoft.Maui.Hosting; 4 | 5 | namespace Maui; 6 | 7 | class Program : MauiApplication 8 | { 9 | protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); 10 | 11 | static void Main(string[] args) 12 | { 13 | var app = new Program(); 14 | app.Run(args); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Ui/Host.Ui/Platforms/Tizen/tizen-manifest.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | maui-appicon-placeholder 7 | 8 | 9 | 10 | 11 | http://tizen.org/privilege/internet 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/Ui/Host.Ui/Platforms/Windows/App.xaml: -------------------------------------------------------------------------------- 1 |  7 | 8 | 9 | -------------------------------------------------------------------------------- /src/Ui/Host.Ui/Platforms/Windows/App.xaml.cs: -------------------------------------------------------------------------------- 1 |  2 | 3 | // To learn more about WinUI, the WinUI project structure, 4 | // and more about our project templates, see: http://aka.ms/winui-project-info. 5 | 6 | namespace CrossBusExplorer.Host.Ui.Windows; 7 | 8 | /// 9 | /// Provides application-specific behavior to supplement the default Application class. 10 | /// 11 | public partial class App : MauiWinUIApplication 12 | { 13 | /// 14 | /// Initializes the singleton application object. This is the first line of authored code 15 | /// executed, and as such is the logical equivalent of main() or WinMain(). 16 | /// 17 | public App() 18 | { 19 | this.InitializeComponent(); 20 | } 21 | 22 | protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); 23 | } 24 | 25 | -------------------------------------------------------------------------------- /src/Ui/Host.Ui/Platforms/Windows/Package.appxmanifest: -------------------------------------------------------------------------------- 1 |  2 | 7 | 8 | 9 | 10 | 11 | $placeholder$ 12 | Mariusz Matysek 13 | $placeholder$.png 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /src/Ui/Host.Ui/Platforms/Windows/app.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | true/PM 12 | PerMonitorV2, PerMonitor 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/Ui/Host.Ui/Platforms/iOS/AppDelegate.cs: -------------------------------------------------------------------------------- 1 | using Foundation; 2 | 3 | namespace Maui; 4 | 5 | [Register("AppDelegate")] 6 | public class AppDelegate : MauiUIApplicationDelegate 7 | { 8 | protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); 9 | } 10 | -------------------------------------------------------------------------------- /src/Ui/Host.Ui/Platforms/iOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | LSRequiresIPhoneOS 6 | 7 | UIDeviceFamily 8 | 9 | 1 10 | 2 11 | 12 | UIRequiredDeviceCapabilities 13 | 14 | arm64 15 | 16 | UISupportedInterfaceOrientations 17 | 18 | UIInterfaceOrientationPortrait 19 | UIInterfaceOrientationLandscapeLeft 20 | UIInterfaceOrientationLandscapeRight 21 | 22 | UISupportedInterfaceOrientations~ipad 23 | 24 | UIInterfaceOrientationPortrait 25 | UIInterfaceOrientationPortraitUpsideDown 26 | UIInterfaceOrientationLandscapeLeft 27 | UIInterfaceOrientationLandscapeRight 28 | 29 | XSAppIconAssets 30 | Assets.xcassets/appicon.appiconset 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/Ui/Host.Ui/Platforms/iOS/Program.cs: -------------------------------------------------------------------------------- 1 | using ObjCRuntime; 2 | using UIKit; 3 | 4 | namespace Maui; 5 | 6 | public class Program 7 | { 8 | // This is the main entry point of the application. 9 | static void Main(string[] args) 10 | { 11 | // if you want to use a different Application Delegate class from "AppDelegate" 12 | // you can specify it here. 13 | UIApplication.Main(args, null, typeof(AppDelegate)); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Ui/Host.Ui/Resources/AppIcon/appicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/Ui/Host.Ui/Resources/AppIcon/appiconfg.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/Ui/Host.Ui/Resources/Fonts/OpenSans-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carael/CrossBusExplorer/c965c80e011bdc17a19405e063d226606f59ceba/src/Ui/Host.Ui/Resources/Fonts/OpenSans-Regular.ttf -------------------------------------------------------------------------------- /src/Ui/Host.Ui/Resources/Raw/AboutAssets.txt: -------------------------------------------------------------------------------- 1 | Any raw assets you want to be deployed with your application can be placed in 2 | this directory (and child directories). Deployment of the asset to your application 3 | is automatically handled by the following `MauiAsset` Build Action within your `.csproj`. 4 | 5 | 6 | 7 | These files will be deployed with you package and will be accessible using Essentials: 8 | 9 | async Task LoadMauiAsset() 10 | { 11 | using var stream = await FileSystem.OpenAppPackageFileAsync("AboutAssets.txt"); 12 | using var reader = new StreamReader(stream); 13 | 14 | var contents = reader.ReadToEnd(); 15 | } 16 | -------------------------------------------------------------------------------- /src/Ui/Host.Ui/Resources/Splash/splash.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/Ui/Host.Ui/UserSettingsService.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json; 2 | using CrossBusExplorer.Website; 3 | using CrossBusExplorer.Website.Models; 4 | namespace CrossBusExplorer.Host.Ui; 5 | 6 | public class UserSettingsService : IUserSettingsService 7 | { 8 | private const string key = "user_settings"; 9 | 10 | public Task GetAsync(CancellationToken cancellationToken) 11 | { 12 | if (!Preferences.ContainsKey(key)) 13 | { 14 | return Task.FromResult(new UserSettings()); 15 | } 16 | 17 | var json = Preferences.Get(key, null); 18 | 19 | if (json is null) 20 | { 21 | return Task.FromResult(new UserSettings()); 22 | } 23 | 24 | return Task.FromResult(JsonSerializer.Deserialize(json) 25 | ?? new UserSettings()); 26 | } 27 | 28 | public Task SaveAsync(UserSettings userSettings, CancellationToken cancellationToken) 29 | { 30 | Preferences.Set(key, JsonSerializer.Serialize(userSettings)); 31 | 32 | return Task.CompletedTask; 33 | } 34 | } -------------------------------------------------------------------------------- /src/Ui/Host.Ui/_Imports.razor: -------------------------------------------------------------------------------- 1 | @using System.Net.Http 2 | @using Microsoft.AspNetCore.Components.Forms 3 | @using Microsoft.AspNetCore.Components.Routing 4 | @using Microsoft.AspNetCore.Components.Web 5 | @using Microsoft.AspNetCore.Components.Web.Virtualization 6 | @using Microsoft.JSInterop 7 | @using MudBlazor 8 | -------------------------------------------------------------------------------- /src/Ui/Host.Ui/wwwroot/css/custom.css: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /src/Ui/Host.Ui/wwwroot/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carael/CrossBusExplorer/c965c80e011bdc17a19405e063d226606f59ceba/src/Ui/Host.Ui/wwwroot/favicon.ico -------------------------------------------------------------------------------- /src/Ui/Host.Ui/wwwroot/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Maui 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 |
Loading...
18 | 19 |
20 | An unhandled error has occurred. 21 | Reload 22 | 🗙 23 |
24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/Ui/Website.Host/App.razor: -------------------------------------------------------------------------------- 1 | @using CrossBusExplorer.Website.Shared 2 | 3 | 4 | 5 | 6 | 7 | Not found 8 | 9 |

Sorry, there's nothing at this address.

10 |
11 |
12 |
-------------------------------------------------------------------------------- /src/Ui/Website.Host/DefaultSettingsService.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json; 2 | using CrossBusExplorer.Website; 3 | using CrossBusExplorer.Website.Models; 4 | using ElectronSharp.API; 5 | using ElectronSharp.API.Entities; 6 | namespace Website.Host; 7 | 8 | public class DefaultSettingsService : ISettingsService 9 | { 10 | private const string FileName = "settings.json"; 11 | 12 | public async Task GetAsync(CancellationToken cancellationToken) 13 | { 14 | var filePath = await FilePath(cancellationToken); 15 | 16 | if (File.Exists(filePath)) 17 | { 18 | var fileContent = await File.ReadAllTextAsync(filePath, cancellationToken); 19 | return JsonSerializer.Deserialize(fileContent); 20 | } 21 | 22 | return new UserSettings(); 23 | } 24 | 25 | 26 | public async Task SaveAsync(UserSettings userSettings, CancellationToken cancellationToken) 27 | { 28 | await File.WriteAllTextAsync( 29 | await FilePath(cancellationToken), 30 | JsonSerializer.Serialize(userSettings), 31 | cancellationToken); 32 | } 33 | 34 | private async Task FilePath(CancellationToken cancellationToken) 35 | { 36 | var path = HybridSupport.IsElectronActive 37 | ? await Electron.App.GetPathAsync(PathName.UserData, cancellationToken) : 38 | Directory.GetCurrentDirectory(); 39 | 40 | return Path.Combine( 41 | path, 42 | FileName); 43 | } 44 | } -------------------------------------------------------------------------------- /src/Ui/Website.Host/ManagementStorage.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | using System.Text.Json; 3 | using CrossBusExplorer.Management; 4 | using CrossBusExplorer.Management.Contracts; 5 | using ElectronSharp.API; 6 | using ElectronSharp.API.Entities; 7 | namespace Website.Host; 8 | 9 | public class ManagementStorage : IManagementStorage 10 | { 11 | private const string ServiceBusConnectionsFileName = "cross_bus_explorer_connections.json"; 12 | 13 | public async Task StoreAsync( 14 | IDictionary connections, 15 | CancellationToken cancellationToken) 16 | { 17 | await File.WriteAllTextAsync( 18 | await FilePath(cancellationToken), 19 | JsonSerializer.Serialize(connections), 20 | Encoding.UTF8, 21 | cancellationToken); 22 | } 23 | 24 | public async Task> ReadAsync( 25 | CancellationToken cancellationToken) 26 | { 27 | var path = await FilePath(cancellationToken); 28 | 29 | if (File.Exists(Path.Combine(path))) 30 | { 31 | var serializedData = await File.ReadAllTextAsync(path, cancellationToken); 32 | 33 | return JsonSerializer.Deserialize>( 34 | serializedData) ?? new Dictionary(); 35 | } 36 | 37 | return new Dictionary(); 38 | } 39 | 40 | private async Task FilePath(CancellationToken cancellationToken) 41 | { 42 | var path = HybridSupport.IsElectronActive 43 | ? await Electron.App.GetPathAsync(PathName.UserData, cancellationToken) : 44 | Directory.GetCurrentDirectory(); 45 | 46 | return Path.Combine( 47 | path, 48 | ServiceBusConnectionsFileName); 49 | } 50 | } -------------------------------------------------------------------------------- /src/Ui/Website.Host/Pages/Error.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model Website.Host.Pages.ErrorModel 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Error 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |

Error.

19 |

An error occurred while processing your request.

20 | 21 | @if (Model.ShowRequestId) 22 | { 23 |

24 | Request ID: @Model.RequestId 25 |

26 | } 27 | 28 |

Development Mode

29 |

30 | Swapping to the Development environment displays detailed information about the error that occurred. 31 |

32 |

33 | The Development environment shouldn't be enabled for deployed applications. 34 | It can result in displaying sensitive information from exceptions to end users. 35 | For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development 36 | and restarting the app. 37 |

38 |
39 |
40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /src/Ui/Website.Host/Pages/Error.cshtml.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using Microsoft.AspNetCore.Mvc.RazorPages; 3 | using System.Diagnostics; 4 | 5 | namespace Website.Host.Pages 6 | { 7 | [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] 8 | [IgnoreAntiforgeryToken] 9 | public class ErrorModel : PageModel 10 | { 11 | public string? RequestId { get; set; } 12 | 13 | public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); 14 | 15 | private readonly ILogger _logger; 16 | 17 | public ErrorModel(ILogger logger) 18 | { 19 | _logger = logger; 20 | } 21 | 22 | public void OnGet() 23 | { 24 | RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Ui/Website.Host/Pages/_Host.cshtml: -------------------------------------------------------------------------------- 1 | @page "/" 2 | @namespace Website.Host.Pages 3 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 4 | @{ 5 | Layout = "_Layout"; 6 | } 7 | 8 | -------------------------------------------------------------------------------- /src/Ui/Website.Host/Pages/_Layout.cshtml: -------------------------------------------------------------------------------- 1 | @using Microsoft.AspNetCore.Components.Web 2 | @namespace Website.Host.Pages 3 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | @RenderBody() 17 | 18 |
19 | 20 | An error has occurred. This application may no longer respond until reloaded. 21 | 22 | 23 | An unhandled exception has occurred. See browser dev tools for details. 24 | 25 | Reload 26 | 🗙 27 |
28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/Ui/Website.Host/Program.cs: -------------------------------------------------------------------------------- 1 | using CrossBusExplorer.Management; 2 | using CrossBusExplorer.ServiceBus; 3 | using CrossBusExplorer.Website; 4 | using ElectronSharp.API; 5 | using ElectronSharp.API.Entities; 6 | using Microsoft.AspNetCore.Hosting.StaticWebAssets; 7 | using Website.Host; 8 | 9 | var builder = WebApplication.CreateBuilder(args); 10 | 11 | StaticWebAssetsLoader.UseStaticWebAssets(builder.Environment, builder.Configuration); 12 | 13 | builder.Services.AddRazorPages(); 14 | builder.Services.AddServerSideBlazor(); 15 | builder.Services.AddWebsiteServices(); 16 | builder.Services.AddServiceBusServices(); 17 | builder.Services.AddManagement(); 18 | 19 | builder.Services.AddScoped(); 20 | builder.Services.AddScoped(); 21 | 22 | builder.Services.AddElectron(); 23 | builder.WebHost.UseElectron(args); 24 | 25 | var app = builder.Build(); 26 | 27 | app.UseStaticFiles(); 28 | 29 | app.UseRouting(); 30 | 31 | app.MapBlazorHub(); 32 | app.MapFallbackToPage("/_Host"); 33 | 34 | Task.Run(async () => 35 | { 36 | Electron.ReadAuth(); 37 | await Task.Delay(500); 38 | 39 | var browserWindow = await Electron.WindowManager.CreateWindowAsync( 40 | new BrowserWindowOptions 41 | { 42 | ZoomToPageWidth = true, 43 | WebPreferences = new WebPreferences 44 | { 45 | ZoomFactor = 1 46 | }, 47 | Icon = "../../../icon512x512.png" 48 | }); 49 | 50 | browserWindow.OnClose += () => app.StopAsync(); 51 | browserWindow.OnReadyToShow += () => browserWindow.Show(); 52 | }); 53 | 54 | app.Run(); -------------------------------------------------------------------------------- /src/Ui/Website.Host/Website.Host.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | net8.0 4 | enable 5 | enable 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | PreserveNewest 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/Ui/Website.Host/_Imports.razor: -------------------------------------------------------------------------------- 1 | @using System.Net.Http 2 | @using Microsoft.AspNetCore.Authorization 3 | @using Microsoft.AspNetCore.Components.Authorization 4 | @using Microsoft.AspNetCore.Components.Forms 5 | @using Microsoft.AspNetCore.Components.Routing 6 | @using Microsoft.AspNetCore.Components.Web 7 | @using Microsoft.AspNetCore.Components.Web.Virtualization 8 | @using Microsoft.JSInterop 9 | @using MudBlazor 10 | @using Website.Host 11 | -------------------------------------------------------------------------------- /src/Ui/Website.Host/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "DetailedErrors": true, 3 | "Logging": { 4 | "LogLevel": { 5 | "Default": "Information", 6 | "Microsoft": "Warning", 7 | "Microsoft.Hosting.Lifetime": "Information" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Ui/Website.Host/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | }, 9 | "AllowedHosts": "*" 10 | } 11 | -------------------------------------------------------------------------------- /src/Ui/Website.Host/build/entitlements.mac.inherit.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.cs.allow-jit 6 | 7 | com.apple.security.cs.allow-unsigned-executable-memory 8 | 9 | com.apple.security.cs.allow-dyld-environment-variables 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/Ui/Website.Host/build/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carael/CrossBusExplorer/c965c80e011bdc17a19405e063d226606f59ceba/src/Ui/Website.Host/build/icon.png -------------------------------------------------------------------------------- /src/Ui/Website.Host/build/icon512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carael/CrossBusExplorer/c965c80e011bdc17a19405e063d226606f59ceba/src/Ui/Website.Host/build/icon512x512.png -------------------------------------------------------------------------------- /src/Ui/Website.Host/electron.manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "executable": "Website.Host", 3 | "splashscreen": { 4 | "imageFile": "" 5 | }, 6 | "name": "CrossBusExplorer", 7 | "author": "Mariusz Matysek", 8 | "singleInstance": false, 9 | "environment": "Production", 10 | "description": "Cross Bus Explorer", 11 | "aspCoreBackendPort": 8010, 12 | "build": { 13 | "appId": "com.crossbusexplorer.app", 14 | "productName": "Cross Bus Explorer", 15 | "copyright": "Copyright © 2024", 16 | "buildVersion": "0.4.11", 17 | "compression": "maximum", 18 | "directories": { 19 | "output": "../../../bin/Desktop" 20 | }, 21 | "extraResources": [ 22 | { 23 | "from": "./bin", 24 | "to": "bin", 25 | "filter": ["**/*"] 26 | } 27 | ], 28 | "files": [ 29 | { 30 | "from": "./ElectronHostHook/node_modules", 31 | "to": "ElectronHostHook/node_modules", 32 | "filter": ["**/*"] 33 | }, 34 | "**/*" 35 | ], 36 | "win": { 37 | "icon": "../../../build/icon.png" 38 | }, 39 | "linux": { 40 | "icon": "../../../build/icon.png" 41 | }, 42 | "mac": { 43 | "icon": "../../../build/icon512x512.png" 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Ui/Website.Host/wwwroot/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carael/CrossBusExplorer/c965c80e011bdc17a19405e063d226606f59ceba/src/Ui/Website.Host/wwwroot/favicon.ico -------------------------------------------------------------------------------- /src/Ui/Website/App.razor: -------------------------------------------------------------------------------- 1 | @using CrossBusExplorer.Website.Shared 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |

Sorry, there's nothing at this address.

10 |
11 |
12 |
-------------------------------------------------------------------------------- /src/Ui/Website/Exceptions/ConverterException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | namespace CrossBusExplorer.Website.Exceptions; 3 | 4 | public class ConverterException : Exception 5 | { 6 | public ConverterException(string message):base(message){} 7 | } -------------------------------------------------------------------------------- /src/Ui/Website/Exceptions/FolderSettingsForConnectionNotFoundException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | namespace CrossBusExplorer.Website.Exceptions; 3 | 4 | public class FolderSettingsForConnectionNotFoundException : Exception 5 | { 6 | public FolderSettingsForConnectionNotFoundException(string connectionName) 7 | : base($"Folder settings for {connectionName} was not found.") 8 | { 9 | 10 | } 11 | } -------------------------------------------------------------------------------- /src/Ui/Website/Extensions/DateTimeExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | namespace CrossBusExplorer.Website.Extensions; 3 | 4 | public static class DateTimeExtensions 5 | { 6 | public static string ToUniversal(this DateTimeOffset? value) 7 | { 8 | if (value != null && value != DateTimeOffset.MinValue && value != DateTimeOffset.MaxValue) 9 | { 10 | return value.Value.ToString("u"); 11 | } 12 | 13 | return "-"; 14 | } 15 | 16 | public static string ToUniversal(this DateTimeOffset value) 17 | { 18 | if (value != DateTimeOffset.MinValue && value != DateTimeOffset.MaxValue) 19 | { 20 | return value.ToString("u"); 21 | } 22 | 23 | return "-"; 24 | } 25 | } -------------------------------------------------------------------------------- /src/Ui/Website/Extensions/IListExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | namespace CrossBusExplorer.Website.Extensions; 5 | 6 | public static class IListExtensions 7 | { 8 | public static void AddOrReplace(this IList list, Func func, T item) 9 | { 10 | var listItem = list.FirstOrDefault(func); 11 | if (listItem != null) 12 | { 13 | list[list.IndexOf(listItem)] = item; 14 | } 15 | else 16 | { 17 | list.Add(item); 18 | } 19 | } 20 | 21 | public static void RemoveNonExisting(this IList list, Func func) 22 | { 23 | var nonExistingItems = list.Where(func).ToArray(); 24 | 25 | for (var i = 0; i < nonExistingItems.Length; i++) 26 | { 27 | list.Remove(nonExistingItems[i]); 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /src/Ui/Website/Extensions/INotifyPropertyChangedExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Runtime.CompilerServices; 3 | namespace CrossBusExplorer.Website.Extensions; 4 | //source: http://www.blackwasp.co.uk/INotifyPropertyChangedExt.aspx 5 | 6 | public static class INotifyPropertyChangedExtensions 7 | { 8 | public static void Notify( 9 | this INotifyPropertyChanged sender, 10 | PropertyChangedEventHandler handler, 11 | [CallerMemberName] string propertyName = "") 12 | { 13 | if (handler != null) 14 | { 15 | PropertyChangedEventArgs args = new PropertyChangedEventArgs(propertyName); 16 | handler(sender, args); 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /src/Ui/Website/Extensions/StringExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Newtonsoft.Json; 4 | namespace CrossBusExplorer.Website.Extensions; 5 | 6 | public static class StringExtensions 7 | { 8 | public static bool EqualsInvariantIgnoreCase(this string? value, string value2) 9 | { 10 | if (value == null && value2 == null) 11 | { 12 | return true; 13 | } 14 | 15 | if (value == null && value2 != null) 16 | { 17 | return false; 18 | } 19 | 20 | return value.Equals(value2, StringComparison.InvariantCultureIgnoreCase); 21 | } 22 | 23 | 24 | public static TimeSpan? ToTimeSpan(this string? value) 25 | { 26 | return value != null ? TimeSpan.Parse(value) : null; 27 | } 28 | 29 | public static string TryFormatBody(this string value, string? contentType) 30 | { 31 | if (contentType != null) 32 | { 33 | return contentType.Contains("json", StringComparison.InvariantCultureIgnoreCase) 34 | ? TryFormatJson(value) 35 | : value; 36 | } 37 | 38 | return TryFormatJson(value); 39 | } 40 | 41 | public static string SplitAndGetLastSection(this string value, char split) 42 | { 43 | if (value.Contains(split)) 44 | { 45 | return value.Split(split).Last(); 46 | } 47 | 48 | return value; 49 | } 50 | 51 | private static string TryFormatJson(string value) 52 | { 53 | try 54 | { 55 | dynamic parsedJson = JsonConvert.DeserializeObject(value); 56 | return JsonConvert.SerializeObject(parsedJson, Formatting.Indented); 57 | } 58 | catch 59 | { 60 | return value; 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/Ui/Website/Extensions/TimeSpanExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | namespace CrossBusExplorer.Website.Extensions; 3 | 4 | public static class TimeSpanExtensions 5 | { 6 | public static string ToTimeSpanString(this TimeSpan timeSpan) 7 | => timeSpan.ToString(@"ddd\.hh\:mm\:ss"); 8 | } -------------------------------------------------------------------------------- /src/Ui/Website/FluentValidator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using FluentValidation; 5 | namespace CrossBusExplorer.Website; 6 | 7 | /// 8 | /// A glue class to make it easy to define validation rules for single values using FluentValidation 9 | /// You can reuse this class for all your fields, like for the credit card rules above. 10 | /// 11 | /// 12 | public class FluentValueValidator : AbstractValidator 13 | { 14 | public FluentValueValidator(Action> rule) 15 | { 16 | rule(RuleFor(x => x)); 17 | } 18 | 19 | private IEnumerable ValidateValue(T arg) 20 | { 21 | var result = Validate(arg); 22 | if (result.IsValid) 23 | return new string[0]; 24 | return result.Errors.Select(e => e.ErrorMessage); 25 | } 26 | 27 | public Func> Validation => ValidateValue; 28 | } -------------------------------------------------------------------------------- /src/Ui/Website/ISettingsService.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using System.Threading.Tasks; 3 | using CrossBusExplorer.Website.Models; 4 | namespace CrossBusExplorer.Website; 5 | 6 | public interface ISettingsService 7 | { 8 | Task GetAsync(CancellationToken cancellationToken); 9 | Task SaveAsync(UserSettings userSettings, CancellationToken cancellationToken); 10 | } -------------------------------------------------------------------------------- /src/Ui/Website/Jobs/DeleteMessageJob.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | using CrossBusExplorer.ServiceBus.Contracts; 6 | using CrossBusExplorer.ServiceBus.Contracts.Types; 7 | using CrossBusExplorer.Website.Extensions; 8 | using MudBlazor; 9 | namespace CrossBusExplorer.Website.Jobs; 10 | 11 | public class DeleteMessageJob : IJob 12 | { 13 | private readonly string _connectionName; 14 | private readonly string _queueOrTopicName; 15 | private readonly string? _subscriptionName; 16 | private readonly SubQueue _subQueue; 17 | private readonly long _sequenceNumber; 18 | private readonly IMessageService _messageService; 19 | private readonly ISnackbar _snackbar; 20 | private readonly CancellationTokenSource _cancellationTokenSource; 21 | 22 | public event PropertyChangedEventHandler? PropertyChanged; 23 | 24 | public event JobCompletedEventHandler? OnCompleted; 25 | 26 | public DeleteMessageJob( 27 | string connectionName, 28 | string queueOrTopicName, 29 | string? subscriptionName, 30 | SubQueue subQueue, 31 | long sequenceNumber, 32 | IMessageService messageService) 33 | { 34 | _connectionName = connectionName; 35 | _queueOrTopicName = queueOrTopicName; 36 | _subscriptionName = subscriptionName; 37 | _subQueue = subQueue; 38 | _sequenceNumber = sequenceNumber; 39 | 40 | _messageService = messageService; 41 | _cancellationTokenSource = new CancellationTokenSource(); 42 | } 43 | 44 | private int _progress; 45 | public int Progress 46 | { 47 | get => _progress; 48 | private set 49 | { 50 | _progress = value; 51 | this.Notify(PropertyChanged); 52 | } 53 | } 54 | 55 | public string Name => 56 | $"Delete message {_sequenceNumber} from {_queueOrTopicName} {_subscriptionName}".Trim(); 57 | 58 | public bool ViewDetails { get; set; } 59 | 60 | private JobStatus _status; 61 | public JobStatus Status 62 | { 63 | get => _status; 64 | private set 65 | { 66 | _status = value; 67 | this.Notify(PropertyChanged); 68 | } 69 | } 70 | public string? ErrorMessage { get; private set; } 71 | public string? WarningMessage { get; private set; } 72 | 73 | public async Task ExecuteAsync() 74 | { 75 | Status = JobStatus.Running; 76 | 77 | try 78 | { 79 | Result result = await _messageService.DeleteMessage( 80 | _connectionName, 81 | _queueOrTopicName, 82 | _subscriptionName, 83 | _subQueue, 84 | _sequenceNumber, 85 | _cancellationTokenSource.Token); 86 | 87 | Progress = JobsHelper.GetProgress(1, result.Count); 88 | 89 | Status = JobStatus.Succeeded; 90 | 91 | if (result.Count == 0) 92 | { 93 | WarningMessage = "Message was not not deleted"; 94 | } 95 | } 96 | catch (TaskCanceledException) 97 | { 98 | Status = JobStatus.Cancelled; 99 | } 100 | catch (Exception ex) 101 | { 102 | ErrorMessage = $"Job {Name} failed. Error: {ex.Message}."; 103 | Status = JobStatus.Failed; 104 | } 105 | 106 | await OnCompleted(_connectionName, _queueOrTopicName, _subscriptionName); 107 | } 108 | 109 | public void Cancel() 110 | { 111 | _cancellationTokenSource.Cancel(); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/Ui/Website/Jobs/IJob.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Threading.Tasks; 3 | namespace CrossBusExplorer.Website.Jobs; 4 | 5 | public interface IJob : INotifyPropertyChanged 6 | { 7 | public event JobCompletedEventHandler? OnCompleted; 8 | int Progress { get; } 9 | Task ExecuteAsync(); 10 | void Cancel(); 11 | string Name { get; } 12 | bool ViewDetails { get; set; } 13 | JobStatus Status { get; } 14 | string? ErrorMessage { get; } 15 | } -------------------------------------------------------------------------------- /src/Ui/Website/Jobs/JobCompletedEventHandler.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | namespace CrossBusExplorer.Website.Jobs; 3 | 4 | public delegate Task JobCompletedEventHandler( 5 | string connectionName, 6 | string queueOrTopicName, 7 | string? subscriptionName); -------------------------------------------------------------------------------- /src/Ui/Website/Jobs/JobStatus.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.Website.Jobs; 2 | 3 | public enum JobStatus 4 | { 5 | Running, 6 | Succeeded, 7 | Failed, 8 | Cancelled 9 | } -------------------------------------------------------------------------------- /src/Ui/Website/Jobs/JobsHelper.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.Website.Jobs; 2 | 3 | public static class JobsHelper 4 | { 5 | public static int GetProgress(long totalCount, long purgedCount) => 6 | (int)((float)purgedCount / totalCount * 100); 7 | } -------------------------------------------------------------------------------- /src/Ui/Website/Jobs/PurgeMessagesJob.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | using CrossBusExplorer.ServiceBus.Contracts; 6 | using CrossBusExplorer.ServiceBus.Contracts.Types; 7 | using CrossBusExplorer.Website.Extensions; 8 | using MudBlazor; 9 | namespace CrossBusExplorer.Website.Jobs; 10 | 11 | public class PurgeMessagesJob : IJob 12 | { 13 | private readonly string _connectionName; 14 | private readonly string _queueOrTopicName; 15 | private readonly string? _subscriptionName; 16 | private readonly SubQueue _subQueue; 17 | private readonly long _totalCount; 18 | private readonly IMessageService _messageService; 19 | private readonly ISnackbar _snackbar; 20 | private readonly CancellationTokenSource _cancellationTokenSource; 21 | 22 | public event PropertyChangedEventHandler? PropertyChanged; 23 | 24 | public event JobCompletedEventHandler? OnCompleted; 25 | 26 | public PurgeMessagesJob( 27 | string connectionName, 28 | string queueOrTopicName, 29 | string? subscriptionName, 30 | SubQueue subQueue, 31 | long totalCount, 32 | IMessageService messageService) 33 | { 34 | _connectionName = connectionName; 35 | _queueOrTopicName = queueOrTopicName; 36 | _subscriptionName = subscriptionName; 37 | _subQueue = subQueue; 38 | _totalCount = totalCount; 39 | _messageService = messageService; 40 | _cancellationTokenSource = new CancellationTokenSource(); 41 | } 42 | 43 | private int _progress; 44 | public int Progress 45 | { 46 | get => _progress; 47 | private set 48 | { 49 | _progress = value; 50 | this.Notify(PropertyChanged); 51 | } 52 | } 53 | 54 | public string Name => 55 | $"Purge messages from {_queueOrTopicName} {_subscriptionName}".Trim(); 56 | 57 | public bool ViewDetails { get; set; } 58 | 59 | private JobStatus _status; 60 | public JobStatus Status 61 | { 62 | get => _status; 63 | private set 64 | { 65 | _status = value; 66 | this.Notify(PropertyChanged); 67 | } 68 | } 69 | public string? ErrorMessage { get; private set; } 70 | 71 | public async Task ExecuteAsync() 72 | { 73 | Status = JobStatus.Running; 74 | 75 | try 76 | { 77 | await foreach (var result in _messageService.PurgeAsync( 78 | _connectionName, 79 | _queueOrTopicName, 80 | _subscriptionName, 81 | _subQueue, 82 | _totalCount, 83 | _cancellationTokenSource.Token)) 84 | { 85 | Progress = JobsHelper.GetProgress(_totalCount, result.PurgedCount); 86 | } 87 | 88 | Status = JobStatus.Succeeded; 89 | } 90 | catch (TaskCanceledException) 91 | { 92 | Status = JobStatus.Cancelled; 93 | } 94 | catch (Exception ex) 95 | { 96 | ErrorMessage = $"Job {Name} failed. Error: {ex.Message}."; 97 | Status = JobStatus.Failed; 98 | } 99 | 100 | await OnCompleted(_connectionName, _queueOrTopicName, _subscriptionName); 101 | } 102 | 103 | public void Cancel() 104 | { 105 | _cancellationTokenSource.Cancel(); 106 | } 107 | } -------------------------------------------------------------------------------- /src/Ui/Website/Jobs/ResendMessagesJob.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | using CrossBusExplorer.ServiceBus.Contracts; 6 | using CrossBusExplorer.ServiceBus.Contracts.Types; 7 | using CrossBusExplorer.Website.Extensions; 8 | namespace CrossBusExplorer.Website.Jobs; 9 | 10 | public class ResendMessagesJob : IJob 11 | { 12 | private readonly string _connectionName; 13 | private readonly string _queueOrTopicName; 14 | private readonly string? _subscriptionName; 15 | private readonly SubQueue _subQueue; 16 | private readonly string _destinationTopicOrQueueName; 17 | private readonly long _totalCount; 18 | private readonly IMessageService _messageService; 19 | private readonly CancellationTokenSource _cancellationTokenSource; 20 | 21 | public event JobCompletedEventHandler? OnCompleted; 22 | public event PropertyChangedEventHandler? PropertyChanged; 23 | 24 | public ResendMessagesJob( 25 | string connectionName, 26 | string queueOrTopicName, 27 | string? subscriptionName, 28 | SubQueue subQueue, 29 | string destinationTopicOrQueueName, 30 | long totalCount, 31 | IMessageService messageService) 32 | { 33 | _connectionName = connectionName; 34 | _queueOrTopicName = queueOrTopicName; 35 | _subscriptionName = subscriptionName; 36 | _subQueue = subQueue; 37 | _destinationTopicOrQueueName = destinationTopicOrQueueName; 38 | _totalCount = totalCount; 39 | _messageService = messageService; 40 | _cancellationTokenSource = new CancellationTokenSource(); 41 | } 42 | 43 | private int _progress; 44 | public int Progress 45 | { 46 | get => _progress; 47 | private set 48 | { 49 | _progress = value; 50 | this.Notify(PropertyChanged); 51 | } 52 | } 53 | public async Task ExecuteAsync() 54 | { 55 | Status = JobStatus.Running; 56 | 57 | try 58 | { 59 | await foreach (var result in _messageService.ResendAsync( 60 | _connectionName, 61 | _queueOrTopicName, 62 | _subscriptionName, 63 | _subQueue, 64 | _destinationTopicOrQueueName, 65 | _totalCount, 66 | _cancellationTokenSource.Token)) 67 | { 68 | Progress = JobsHelper.GetProgress(_totalCount, result.ResendCount); 69 | } 70 | 71 | Status = JobStatus.Succeeded; 72 | } 73 | catch (TaskCanceledException) 74 | { 75 | Status = JobStatus.Cancelled; 76 | } 77 | catch (Exception ex) 78 | { 79 | ErrorMessage = $"Job {Name} failed. Error: {ex.Message}."; 80 | Status = JobStatus.Failed; 81 | } 82 | 83 | await OnCompleted(_connectionName, _queueOrTopicName, _subscriptionName); 84 | } 85 | 86 | private JobStatus _status; 87 | public JobStatus Status 88 | { 89 | get => _status; 90 | private set 91 | { 92 | _status = value; 93 | this.Notify(PropertyChanged); 94 | } 95 | } 96 | public string? ErrorMessage { get; private set; } 97 | 98 | public void Cancel() 99 | { 100 | _cancellationTokenSource.Cancel(); 101 | } 102 | 103 | public string Name => 104 | $"Resend messages from {_queueOrTopicName} {_subscriptionName} " + 105 | $"to {_destinationTopicOrQueueName}.".Trim(); 106 | 107 | public bool ViewDetails { get; set; } 108 | } -------------------------------------------------------------------------------- /src/Ui/Website/Mappings/MessageMappings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Collections.ObjectModel; 4 | using System.Linq; 5 | using CrossBusExplorer.ServiceBus.Contracts.Types; 6 | using CrossBusExplorer.ServiceBus.Extensions; 7 | using CrossBusExplorer.Website.Extensions; 8 | using CrossBusExplorer.Website.Models; 9 | namespace CrossBusExplorer.Website.Mappings; 10 | 11 | public static class MessageMappings 12 | { 13 | public static SendMessage ToSendMessage(this MessageDetailsModel message) => 14 | new SendMessage( 15 | message.Body.TryFormatBody(message.ContentType), 16 | message.Subject, 17 | message.To, 18 | message.ContentType, 19 | message.CorrelationId, 20 | message.Id, 21 | message.PartitionKey, 22 | message.ReplyTo, 23 | message.SessionId, 24 | message.ScheduledEnqueueTime, 25 | message.TimeToLive, 26 | message.ApplicationProperties 27 | .ToDictionary(p => p.Key, p => p.Value.GetApplicationPropertyValue(p.Type))); 28 | 29 | public static MessageDetailsModel ToSendMessageModel(this Message message) => 30 | new MessageDetailsModel 31 | { 32 | Body = message.Body.TryFormatBody(message.SystemProperties.ContentType), 33 | Subject = message.Subject, 34 | To = message.SystemProperties.To, 35 | ContentType = message.SystemProperties.ContentType, 36 | CorrelationId = message.SystemProperties.CorrelationId, 37 | Id = message.Id, 38 | PartitionKey = message.SystemProperties.PartitionKey, 39 | ReplyTo = message.SystemProperties.ReplyTo, 40 | SessionId = message.SystemProperties.SessionId, 41 | ScheduledEnqueueTime = 42 | message.SystemProperties.ScheduledEnqueueTime == DateTimeOffset.MinValue ? null 43 | : message.SystemProperties.ScheduledEnqueueTime, 44 | TimeToLive = message.SystemProperties.TimeToLive, 45 | ApplicationProperties = 46 | new ObservableCollection( 47 | message.ApplicationProperties?.Select(p => 48 | new KeyValueTypePair 49 | { 50 | Key = p.Key, 51 | Value = p.Value?.ToString() ?? null, 52 | Type = p.Value.GetApplicationPropertyType() 53 | }).ToList() ?? new List()) 54 | }; 55 | } 56 | -------------------------------------------------------------------------------- /src/Ui/Website/Mappings/QueueMappings.cs: -------------------------------------------------------------------------------- 1 | using CrossBusExplorer.ServiceBus.Contracts.Types; 2 | using CrossBusExplorer.Website.Extensions; 3 | using CrossBusExplorer.Website.Models; 4 | using CrossBusExplorer.Website.Pages; 5 | namespace CrossBusExplorer.Website.Mappings; 6 | 7 | public static class QueueMappings 8 | { 9 | public static QueueFormModel ToFormModel(this QueueDetails details, OperationType operationType) 10 | { 11 | return new QueueFormModel(operationType) 12 | { 13 | Name = operationType == OperationType.Update ? details.Info.Name : null, 14 | MaxSizeInMegabytes = details.Properties.MaxQueueSizeInMegabytes, 15 | MaxDeliveryCount = details.Properties.MaxDeliveryCount, 16 | UserMetadata = details.Properties.UserMetadata, 17 | ForwardTo = details.Properties.ForwardTo, 18 | ForwardDeadLetteredMessagesTo = details.Properties.ForwardDeadLetteredMessagesTo, 19 | DuplicateDetectionHistoryTimeWindow = details.TimeSettings 20 | .DuplicateDetectionHistoryTimeWindow, 21 | AutoDeleteOnIdle = details.TimeSettings.AutoDeleteOnIdle, 22 | DefaultMessageTimeToLive = 23 | details.TimeSettings.DefaultMessageTimeToLive, 24 | LockDuration = details.TimeSettings.LockDuration, 25 | RequiresSession = details.Settings.RequiresSession, 26 | DeadLetteringOnMessageExpiration = 27 | details.Settings.EnableDeadLetteringOnMessageExpiration, 28 | EnableBatchedOperations = details.Settings.EnableBatchedOperations, 29 | RequiresDuplicateDetection = details.Settings.RequiresDuplicateDetection, 30 | EnablePartitioning = details.Settings.EnablePartitioning, 31 | MaxMessageSizeInKilobytes = details.Properties.MaxMessageSizeInKilobytes 32 | }; 33 | } 34 | 35 | public static UpdateQueueOptions ToUpdateOptions(this QueueFormModel model) 36 | { 37 | return new UpdateQueueOptions( 38 | model.Name!, 39 | AuthorizationRules: null, 40 | MaxSizeInMegabytes: model.MaxSizeInMegabytes, 41 | LockDuration: model.LockDuration, 42 | RequiresSession: model.RequiresSession, 43 | DefaultMessageTimeToLive: model.DefaultMessageTimeToLive, 44 | AutoDeleteOnIdle: model.AutoDeleteOnIdle, 45 | DeadLetteringOnMessageExpiration: model.DeadLetteringOnMessageExpiration, 46 | DuplicateDetectionHistoryTimeWindow: model.DuplicateDetectionHistoryTimeWindow, 47 | MaxDeliveryCount: model.MaxDeliveryCount, 48 | EnableBatchedOperations: model.EnableBatchedOperations, 49 | Status: null, 50 | ForwardTo: model.ForwardTo, 51 | ForwardDeadLetteredMessagesTo: model.ForwardDeadLetteredMessagesTo, 52 | MaxMessageSizeInKilobytes: model.MaxMessageSizeInKilobytes, 53 | UserMetadata: model.UserMetadata); 54 | } 55 | 56 | public static CreateQueueOptions ToCreateOptions(this QueueFormModel model) 57 | { 58 | return new CreateQueueOptions( 59 | model.Name!, 60 | AuthorizationRules: null, 61 | MaxSizeInMegabytes: model.MaxSizeInMegabytes, 62 | LockDuration: model.LockDuration, 63 | RequiresSession: model.RequiresSession, 64 | DefaultMessageTimeToLive: model.DefaultMessageTimeToLive, 65 | AutoDeleteOnIdle: model.AutoDeleteOnIdle, 66 | DeadLetteringOnMessageExpiration: model.DeadLetteringOnMessageExpiration, 67 | DuplicateDetectionHistoryTimeWindow: model.DuplicateDetectionHistoryTimeWindow, 68 | MaxDeliveryCount: model.MaxDeliveryCount, 69 | EnableBatchedOperations: model.EnableBatchedOperations, 70 | Status: null, 71 | ForwardTo: model.ForwardTo, 72 | ForwardDeadLetteredMessagesTo: model.ForwardDeadLetteredMessagesTo, 73 | MaxMessageSizeInKilobytes: model.MaxMessageSizeInKilobytes, 74 | UserMetadata: model.UserMetadata, 75 | RequiresDuplicateDetection: model.RequiresDuplicateDetection, 76 | EnablePartitioning: model.EnablePartitioning); 77 | } 78 | } -------------------------------------------------------------------------------- /src/Ui/Website/Mappings/SubscriptionMappings.cs: -------------------------------------------------------------------------------- 1 | using Azure.Core; 2 | using CrossBusExplorer.ServiceBus.Contracts.Types; 3 | using CrossBusExplorer.Website.Extensions; 4 | using CrossBusExplorer.Website.Models; 5 | using CrossBusExplorer.Website.Pages; 6 | namespace CrossBusExplorer.Website.Mappings; 7 | 8 | public static class SubscriptionMappings 9 | { 10 | public static SubscriptionFormModel ToFormModel(this SubscriptionDetails details, 11 | OperationType operationType) 12 | { 13 | return new SubscriptionFormModel(operationType) 14 | { 15 | TopicName = details.Info.TopicName, 16 | SubscriptionName = operationType == OperationType.Update ? details.Info.SubscriptionName 17 | : null, 18 | MaxDeliveryCount = details.Properties.MaxDeliveryCount, 19 | UserMetadata = details.Properties.UserMetadata, 20 | ForwardTo = details.Properties.ForwardTo, 21 | ForwardDeadLetteredMessagesTo = details.Properties.ForwardDeadLetteredMessagesTo, 22 | AutoDeleteOnIdle = details.TimeSettings.AutoDeleteOnIdle, 23 | DefaultMessageTimeToLive = 24 | details.TimeSettings.DefaultMessageTimeToLive, 25 | LockDuration = details.TimeSettings.LockDuration, 26 | RequiresSession = details.Settings.RequiresSession, 27 | DeadLetteringOnMessageExpiration = 28 | details.Settings.EnableDeadLetteringOnMessageExpiration, 29 | EnableBatchedOperations = details.Settings.EnableBatchedOperations, 30 | EnableDeadLetteringOnFilterEvaluationExceptions = 31 | details.Settings.EnableDeadLetteringOnFilterEvaluationExceptions 32 | }; 33 | } 34 | 35 | public static UpdateSubscriptionOptions ToUpdateOptions(this SubscriptionFormModel model) 36 | { 37 | return new UpdateSubscriptionOptions( 38 | model.TopicName!, 39 | model.SubscriptionName, 40 | LockDuration: model.LockDuration, 41 | RequiresSession: model.RequiresSession, 42 | DefaultMessageTimeToLive: model.DefaultMessageTimeToLive, 43 | AutoDeleteOnIdle: model.AutoDeleteOnIdle, 44 | DeadLetteringOnMessageExpiration: model.DeadLetteringOnMessageExpiration, 45 | MaxDeliveryCount: model.MaxDeliveryCount, 46 | EnableBatchedOperations: model.EnableBatchedOperations, 47 | Status: null, 48 | ForwardTo: model.ForwardTo, 49 | ForwardDeadLetteredMessagesTo: model.ForwardDeadLetteredMessagesTo, 50 | UserMetadata: model.UserMetadata); 51 | } 52 | 53 | public static CreateSubscriptionOptions ToCreateOptions(this SubscriptionFormModel model) 54 | { 55 | return new CreateSubscriptionOptions( 56 | model.TopicName, 57 | model.SubscriptionName, 58 | LockDuration: model.LockDuration, 59 | RequiresSession: model.RequiresSession, 60 | DefaultMessageTimeToLive: model.DefaultMessageTimeToLive, 61 | AutoDeleteOnIdle: model.AutoDeleteOnIdle, 62 | DeadLetteringOnMessageExpiration: model.DeadLetteringOnMessageExpiration, 63 | EnableDeadLetteringOnFilterEvaluationExceptions: 64 | model.EnableDeadLetteringOnFilterEvaluationExceptions, 65 | MaxDeliveryCount: model.MaxDeliveryCount, 66 | EnableBatchedOperations: model.EnableBatchedOperations, 67 | Status: null, 68 | ForwardTo: model.ForwardTo, 69 | ForwardDeadLetteredMessagesTo: model.ForwardDeadLetteredMessagesTo, 70 | UserMetadata: model.UserMetadata); 71 | } 72 | } -------------------------------------------------------------------------------- /src/Ui/Website/Mappings/TopicMappings.cs: -------------------------------------------------------------------------------- 1 | using CrossBusExplorer.ServiceBus.Contracts.Types; 2 | using CrossBusExplorer.Website.Models; 3 | using CrossBusExplorer.Website.Pages; 4 | namespace CrossBusExplorer.Website.Mappings; 5 | 6 | public static class TopicMappings 7 | { 8 | public static TopicFormModel ToFormModel(this TopicDetails details, OperationType operationType) 9 | { 10 | return new TopicFormModel(operationType) 11 | { 12 | Name = operationType == OperationType.Update ? details.Info.Name : null, 13 | MaxSizeInMegabytes = details.Properties.MaxQueueSizeInMegabytes, 14 | UserMetadata = details.Properties.UserMetadata, 15 | DuplicateDetectionHistoryTimeWindow = details.TimeSettings 16 | .DuplicateDetectionHistoryTimeWindow, 17 | AutoDeleteOnIdle = details.TimeSettings.AutoDeleteOnIdle, 18 | DefaultMessageTimeToLive = 19 | details.TimeSettings.DefaultMessageTimeToLive, 20 | EnableBatchedOperations = details.Settings.EnableBatchedOperations, 21 | RequiresDuplicateDetection = details.Settings.RequiresDuplicateDetection, 22 | EnablePartitioning = details.Settings.EnablePartitioning, 23 | SupportOrdering = details.Settings.SupportOrdering, 24 | MaxMessageSizeInKilobytes = details.Properties.MaxMessageSizeInKilobytes 25 | }; 26 | } 27 | 28 | public static UpdateTopicOptions ToUpdateOptions(this TopicFormModel model) 29 | { 30 | return new UpdateTopicOptions( 31 | model.Name!, 32 | AuthorizationRules: null, 33 | MaxSizeInMegabytes: model.MaxSizeInMegabytes, 34 | DefaultMessageTimeToLive: model.DefaultMessageTimeToLive, 35 | AutoDeleteOnIdle: model.AutoDeleteOnIdle, 36 | DuplicateDetectionHistoryTimeWindow: model.DuplicateDetectionHistoryTimeWindow, 37 | EnableBatchedOperations: model.EnableBatchedOperations, 38 | SupportOrdering: model.SupportOrdering, 39 | Status: null, 40 | MaxMessageSizeInKilobytes: model.MaxMessageSizeInKilobytes, 41 | UserMetadata: model.UserMetadata); 42 | } 43 | 44 | public static CreateTopicOptions ToCreateOptions(this TopicFormModel model) 45 | { 46 | return new CreateTopicOptions( 47 | model.Name!, 48 | AuthorizationRules: null, 49 | MaxSizeInMegabytes: model.MaxSizeInMegabytes, 50 | DefaultMessageTimeToLive: model.DefaultMessageTimeToLive, 51 | AutoDeleteOnIdle: model.AutoDeleteOnIdle, 52 | DuplicateDetectionHistoryTimeWindow: model.DuplicateDetectionHistoryTimeWindow, 53 | EnableBatchedOperations: model.EnableBatchedOperations, 54 | Status: null, 55 | MaxMessageSizeInKilobytes: model.MaxMessageSizeInKilobytes, 56 | UserMetadata: model.UserMetadata, 57 | RequiresDuplicateDetection: model.RequiresDuplicateDetection, 58 | SupportOrdering: model.SupportOrdering, 59 | EnablePartitioning: model.EnablePartitioning); 60 | } 61 | } -------------------------------------------------------------------------------- /src/Ui/Website/Models/ConnectionFolder.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.ObjectModel; 2 | using System.ComponentModel; 3 | using CrossBusExplorer.Website.Extensions; 4 | namespace CrossBusExplorer.Website.Models; 5 | 6 | public class ConnectionFolder : INotifyPropertyChanged 7 | { 8 | public ConnectionFolder(string name) 9 | { 10 | _name = name; 11 | _menuItems = new ObservableCollection(); 12 | _menuItems.CollectionChanged += (_, _) => this.Notify(PropertyChanged); 13 | } 14 | 15 | public event PropertyChangedEventHandler? PropertyChanged; 16 | 17 | private string _name; 18 | public string Name 19 | { 20 | get => _name; 21 | set 22 | { 23 | _name = value; 24 | this.Notify(PropertyChanged); 25 | } 26 | } 27 | 28 | private ObservableCollection _menuItems; 29 | 30 | public ObservableCollection MenuItems 31 | { 32 | get => _menuItems; 33 | private set 34 | { 35 | _menuItems = value; 36 | _menuItems.CollectionChanged += (_, _) => 37 | { 38 | this.Notify(PropertyChanged); 39 | }; 40 | this.Notify(PropertyChanged); 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /src/Ui/Website/Models/ConnectionMenuItem.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.ObjectModel; 2 | using System.ComponentModel; 3 | using CrossBusExplorer.ServiceBus.Contracts.Types; 4 | using CrossBusExplorer.Website.Extensions; 5 | namespace CrossBusExplorer.Website.Models; 6 | 7 | public class ConnectionMenuItem : INotifyPropertyChanged 8 | { 9 | public event PropertyChangedEventHandler? PropertyChanged; 10 | 11 | public ConnectionMenuItem(string connectionName) 12 | { 13 | ConnectionName = connectionName; 14 | Queues = new ObservableCollection(); 15 | Topics = new ObservableCollection(); 16 | } 17 | 18 | public string ConnectionName { get; } 19 | 20 | private ObservableCollection _queues; 21 | public ObservableCollection Queues 22 | { 23 | get => _queues; 24 | private set 25 | { 26 | _queues = value; 27 | _queues.CollectionChanged += (_, _) => 28 | { 29 | this.Notify(PropertyChanged); 30 | }; 31 | this.Notify(PropertyChanged); 32 | } 33 | } 34 | 35 | private ObservableCollection _topics; 36 | public ObservableCollection Topics 37 | { 38 | get => _topics; 39 | private set 40 | { 41 | _topics = value; 42 | _topics.CollectionChanged += (_, _) => 43 | { 44 | this.Notify(PropertyChanged); 45 | }; 46 | this.Notify(PropertyChanged); 47 | } 48 | } 49 | public bool QueuesLoaded { get; set; } 50 | public bool TopicsLoaded { get; set; } 51 | public bool LoadingQueues { get; set; } 52 | public bool LoadingTopics { get; set; } 53 | public bool QueuesExpanded { get; set; } 54 | public bool TopicsExpanded { get; set; } 55 | } -------------------------------------------------------------------------------- /src/Ui/Website/Models/CurrentMessagesEntity.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | namespace CrossBusExplorer.Website.Models; 3 | 4 | public record CurrentMessagesEntity( 5 | string ConnectionName, 6 | string QueueOrTopicName, 7 | string SubscriptionName) 8 | { 9 | public virtual bool Equals(CurrentMessagesEntity? other) 10 | { 11 | if (ReferenceEquals(null, other)) 12 | return false; 13 | if (ReferenceEquals(this, other)) 14 | return true; 15 | 16 | return string.Equals(ConnectionName, other.ConnectionName, 17 | StringComparison.InvariantCultureIgnoreCase) && 18 | string.Equals(QueueOrTopicName, other.QueueOrTopicName, 19 | StringComparison.InvariantCultureIgnoreCase) && string.Equals(SubscriptionName, 20 | other.SubscriptionName, StringComparison.InvariantCultureIgnoreCase); 21 | } 22 | public override int GetHashCode() 23 | { 24 | var hashCode = new HashCode(); 25 | hashCode.Add(ConnectionName, StringComparer.InvariantCultureIgnoreCase); 26 | hashCode.Add(QueueOrTopicName, StringComparer.InvariantCultureIgnoreCase); 27 | hashCode.Add(SubscriptionName, StringComparer.InvariantCultureIgnoreCase); 28 | return hashCode.ToHashCode(); 29 | } 30 | } -------------------------------------------------------------------------------- /src/Ui/Website/Models/DirectionChange.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.Website.Models; 2 | 3 | public enum DirectionChange 4 | { 5 | Up, 6 | Down 7 | } -------------------------------------------------------------------------------- /src/Ui/Website/Models/FolderSettings.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using CrossBusExplorer.Management.Contracts; 4 | using CrossBusExplorer.Website.Extensions; 5 | namespace CrossBusExplorer.Website.Models; 6 | 7 | public class FolderSettings 8 | { 9 | public FolderSettings( 10 | string name, 11 | int index, 12 | List? serviceBusConnectionSettings) 13 | { 14 | Name = name; 15 | Index = index; 16 | ServiceBusConnectionSettings = 17 | serviceBusConnectionSettings ?? new List(); 18 | } 19 | 20 | public string Name { get; private set; } 21 | public int Index { get; private set; } 22 | public List ServiceBusConnectionSettings { get;} 23 | 24 | public void UpdateName(string newName) 25 | { 26 | Name = newName; 27 | } 28 | 29 | public void UpdateIndex(int newIndex) 30 | { 31 | Index = newIndex; 32 | } 33 | 34 | public void AddServiceBusConnectionSetting( 35 | ServiceBusConnection serviceBusConnection) 36 | { 37 | var index = ServiceBusConnectionSettings.MaxBy(p => p.Index)?.Index ?? 0; 38 | 39 | ServiceBusConnectionSettings.Add( 40 | new ServiceBusConnectionSettings( 41 | serviceBusConnection.Name, 42 | index + 1)); 43 | } 44 | 45 | public void UpdateServiceBusConnectionsIndexes(string serviceBusConnectionName, int index) 46 | { 47 | var connectionByName = ServiceBusConnectionSettings 48 | .First(p => p.Name.EqualsInvariantIgnoreCase(serviceBusConnectionName)); 49 | 50 | connectionByName.UpdateIndex(index); 51 | 52 | foreach (ServiceBusConnectionSettings connection in ServiceBusConnectionSettings 53 | .Where(p => !p.Name.EqualsInvariantIgnoreCase(serviceBusConnectionName) && 54 | p.Index >= index) 55 | .OrderBy(p=>p.Index)) 56 | { 57 | connection.UpdateIndex(connection.Index + 1); 58 | } 59 | } 60 | public bool IsDefault() => string.IsNullOrEmpty(Name); 61 | } -------------------------------------------------------------------------------- /src/Ui/Website/Models/KeyValueTypePair.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using CrossBusExplorer.ServiceBus.Contracts.Types; 3 | using CrossBusExplorer.Website.Extensions; 4 | namespace CrossBusExplorer.Website.Models; 5 | 6 | public class KeyValueTypePair : INotifyPropertyChanged 7 | { 8 | public event PropertyChangedEventHandler? PropertyChanged; 9 | 10 | private string _key; 11 | 12 | public string Key 13 | { 14 | get => _key; 15 | set 16 | { 17 | _key = value; 18 | this.Notify(PropertyChanged); 19 | } 20 | } 21 | 22 | private string? _value; 23 | 24 | public string? Value 25 | { 26 | get => _value; 27 | set 28 | { 29 | _value = value; 30 | this.Notify(PropertyChanged); 31 | } 32 | } 33 | 34 | private ApplicationPropertyType _type; 35 | 36 | public ApplicationPropertyType Type 37 | { 38 | get => _type; 39 | set 40 | { 41 | _type = value; 42 | this.Notify(PropertyChanged); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Ui/Website/Models/MessageDetailsModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Collections.ObjectModel; 4 | using System.ComponentModel; 5 | using System.Runtime.CompilerServices; 6 | using CrossBusExplorer.Website.Extensions; 7 | namespace CrossBusExplorer.Website.Models; 8 | 9 | public class MessageDetailsModel : INotifyPropertyChanged 10 | { 11 | public event PropertyChangedEventHandler? PropertyChanged; 12 | 13 | public MessageDetailsModel() 14 | { 15 | ApplicationProperties = new ObservableCollection(); 16 | } 17 | 18 | private string _body; 19 | 20 | public string Body 21 | { 22 | get => _body; 23 | set 24 | { 25 | _body = value; 26 | this.Notify(PropertyChanged); 27 | } 28 | } 29 | 30 | private string? _subject; 31 | 32 | public string? Subject 33 | { 34 | get => _subject; 35 | set 36 | { 37 | _subject = value; 38 | this.Notify(PropertyChanged); 39 | } 40 | } 41 | 42 | private string? _to; 43 | 44 | public string? To 45 | { 46 | get => _to; 47 | set 48 | { 49 | _to = value; 50 | this.Notify(PropertyChanged); 51 | } 52 | } 53 | 54 | private string? _contentType; 55 | 56 | public string? ContentType 57 | { 58 | get => _contentType; 59 | set 60 | { 61 | _contentType = value; 62 | this.Notify(PropertyChanged); 63 | } 64 | } 65 | 66 | private string? _correlationId; 67 | 68 | public string? CorrelationId 69 | { 70 | get => _correlationId; 71 | set 72 | { 73 | _correlationId = value; 74 | this.Notify(PropertyChanged); 75 | } 76 | } 77 | 78 | private string? _id; 79 | 80 | public string? Id 81 | { 82 | get => _id; 83 | set 84 | { 85 | _id = value; 86 | this.Notify(PropertyChanged); 87 | } 88 | } 89 | 90 | private string? _partitionKey; 91 | 92 | public string? PartitionKey 93 | { 94 | get => _partitionKey; 95 | set 96 | { 97 | _partitionKey = value; 98 | this.Notify(PropertyChanged); 99 | } 100 | } 101 | 102 | private string? _replyTo; 103 | 104 | public string? ReplyTo 105 | { 106 | get => _replyTo; 107 | set 108 | { 109 | _replyTo = value; 110 | this.Notify(PropertyChanged); 111 | } 112 | } 113 | 114 | private string? _sessionId; 115 | 116 | public string? SessionId 117 | { 118 | get => _sessionId; 119 | set 120 | { 121 | _sessionId = value; 122 | this.Notify(PropertyChanged); 123 | } 124 | } 125 | 126 | private DateTimeOffset? _scheduledEnqueueTime; 127 | 128 | public DateTimeOffset? ScheduledEnqueueTime 129 | { 130 | get => _scheduledEnqueueTime; 131 | set 132 | { 133 | _scheduledEnqueueTime = value; 134 | this.Notify(PropertyChanged); 135 | } 136 | } 137 | 138 | private TimeSpan? _timeToLive; 139 | 140 | public TimeSpan? TimeToLive 141 | { 142 | get => _timeToLive; 143 | set 144 | { 145 | _timeToLive = value; 146 | this.Notify(PropertyChanged); 147 | } 148 | } 149 | 150 | private ObservableCollection _applicationProperties; 151 | 152 | public ObservableCollection ApplicationProperties 153 | { 154 | get => _applicationProperties; 155 | set 156 | { 157 | _applicationProperties = value; 158 | _applicationProperties.CollectionChanged += (_, _) => this.Notify(PropertyChanged); 159 | this.Notify(PropertyChanged); 160 | } 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /src/Ui/Website/Models/MessagesUploadDialogResult.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using CrossBusExplorer.ServiceBus.Contracts.Types; 3 | namespace CrossBusExplorer.Website.Models; 4 | 5 | public record MessagesUploadDialogResult(UploadFileType Type, IList FilesContent); 6 | -------------------------------------------------------------------------------- /src/Ui/Website/Models/OperationType.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.Website.Pages; 2 | 3 | public enum OperationType 4 | { 5 | Create, 6 | Update, 7 | Delete 8 | } -------------------------------------------------------------------------------- /src/Ui/Website/Models/ReceiveMessagesForm.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.ComponentModel.DataAnnotations; 3 | using CrossBusExplorer.ServiceBus.Contracts.Types; 4 | using CrossBusExplorer.Website.Extensions; 5 | using MudBlazor; 6 | namespace CrossBusExplorer.Website.Models; 7 | 8 | public class ReceiveMessagesForm : INotifyPropertyChanged 9 | { 10 | public event PropertyChangedEventHandler? PropertyChanged; 11 | 12 | private SubQueue _subQueue; 13 | 14 | [Label("Queue type")] 15 | public SubQueue SubQueue 16 | { 17 | get => _subQueue; 18 | set 19 | { 20 | _subQueue = value; 21 | this.Notify(PropertyChanged); 22 | } 23 | } 24 | 25 | private ReceiveMode _mode; 26 | 27 | [Label("Receive type")] 28 | public ReceiveMode Mode 29 | { 30 | get => _mode; 31 | set 32 | { 33 | _mode = value; 34 | 35 | if (_mode == ReceiveMode.ReceiveAndDelete && _mode != value) 36 | { 37 | FromSequenceNumber = null; 38 | } 39 | 40 | this.Notify(PropertyChanged); 41 | } 42 | } 43 | 44 | private ReceiveType _type; 45 | 46 | [Label("Receive type")] 47 | public ReceiveType Type 48 | { 49 | get => _type; 50 | set 51 | { 52 | if (value == ReceiveType.All && value != _type) 53 | { 54 | MessagesCount = null; 55 | } 56 | else 57 | { 58 | MessagesCount = 10; 59 | } 60 | 61 | _type = value; 62 | 63 | this.Notify(PropertyChanged); 64 | } 65 | } 66 | 67 | private int? _messagesCount; 68 | 69 | public int? MessagesCount 70 | { 71 | get => _messagesCount; 72 | set 73 | { 74 | _messagesCount = value; 75 | this.Notify(PropertyChanged); 76 | } 77 | } 78 | 79 | private long? _fromSequenceNumber; 80 | 81 | public long? FromSequenceNumber 82 | { 83 | get => _fromSequenceNumber; 84 | set 85 | { 86 | _fromSequenceNumber = value; 87 | this.Notify(PropertyChanged); 88 | } 89 | } 90 | } -------------------------------------------------------------------------------- /src/Ui/Website/Models/RequeueMessage.cs: -------------------------------------------------------------------------------- 1 | using CrossBusExplorer.ServiceBus.Contracts.Types; 2 | namespace CrossBusExplorer.Website.Models; 3 | 4 | public record RequeueMessage( 5 | string QueueOrTopicName, 6 | MessageDetailsModel Message); -------------------------------------------------------------------------------- /src/Ui/Website/Models/RuleFormModel.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using CrossBusExplorer.ServiceBus.Contracts.Types; 3 | using CrossBusExplorer.Website.Extensions; 4 | using CrossBusExplorer.Website.Pages; 5 | using MudBlazor; 6 | namespace CrossBusExplorer.Website.Models; 7 | 8 | public class RuleFormModel : INotifyPropertyChanged 9 | { 10 | public event PropertyChangedEventHandler? PropertyChanged; 11 | 12 | public RuleFormModel(OperationType operationType) 13 | { 14 | OperationType = operationType; 15 | } 16 | 17 | public OperationType OperationType { get; } 18 | 19 | private string? _name; 20 | 21 | public string? Name 22 | { 23 | get => _name; 24 | set 25 | { 26 | _name = value; 27 | this.Notify(PropertyChanged); 28 | } 29 | } 30 | 31 | private RuleType _type; 32 | 33 | public RuleType Type 34 | { 35 | get => _type; 36 | set 37 | { 38 | _type = value; 39 | this.Notify(PropertyChanged); 40 | } 41 | } 42 | 43 | private string? _value; 44 | 45 | public string? Value 46 | { 47 | get => _value; 48 | set 49 | { 50 | _value = value; 51 | this.Notify(PropertyChanged); 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /src/Ui/Website/Models/SaveConnectionForm.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.ComponentModel.DataAnnotations; 3 | using CrossBusExplorer.Management; 4 | using CrossBusExplorer.Website.Extensions; 5 | using MudBlazor; 6 | namespace CrossBusExplorer.Website.Models; 7 | 8 | public class SaveConnectionForm : INotifyPropertyChanged 9 | { 10 | public event PropertyChangedEventHandler? PropertyChanged; 11 | 12 | private string? _connectionString; 13 | 14 | [Label("Connection string")] 15 | [Required(ErrorMessage = "ConnectionString is required")] 16 | [ConnectionStringValidation(ErrorMessage = "ConnectionString has invalid format!")] 17 | public string? ConnectionString 18 | { 19 | get => _connectionString; 20 | set 21 | { 22 | _connectionString = value; 23 | 24 | if (string.IsNullOrEmpty(Name)) 25 | { 26 | Name = ServiceBusConnectionStringHelper.TryGetNameFromConnectionString( 27 | _connectionString); 28 | } 29 | 30 | this.Notify(PropertyChanged); 31 | } 32 | } 33 | 34 | private string? _name; 35 | [Label("Name")] 36 | public string? Name 37 | { 38 | get => _name; 39 | set 40 | { 41 | _name = value; 42 | this.Notify(PropertyChanged); 43 | } 44 | } 45 | 46 | private string? _folder; 47 | [Label("Folder")] 48 | public string? Folder 49 | { 50 | get => _folder; 51 | set 52 | { 53 | _folder = value; 54 | this.Notify(PropertyChanged); 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /src/Ui/Website/Models/ServiceBusConnectionFolder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using CrossBusExplorer.Management.Contracts; 3 | namespace CrossBusExplorer.Website.Models; 4 | 5 | public class ServiceBusConnectionWithFolder : ServiceBusConnection 6 | { 7 | public string Folder { get; private set; } 8 | 9 | public void UpdateFolder(string folder) 10 | { 11 | Folder = folder; 12 | } 13 | 14 | public ServiceBusConnectionWithFolder(ServiceBusConnection serviceBusConnection, string folder) : base(serviceBusConnection.Name, serviceBusConnection.ConnectionString, serviceBusConnection.Endpoint, serviceBusConnection.FullyQualifiedName, serviceBusConnection.EntityPath, serviceBusConnection.SharedAccessKey, serviceBusConnection.SharedAccessSignature, serviceBusConnection.SharedAccessKeyName) 15 | { 16 | Folder = folder; 17 | } 18 | } -------------------------------------------------------------------------------- /src/Ui/Website/Models/ServiceBusConnectionSettings.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.Website.Models; 2 | 3 | public class ServiceBusConnectionSettings 4 | { 5 | public ServiceBusConnectionSettings(string name, int index) 6 | { 7 | Name = name; 8 | Index = index; 9 | } 10 | 11 | public string Name { get; } 12 | public int Index { get; private set; } 13 | 14 | public void UpdateIndex(int newIndex) 15 | { 16 | Index = newIndex; 17 | } 18 | } -------------------------------------------------------------------------------- /src/Ui/Website/Models/TopicFormModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.ComponentModel.DataAnnotations; 4 | using CrossBusExplorer.Website.Extensions; 5 | using CrossBusExplorer.Website.Pages; 6 | using MudBlazor; 7 | namespace CrossBusExplorer.Website.Models; 8 | 9 | public class TopicFormModel : INotifyPropertyChanged 10 | { 11 | public event PropertyChangedEventHandler? PropertyChanged; 12 | 13 | public TopicFormModel(OperationType operationType) 14 | { 15 | OperationType = operationType; 16 | } 17 | 18 | public OperationType OperationType { get; } 19 | 20 | private string? _name; 21 | 22 | [Label("Name")] 23 | [Required(ErrorMessage = "Name is required")] 24 | public string? Name 25 | { 26 | get => _name; 27 | set 28 | { 29 | _name = value; 30 | this.Notify(PropertyChanged); 31 | } 32 | } 33 | 34 | private long? _maxSizeInMegabytes; 35 | 36 | [Label("Max size in MB")] 37 | [Required(ErrorMessage = "Field is required")] 38 | public long? MaxSizeInMegabytes 39 | { 40 | get => _maxSizeInMegabytes; 41 | set 42 | { 43 | _maxSizeInMegabytes = value; 44 | this.Notify(PropertyChanged); 45 | } 46 | } 47 | 48 | private string? _userMetadata; 49 | 50 | [Label("User metadata")] 51 | public string? UserMetadata 52 | { 53 | get => _userMetadata; 54 | set 55 | { 56 | _userMetadata = value; 57 | this.Notify(PropertyChanged); 58 | } 59 | } 60 | 61 | private TimeSpan? _duplicateDetectionHistoryTimeWindow; 62 | 63 | [Label("Duplicate detection history time window")] 64 | [Required(ErrorMessage = "Field is required. Format: DDDD.HH:MM:SS.")] 65 | public TimeSpan? DuplicateDetectionHistoryTimeWindow 66 | { 67 | get => _duplicateDetectionHistoryTimeWindow; 68 | set 69 | { 70 | _duplicateDetectionHistoryTimeWindow = value; 71 | this.Notify(PropertyChanged); 72 | } 73 | } 74 | 75 | private TimeSpan? _autoDeleteOnIdle; 76 | 77 | [Label("Auto delete queue on idle")] 78 | [Required(ErrorMessage = "Field is required. Format: DDDD.HH:MM:SS.")] 79 | public TimeSpan? AutoDeleteOnIdle 80 | { 81 | get => _autoDeleteOnIdle; 82 | set 83 | { 84 | _autoDeleteOnIdle = value; 85 | this.Notify(PropertyChanged); 86 | } 87 | } 88 | 89 | private TimeSpan? _defaultMessageTimeToLive; 90 | 91 | [Label("Default message time to live")] 92 | [Required(ErrorMessage = "Field is required. Format: DDDD.HH:MM:SS.")] 93 | public TimeSpan? DefaultMessageTimeToLive 94 | { 95 | get => _defaultMessageTimeToLive; 96 | set 97 | { 98 | _defaultMessageTimeToLive = value; 99 | this.Notify(PropertyChanged); 100 | } 101 | } 102 | 103 | private bool? _supportOrdering; 104 | 105 | [Label("Support ordering")] 106 | public bool? SupportOrdering 107 | { 108 | get => _supportOrdering; 109 | set 110 | { 111 | _supportOrdering = value; 112 | this.Notify(PropertyChanged); 113 | } 114 | } 115 | 116 | private bool? _enableBatchedOperations; 117 | 118 | [Label("Enable batch operations")] 119 | public bool? EnableBatchedOperations 120 | { 121 | get => _enableBatchedOperations; 122 | set 123 | { 124 | _enableBatchedOperations = value; 125 | this.Notify(PropertyChanged); 126 | } 127 | } 128 | 129 | private bool? _requiresDuplicateDetection; 130 | 131 | [Label("Requires duplicate detection")] 132 | public bool? RequiresDuplicateDetection 133 | { 134 | get => _requiresDuplicateDetection; 135 | set 136 | { 137 | _requiresDuplicateDetection = value; 138 | this.Notify(PropertyChanged); 139 | } 140 | } 141 | 142 | private bool? _enablePartitioning; 143 | 144 | [Label("Enable partitioning")] 145 | public bool? EnablePartitioning 146 | { 147 | get => _enablePartitioning; 148 | set 149 | { 150 | _enablePartitioning = value; 151 | this.Notify(PropertyChanged); 152 | } 153 | } 154 | 155 | private long? _maxMessageSizeInKilobytes; 156 | 157 | [Label("Max message size in KB")] 158 | public long? MaxMessageSizeInKilobytes 159 | { 160 | get => _maxMessageSizeInKilobytes; 161 | set 162 | { 163 | _maxMessageSizeInKilobytes = value; 164 | this.Notify(PropertyChanged); 165 | } 166 | } 167 | } -------------------------------------------------------------------------------- /src/Ui/Website/Models/TopicSubscriptionsModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using CrossBusExplorer.ServiceBus.Contracts.Types; 4 | using CrossBusExplorer.Website.Extensions; 5 | namespace CrossBusExplorer.Website.Models; 6 | 7 | public class TopicSubscriptionsModel 8 | { 9 | public TopicStructure Topic { get; } 10 | public IList Subscriptions { get; } 11 | public IList ChildrenModels { get; } 12 | public TopicSubscriptionsModel(TopicStructure topic) 13 | { 14 | Topic = topic; 15 | Subscriptions = new List(); 16 | ChildrenModels = topic.ChildTopics.Select(p => new TopicSubscriptionsModel(p)).ToList(); 17 | } 18 | 19 | public bool Loaded { get; set; } 20 | public bool IsLoading { get; set; } 21 | public bool TopicExpanded { get; set; } 22 | public bool ShouldRender { get; set; } 23 | 24 | public void AddSubscription(SubscriptionInfo subscriptionInfo) 25 | { 26 | Subscriptions.AddOrReplace( 27 | p=>p.SubscriptionName.EqualsInvariantIgnoreCase(subscriptionInfo.SubscriptionName), 28 | subscriptionInfo); 29 | } 30 | } -------------------------------------------------------------------------------- /src/Ui/Website/Models/UserSettings.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | namespace CrossBusExplorer.Website.Models; 3 | 4 | public class UserSettings 5 | { 6 | public bool IsDarkMode { get; set; } 7 | public List FolderSettings { get; set; } = new List(); 8 | } -------------------------------------------------------------------------------- /src/Ui/Website/Models/Validators/ReceiveMessageFormValidator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using CrossBusExplorer.ServiceBus.Contracts.Types; 6 | using CrossBusExplorer.Website.Extensions; 7 | using FluentValidation; 8 | namespace CrossBusExplorer.Website.Models.Validators; 9 | 10 | public class ReceiveMessageFormValidator : AbstractValidator 11 | { 12 | public ReceiveMessageFormValidator() 13 | { 14 | RuleFor(p => p.MessagesCount) 15 | .GreaterThan(0) 16 | .NotEmpty() 17 | .When(p => p.Type == ReceiveType.ByCount) 18 | .WithMessage($"When mode is set to {ReceiveMode.PeekLock} then " + 19 | $"{nameof(ReceiveMessagesForm.MessagesCount)} hast to be" + 20 | $" greater then 0."); 21 | } 22 | 23 | public Func>> ValidateValue => 24 | async (model, propertyName) => 25 | { 26 | var result = await ValidateAsync( 27 | ValidationContext.CreateWithOptions((ReceiveMessagesForm)model, 28 | x => x.IncludeProperties(propertyName.SplitAndGetLastSection('.')))); 29 | if (result.IsValid) 30 | return Array.Empty(); 31 | 32 | return result.Errors.Select(e => e.ErrorMessage); 33 | }; 34 | } -------------------------------------------------------------------------------- /src/Ui/Website/Models/Validators/RuleFormValidator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using CrossBusExplorer.ServiceBus.Contracts.Types; 6 | using CrossBusExplorer.Website.Extensions; 7 | using FluentValidation; 8 | namespace CrossBusExplorer.Website.Models.Validators; 9 | 10 | public class RuleFormValidator : AbstractValidator 11 | { 12 | public RuleFormValidator() 13 | { 14 | RuleFor(p => p.Name) 15 | .NotNull() 16 | .NotEmpty() 17 | .WithMessage("Name is required."); 18 | 19 | RuleFor(p => p.Value) 20 | .NotNull() 21 | .NotEmpty() 22 | .When(p => p.Type is RuleType.CorrelationId or RuleType.Sql) 23 | .WithMessage($"When type is set to {RuleType.Sql} or " + 24 | $"{RuleType.CorrelationId} the value must be set."); 25 | } 26 | 27 | public Func>> ValidateValue => 28 | async (model, propertyName) => 29 | { 30 | var result = await ValidateAsync( 31 | ValidationContext.CreateWithOptions( 32 | (RuleFormModel)model, 33 | x => x.IncludeProperties(propertyName.SplitAndGetLastSection('.')))); 34 | 35 | if (result.IsValid) 36 | return Array.Empty(); 37 | 38 | return result.Errors.Select(e => e.ErrorMessage); 39 | }; 40 | } -------------------------------------------------------------------------------- /src/Ui/Website/Pages/Monitoring.razor: -------------------------------------------------------------------------------- 1 |

Monitoring

2 | 3 | @code { 4 | 5 | } -------------------------------------------------------------------------------- /src/Ui/Website/Pages/Queues.razor: -------------------------------------------------------------------------------- 1 | @page "/queues/{ConnectionName}" 2 | Topics from @ConnectionName 3 | Topics from @ConnectionName 4 | 5 | @code { 6 | [Parameter] 7 | public string? ConnectionName { get; set; } 8 | } -------------------------------------------------------------------------------- /src/Ui/Website/Pages/ServiceBus.razor: -------------------------------------------------------------------------------- 1 | @page "/servicebus/{ServiceBusName}" 2 | 3 | Service bus @ServiceBusName 4 | -------------------------------------------------------------------------------- /src/Ui/Website/Pages/ServiceBus.razor.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components; 2 | namespace CrossBusExplorer.Website.Pages; 3 | 4 | public partial class ServiceBus 5 | { 6 | [Parameter] 7 | public string ServiceBusName { get; set; } 8 | } -------------------------------------------------------------------------------- /src/Ui/Website/Pages/Topics.razor: -------------------------------------------------------------------------------- 1 | @page "/topics/{ConnectionName}" 2 | Topics from @ConnectionName 3 | Topics from @ConnectionName 4 | 5 | @code { 6 | [Parameter] 7 | public string? ConnectionName { get; set; } 8 | } -------------------------------------------------------------------------------- /src/Ui/Website/ServiceCollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using CrossBusExplorer.Website.ViewModels; 2 | using Microsoft.Extensions.DependencyInjection; 3 | using MudBlazor; 4 | using MudBlazor.Services; 5 | namespace CrossBusExplorer.Website; 6 | 7 | public static class ServiceCollectionExtensions 8 | { 9 | public static IServiceCollection AddWebsiteServices(this IServiceCollection collection) 10 | { 11 | collection.AddScoped(); 12 | collection.AddScoped(); 13 | collection.AddScoped(); 14 | collection.AddScoped(); 15 | collection.AddScoped(); 16 | collection.AddScoped(); 17 | collection.AddScoped(); 18 | collection.AddScoped(); 19 | collection.AddCustomTheme(); 20 | 21 | return collection.AddMudServices(config => 22 | { 23 | config.SnackbarConfiguration.PositionClass = Defaults.Classes.Position.BottomRight; 24 | 25 | config.SnackbarConfiguration.PreventDuplicates = false; 26 | config.SnackbarConfiguration.NewestOnTop = false; 27 | config.SnackbarConfiguration.ShowCloseIcon = true; 28 | config.SnackbarConfiguration.VisibleStateDuration = 10000; 29 | config.SnackbarConfiguration.HideTransitionDuration = 500; 30 | config.SnackbarConfiguration.ShowTransitionDuration = 500; 31 | config.SnackbarConfiguration.SnackbarVariant = Variant.Filled; 32 | }); 33 | } 34 | 35 | private static IServiceCollection AddCustomTheme(this IServiceCollection collection) 36 | { 37 | collection.AddSingleton(new MudTheme() 38 | { 39 | Palette = new Palette 40 | { 41 | Secondary = Colors.Blue.Darken2 42 | }, 43 | PaletteDark = new PaletteDark 44 | { 45 | Secondary = Colors.Grey.Darken4 46 | } 47 | }); 48 | 49 | return collection; 50 | } 51 | } -------------------------------------------------------------------------------- /src/Ui/Website/Shared/ConfirmDialog.razor: -------------------------------------------------------------------------------- 1 | 2 | 3 | @ContentText 4 | 5 | 6 | No 7 | Yes 8 | 9 | 10 | 11 | @code { 12 | [CascadingParameter] 13 | MudDialogInstance MudDialog { get; set; } 14 | 15 | [Parameter] 16 | public string ContentText { get; set; } 17 | 18 | void Submit(bool result) => MudDialog.Close(DialogResult.Ok(result)); 19 | } -------------------------------------------------------------------------------- /src/Ui/Website/Shared/Connections/FolderDialog.razor: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | @FolderDialogName 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | Close 14 | Save 15 | 16 | 17 | 18 | @code { 19 | [CascadingParameter] 20 | MudDialogInstance MudDialog { get; set; } 21 | 22 | [Parameter] 23 | public string FolderDialogName { get; set; } 24 | 25 | [Parameter] 26 | public string? FolderName { get; set; } 27 | 28 | MudForm form; 29 | 30 | async Task Submit() 31 | { 32 | await form.Validate(); 33 | 34 | if (form.IsValid) 35 | { 36 | MudDialog.Close(DialogResult.Ok(FolderName)); 37 | } 38 | 39 | } 40 | private void CloseDialog() 41 | { 42 | MudDialog.Close(DialogResult.Cancel()); 43 | } 44 | } -------------------------------------------------------------------------------- /src/Ui/Website/Shared/Jobs.razor: -------------------------------------------------------------------------------- 1 | @using CrossBusExplorer.Website.ViewModels 2 | @using MudBlazor.Utilities 3 | 4 | @foreach (var job in Model.Jobs) 5 | { 6 | 7 | 8 | 9 | 10 | 14 |
15 | @($"{job.Name} {job.Progress}%") 16 | 17 | 21 | 22 | 23 |
24 |
25 |
26 | } 27 | 28 | @code { 29 | [Inject] 30 | public IJobsViewModel Model { get; set; } 31 | 32 | protected override void OnInitialized() 33 | { 34 | Model.PropertyChanged += (_, _) => StateHasChanged(); 35 | } 36 | } -------------------------------------------------------------------------------- /src/Ui/Website/Shared/MainLayout.razor: -------------------------------------------------------------------------------- 1 | @using CrossBusExplorer.Website.Models 2 | @inherits LayoutComponentBase 3 | @inject IConnectionsViewModel _connectionsViewModel 4 | @inject ISettingsService SettingsService 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 29 | 30 | 31 | 32 | Normal 33 | Dark 34 | 35 | 36 | 37 | 38 | 39 | @if (_drawerOpen) 40 | { 41 | 42 | 43 | 44 | } 45 | 46 | 47 | 48 | @Body 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | @context 57 | Recover 58 | 59 | 60 | 61 | 62 | 63 | @code { 64 | private ErrorBoundary? _errorBoundary; 65 | private bool _isOpen; 66 | private UserSettings _userSettings = new UserSettings(); 67 | bool _drawerOpen = true; 68 | public bool DarkMode { get; set; } 69 | 70 | [Inject] 71 | private INavigationViewModel _navigationViewModel { get; set; } 72 | 73 | [Inject] 74 | private MudTheme _customTheme { get; set; } 75 | 76 | protected override void OnParametersSet() 77 | { 78 | _errorBoundary?.Recover(); 79 | } 80 | 81 | protected override async Task OnInitializedAsync() 82 | { 83 | await _connectionsViewModel.InitializeAsync(default); 84 | } 85 | 86 | protected override async Task OnAfterRenderAsync(bool firstRender) 87 | { 88 | if (firstRender) 89 | { 90 | _userSettings = await SettingsService.GetAsync(default); 91 | StateHasChanged(); 92 | } 93 | } 94 | 95 | private async Task ChangeDarkMode(bool isDarkMode) 96 | { 97 | _userSettings.IsDarkMode = isDarkMode; 98 | StateHasChanged(); 99 | 100 | await SettingsService.SaveAsync(_userSettings, default); 101 | } 102 | 103 | private async Task ChangeDarkModeInternal(bool isDarkMode) 104 | { 105 | DarkMode = isDarkMode; 106 | await ChangeDarkMode(isDarkMode); 107 | } 108 | 109 | void DrawerToggle() 110 | { 111 | _drawerOpen = !_drawerOpen; 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/Ui/Website/Shared/MenuItem.razor: -------------------------------------------------------------------------------- 1 | @using System.Web 2 | @using CrossBusExplorer.Website.Models 3 | 5 | 6 | 10 | @if (Value.LoadingQueues) 11 | { 12 | 13 | } 14 | else 15 | { 16 | 19 | Create new queue 20 | 21 | } 22 | 23 | @foreach (var queue in Value.Queues) 24 | { 25 | 28 | 29 | @queue.Name 30 | (@queue.ActiveMessagesCount, @queue.DeadLetterMessagesCount, @queue.InTransferMessagesCount, 31 | @queue.ScheduledMessagesCount) 32 | 33 | 34 | 35 | } 36 | 37 | 38 | 42 | 43 | @if (Value.LoadingTopics) 44 | { 45 | 46 | } 47 | else 48 | { 49 | 52 | Create new topic 53 | 54 | } 55 | @foreach (var topic in Value.Topics) 56 | { 57 | 58 | } 59 | 60 | 61 | 62 | @code { 63 | [Parameter] 64 | public ConnectionMenuItem Value { get; set; } 65 | [Inject] 66 | private INavigationViewModel Model { get; set; } 67 | 68 | protected override async Task OnInitializedAsync() 69 | { 70 | Model.PropertyChanged += (_, _) => 71 | { 72 | StateHasChanged(); 73 | }; 74 | 75 | Value.PropertyChanged += (_, _) => 76 | { 77 | StateHasChanged(); 78 | }; 79 | } 80 | 81 | private async Task OnQueuesExpandChange() 82 | { 83 | await Model.LoadQueues(Value, default); 84 | } 85 | 86 | private async Task OnTopicsExpanded() 87 | { 88 | await Model.LoadTopics(Value, default); 89 | } 90 | } -------------------------------------------------------------------------------- /src/Ui/Website/Shared/Messages/MessagesUploadDialog.razor: -------------------------------------------------------------------------------- 1 | @using CrossBusExplorer.ServiceBus.Contracts.Types 2 | @using System.IO 3 | @using CrossBusExplorer.Website.Models 4 | 5 | 6 | 7 | Upload messages from file 8 | 9 | Max 200 at once 10 | 11 | 12 | 13 | 14 | 16 | 19 | Body only 20 | 21 | 25 | Body with ApplicationProperties (not yet supported) 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 39 | Select multiple files 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 51 | Close 52 | 53 | 58 | Upload @_fileContents.Count files 59 | 60 | 61 | 62 | 63 | @code { 64 | [CascadingParameter] 65 | MudDialogInstance MudDialog { get; set; } 66 | 67 | IList _fileContents = new List(); 68 | 69 | private UploadFileType _uploadFileType; 70 | 71 | private void CloseDialog() 72 | { 73 | MudDialog.Close(DialogResult.Cancel()); 74 | } 75 | 76 | private void Submit() 77 | { 78 | MudDialog.Close(DialogResult.Ok(new MessagesUploadDialogResult(_uploadFileType, _fileContents))); 79 | } 80 | 81 | private async Task UploadFilesAsync(IReadOnlyList files) 82 | { 83 | _fileContents.Clear(); 84 | 85 | foreach (IBrowserFile file in files) 86 | { 87 | using var reader = new StreamReader(file.OpenReadStream()); 88 | var fileContent = await reader.ReadToEndAsync(default); 89 | 90 | _fileContents.Add(fileContent); 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/Ui/Website/Shared/Messages/PurgeMessagesDialog.razor: -------------------------------------------------------------------------------- 1 | @using CrossBusExplorer.ServiceBus.Contracts.Types 2 | 3 | 4 | 5 | Select which sub queue to purge 6 | 7 | 8 | 9 | 10 | 11 | 13 | 16 | Active messages 17 | 18 | 21 | Dead letter 22 | 23 | 26 | Transfer dead letter 27 | 28 | 29 | 30 | 31 | 32 | 33 | 37 | Close 38 | 39 | 43 | Purge 44 | 45 | 46 | 47 | 48 | @code { 49 | [CascadingParameter] 50 | MudDialogInstance MudDialog { get; set; } 51 | 52 | private SubQueue _subQueue; 53 | 54 | private void CloseDialog() 55 | { 56 | MudDialog.Close(DialogResult.Cancel()); 57 | } 58 | 59 | private void Submit() 60 | { 61 | MudDialog.Close(DialogResult.Ok(_subQueue)); 62 | } 63 | } -------------------------------------------------------------------------------- /src/Ui/Website/Shared/Queue/CloneDialog.razor: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Clone @SourceDialogName 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | No 14 | Yes 15 | 16 | 17 | 18 | @code { 19 | [CascadingParameter] 20 | MudDialogInstance MudDialog { get; set; } 21 | 22 | [Parameter] 23 | public string SourceDialogName { get; set; } 24 | 25 | [Parameter] 26 | public string ConnectionName { get; set; } 27 | 28 | MudForm form; 29 | string name; 30 | 31 | async Task Submit() 32 | { 33 | await form.Validate(); 34 | 35 | if (form.IsValid) 36 | { 37 | MudDialog.Close(DialogResult.Ok(name)); 38 | } 39 | 40 | } 41 | private void CloseDialog() 42 | { 43 | MudDialog.Close(DialogResult.Cancel()); 44 | } 45 | } -------------------------------------------------------------------------------- /src/Ui/Website/Shared/ServiceBusNavMenu.razor: -------------------------------------------------------------------------------- 1 | @using CrossBusExplorer.Management 2 | @using CrossBusExplorer.Management.Contracts 3 | @using CrossBusExplorer.ServiceBus.Contracts 4 | @using CrossBusExplorer.Website.Models 5 | @using System.Security.Cryptography 6 | @using System.Net 7 | @using System.Web 8 | 9 | 10 | 11 | @foreach (var folder in Model.Folders) 12 | { 13 | if (string.IsNullOrEmpty(folder.Name)) 14 | { 15 | foreach (var menuItem in folder.MenuItems) 16 | { 17 | 18 | } 19 | } 20 | else 21 | { 22 | 24 | @foreach (var menuItem in folder.MenuItems) 25 | { 26 | 27 | } 28 | 29 | } 30 | } 31 | 32 | 33 | @code { 34 | [Inject] 35 | private INavigationViewModel Model { get; set; } 36 | 37 | protected override async Task OnInitializedAsync() 38 | { 39 | Model.PropertyChanged += (_, _) => 40 | { 41 | StateHasChanged(); 42 | }; 43 | } 44 | } -------------------------------------------------------------------------------- /src/Ui/Website/Shared/TopicNestedMenuItem.razor: -------------------------------------------------------------------------------- 1 | @using System.Web 2 | @using CrossBusExplorer.Website.Models 3 | 4 | @if (TopicSubscriptionsModel.Topic.IsFolder) 5 | { 6 | 7 | 8 | @if (TopicSubscriptionsModel.TopicExpanded) 9 | { 10 | @foreach (var model in TopicSubscriptionsModel.ChildrenModels) 11 | { 12 | 13 | } 14 | } 15 | 16 | 17 | } 18 | else 19 | { 20 | 21 | 24 | View topic details 25 | 26 | 29 | 30 | @if (TopicSubscriptionsModel.IsLoading) 31 | { 32 | 33 | } 34 | @if (TopicSubscriptionsModel.Loaded) 35 | { 36 | 39 | Create new subscription 40 | 41 | 42 | @foreach (var subscription in TopicSubscriptionsModel.Subscriptions) 43 | { 44 | 47 | 48 | @subscription.SubscriptionName (@subscription.ActiveMessagesCount, 49 | @subscription.DeadLetterMessagesCount, 50 | @subscription.TransferMessagesCount) 51 | 52 | 53 | } 54 | } 55 | 56 | 57 | } 58 | 59 | @code { 60 | [Inject] public INavigationViewModel Model { get; set; } 61 | [Parameter] public TopicSubscriptionsModel TopicSubscriptionsModel { get; set; } = null!; 62 | [Parameter] public string ConnectionName { get; set; } = null!; 63 | 64 | protected override void OnInitialized() 65 | { 66 | Model.PropertyChanged += (_, _) => { StateHasChanged(); }; 67 | 68 | TopicSubscriptionsModel.ShouldRender = true; 69 | } 70 | 71 | protected override bool ShouldRender() => TopicSubscriptionsModel.ShouldRender; 72 | 73 | private async Task OnSubscriptionsExpanded() 74 | { 75 | TopicSubscriptionsModel.ShouldRender = false; 76 | await Model.LoadSubscriptionsAsync(ConnectionName, TopicSubscriptionsModel); 77 | TopicSubscriptionsModel.ShouldRender = true; 78 | } 79 | 80 | private void OnTopicExpandChange() 81 | { 82 | TopicSubscriptionsModel.TopicExpanded = !TopicSubscriptionsModel.TopicExpanded; 83 | } 84 | 85 | } -------------------------------------------------------------------------------- /src/Ui/Website/Shared/TopicSubNestedMenuItem.razor: -------------------------------------------------------------------------------- 1 | @using CrossBusExplorer.Website.Models 2 | @using System.Web 3 | 4 | @if (TopicSubscriptionsModel.Topic.IsFolder) 5 | { 6 | 7 | @if (TopicSubscriptionsModel.TopicExpanded) 8 | { 9 | @foreach (var model in TopicSubscriptionsModel.ChildrenModels) 10 | { 11 | 12 | } 13 | } 14 | 15 | } 16 | else 17 | { 18 | 19 | 22 | View topic details 23 | 24 | 27 | 28 | @if (TopicSubscriptionsModel.IsLoading) 29 | { 30 | 31 | } 32 | @if (TopicSubscriptionsModel.Loaded) 33 | { 34 | 37 | Create new subscription 38 | 39 | 40 | @foreach (var subscription in TopicSubscriptionsModel.Subscriptions) 41 | { 42 | 45 | 48 | @subscription.SubscriptionName (@subscription.ActiveMessagesCount, 49 | @subscription.DeadLetterMessagesCount, 50 | @subscription.TransferMessagesCount) 51 | 52 | 53 | } 54 | } 55 | 56 | 57 | } 58 | 59 | @code { 60 | [Inject] 61 | public INavigationViewModel Model { get; set; } 62 | [Parameter] 63 | public TopicSubscriptionsModel TopicSubscriptionsModel { get; set; } = null!; 64 | [Parameter] 65 | public string ConnectionName { get; set; } = null!; 66 | 67 | protected override void OnInitialized() 68 | { 69 | Model.PropertyChanged += (_, _) => 70 | { 71 | StateHasChanged(); 72 | }; 73 | 74 | TopicSubscriptionsModel.ShouldRender = true; 75 | } 76 | 77 | protected override bool ShouldRender() => TopicSubscriptionsModel.ShouldRender; 78 | 79 | private async Task OnSubscriptionsExpanded() 80 | { 81 | TopicSubscriptionsModel.ShouldRender = false; 82 | await Model.LoadSubscriptionsAsync(ConnectionName, TopicSubscriptionsModel); 83 | TopicSubscriptionsModel.ShouldRender = true; 84 | } 85 | private void OnTopicExpandChange() 86 | { 87 | TopicSubscriptionsModel.TopicExpanded = !TopicSubscriptionsModel.TopicExpanded; 88 | } 89 | } -------------------------------------------------------------------------------- /src/Ui/Website/Shared/ViewDialog.razor: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Close 7 | 8 | 9 | @code { 10 | [CascadingParameter] 11 | MudDialogInstance MudDialog { get; set; } 12 | 13 | [Parameter] 14 | public string ContentText { get; set; } 15 | 16 | void Submit() => MudDialog.Close(DialogResult.Ok(true)); 17 | } -------------------------------------------------------------------------------- /src/Ui/Website/Validation/ConnectionStringValidationAttribute.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using CrossBusExplorer.Management; 3 | namespace CrossBusExplorer.Website; 4 | 5 | public class ConnectionStringValidationAttribute : ValidationAttribute 6 | { 7 | public override bool IsValid(object? value) 8 | { 9 | return value is string connectionString && 10 | ServiceBusConnectionStringHelper.IsValid(connectionString); 11 | } 12 | } -------------------------------------------------------------------------------- /src/Ui/Website/ViewModels/ConnectionOperationEventHandler.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using CrossBusExplorer.Website.Models; 3 | namespace CrossBusExplorer.Website.ViewModels; 4 | 5 | public delegate void SettingsChangedEventHandler(IEnumerable folderSettings); -------------------------------------------------------------------------------- /src/Ui/Website/ViewModels/IConnectionsViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.ObjectModel; 3 | using System.ComponentModel; 4 | using System.Threading; 5 | using System.Threading.Tasks; 6 | using CrossBusExplorer.Website.Models; 7 | using CrossBusExplorer.Website.ViewModels; 8 | using Microsoft.AspNetCore.Components.Forms; 9 | namespace CrossBusExplorer.Website; 10 | 11 | public interface IConnectionsViewModel : INotifyPropertyChanged 12 | { 13 | event SettingsChangedEventHandler? OnSettingsChanged; 14 | public SaveConnectionForm? SaveConnectionForm { get; } 15 | bool SaveDialogVisible { get; set; } 16 | ObservableCollection Folders { get; } 17 | ObservableCollection ServiceBusConnections { get; } 18 | Task InitializeAsync(CancellationToken cancellationToken); 19 | void OpenSaveDialog(ServiceBusConnectionWithFolder? model = null); 20 | Task OpenDeleteDialog(ServiceBusConnectionWithFolder item); 21 | void ViewConnectionString(string connectionString); 22 | Task OnValidSaveConnectionSubmit(); 23 | Task SubmitSaveConnectionForm(EditForm editForm); 24 | Task UpdateConnectionPosition(ServiceBusConnectionWithFolder serviceBusConnection, 25 | int index, 26 | string newFolder, CancellationToken cancellationToken); 27 | Task UpdateFolderPositionAsync( 28 | FolderSettings folder, 29 | DirectionChange up, 30 | CancellationToken cancellationToken); 31 | Task OpenNewFolderDialogAsync(CancellationToken cancellationToken); 32 | Task OpenEditFolderDialogAsync( 33 | FolderSettings folderSettings, 34 | Action successCallback, 35 | CancellationToken cancellationToken); 36 | Task OpenDeleteFolderDialogAsync( 37 | FolderSettings folderSettings, 38 | Action successCallback, 39 | CancellationToken cancellationToken); 40 | } -------------------------------------------------------------------------------- /src/Ui/Website/ViewModels/IJobsViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.ObjectModel; 2 | using System.ComponentModel; 3 | using System.Threading.Tasks; 4 | using CrossBusExplorer.Website.Jobs; 5 | namespace CrossBusExplorer.Website.ViewModels; 6 | 7 | public interface IJobsViewModel : INotifyPropertyChanged 8 | { 9 | ObservableCollection Jobs { get; } 10 | Task ScheduleJob(IJob job); 11 | void CancelJob(IJob job); 12 | } -------------------------------------------------------------------------------- /src/Ui/Website/ViewModels/IMessagesViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.ObjectModel; 2 | using System.ComponentModel; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | using CrossBusExplorer.ServiceBus.Contracts.Types; 6 | using CrossBusExplorer.Website.Models; 7 | using MudBlazor; 8 | namespace CrossBusExplorer.Website.ViewModels; 9 | 10 | public interface IMessagesViewModel : INotifyPropertyChanged 11 | { 12 | ObservableCollection Messages { get; } 13 | bool DialogVisible { get; set; } 14 | bool IsPeekMode(ReceiveMessagesForm formModel); 15 | bool CanPeekMore(ReceiveMessagesForm formModel); 16 | Task PeekMore(ReceiveMessagesForm formModel, CancellationToken cancellationToken); 17 | Task OnSubmitReceiveForm( 18 | MudForm form, 19 | ReceiveMessagesForm formModel, 20 | CancellationToken cancellationToken); 21 | void Initialize(CurrentMessagesEntity entity); 22 | Task ViewMessageDetails(Message? message, bool editMode); 23 | Task Requeue(string queueOrTopicName, MessageDetailsModel message); 24 | Task Delete(Message message, SubQueue subQueue); 25 | Task ImportMessagesFromFileAsync(CancellationToken cancellationToken); 26 | } 27 | -------------------------------------------------------------------------------- /src/Ui/Website/ViewModels/INavigationViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.ObjectModel; 2 | using System.ComponentModel; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | using CrossBusExplorer.Website.Models; 6 | namespace CrossBusExplorer.Website; 7 | 8 | public interface INavigationViewModel : INotifyPropertyChanged 9 | { 10 | ObservableCollection Folders { get; } 11 | public Task LoadTopics(ConnectionMenuItem menuItem, CancellationToken cancellationToken); 12 | public Task LoadQueues(ConnectionMenuItem menuItem, CancellationToken cancellationToken); 13 | Task LoadSubscriptionsAsync(string connectionName, TopicSubscriptionsModel model); 14 | Task ReloadMenu(); 15 | bool IsLoading { get; } 16 | } -------------------------------------------------------------------------------- /src/Ui/Website/ViewModels/IQueueViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | using CrossBusExplorer.ServiceBus.Contracts.Types; 5 | using CrossBusExplorer.Website.Models; 6 | namespace CrossBusExplorer.Website.ViewModels; 7 | 8 | public interface IQueueViewModel : INotifyPropertyChanged 9 | { 10 | event QueueOperationEventHandler? OnQueueOperation; 11 | QueueFormModel? Form { get; } 12 | QueueDetails? QueueDetails { get; } 13 | Task InitializeFormAsync( 14 | string connectionName, 15 | string? queueName, 16 | CancellationToken cancellationToken); 17 | Task SaveQueueFormAsync(string connectionName); 18 | void NavigateToNewQueueForm(string connectionName); 19 | Task CloneQueue( 20 | string connectionName, 21 | string sourceQueueName, 22 | CancellationToken cancellationToken); 23 | Task DeleteQueue(string connectionName, string queueName, CancellationToken cancellationToken); 24 | Task UpdateQueueStatus( 25 | string connectionName, 26 | string queueName, 27 | ServiceBusEntityStatus status, 28 | CancellationToken cancellationToken); 29 | Task PurgeMessages( 30 | string connectionName, 31 | string queueName, 32 | CancellationToken cancellationToken); 33 | Task ResendDeadLetters( 34 | string connectionName, 35 | string queueName, 36 | CancellationToken cancellationToken); 37 | } -------------------------------------------------------------------------------- /src/Ui/Website/ViewModels/IRulesViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.ObjectModel; 2 | using System.ComponentModel; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | using CrossBusExplorer.ServiceBus.Contracts.Types; 6 | using CrossBusExplorer.Website.Models; 7 | using MudBlazor; 8 | namespace CrossBusExplorer.Website.ViewModels; 9 | 10 | public interface IRulesViewModel : INotifyPropertyChanged 11 | { 12 | RuleFormModel? Form { get; } 13 | ObservableCollection Rules { get; } 14 | 15 | bool DialogVisible { get; set; } 16 | 17 | void ShowCreateRuleForm(); 18 | 19 | Task InitializeAsync( 20 | string connectionName, 21 | string topicName, 22 | string subscriptionName, 23 | CancellationToken cancellationToken); 24 | 25 | void ShowEditRuleForm(Rule rule); 26 | 27 | Task DeleteRuleAsync( 28 | string connectionName, 29 | string topicName, 30 | string subscriptionName, 31 | Rule rule, 32 | CancellationToken cancellationToken); 33 | Task OnSubmitFormAsync( 34 | string connectionName, 35 | string topicName, 36 | string subscriptionName, 37 | CancellationToken cancellationToken); 38 | } -------------------------------------------------------------------------------- /src/Ui/Website/ViewModels/ISubscriptionViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | using CrossBusExplorer.ServiceBus.Contracts.Types; 5 | using CrossBusExplorer.Website.Models; 6 | namespace CrossBusExplorer.Website.ViewModels; 7 | 8 | public interface ISubscriptionViewModel : INotifyPropertyChanged 9 | { 10 | event SubscriptionOperationEventHandler? OnSubscriptionOperation; 11 | SubscriptionFormModel? Form { get; } 12 | SubscriptionDetails? SubscriptionDetails { get; } 13 | Task InitializeFormAsync( 14 | string connectionName, 15 | string topicName, 16 | string? subscriptionName, 17 | CancellationToken cancellationToken); 18 | Task SaveSubscriptionFormAsync(string connectionName); 19 | void NavigateToNewSubscriptionForm(string connectionName, string topicName); 20 | Task CloneSubscriptionAsync( 21 | string connectionName, 22 | string sourceTopicName, 23 | string sourceSubscriptionName, 24 | CancellationToken cancellationToken); 25 | Task DeleteSubscriptionAsync( 26 | string connectionName, 27 | string topicName, 28 | string subscriptionName, 29 | CancellationToken cancellationToken); 30 | Task UpdateSubscriptionStatusAsync( 31 | string connectionName, 32 | string topicName, 33 | string subscriptionName, 34 | ServiceBusEntityStatus status, 35 | CancellationToken cancellationToken); 36 | Task PurgeMessagesAsync( 37 | string connectionName, 38 | string topicName, 39 | string subscriptionName, 40 | CancellationToken cancellationToken); 41 | Task ResendDeadLettersAsync( 42 | string connectionName, 43 | string topicName, 44 | string subscriptionName, 45 | CancellationToken cancellationToken); 46 | } -------------------------------------------------------------------------------- /src/Ui/Website/ViewModels/ITopicViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | using CrossBusExplorer.ServiceBus.Contracts.Types; 5 | using CrossBusExplorer.Website.Models; 6 | namespace CrossBusExplorer.Website.ViewModels; 7 | 8 | public interface ITopicViewModel : INotifyPropertyChanged 9 | { 10 | event TopicAddedEventHandler? TopicAdded; 11 | event TopicRemovedEventHandler? TopicRemoved; 12 | TopicFormModel? Form { get; } 13 | TopicDetails? TopicDetails { get; } 14 | Task InitializeForm( 15 | string connectionName, 16 | string? topicName, 17 | CancellationToken cancellationToken); 18 | Task SaveTopicFormAsync(string connectionName); 19 | void NavigateToNewTopicForm(string connectionName); 20 | Task CloneTopic( 21 | string connectionName, 22 | string sourceTopicName, 23 | CancellationToken cancellationToken); 24 | Task DeleteTopic(string connectionName, string topicName, CancellationToken cancellationToken); 25 | Task UpdateTopicStatus( 26 | string connectionName, 27 | string topicName, 28 | ServiceBusEntityStatus active, 29 | CancellationToken cancellationToken); 30 | } -------------------------------------------------------------------------------- /src/Ui/Website/ViewModels/JobsViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.ObjectModel; 2 | using System.ComponentModel; 3 | using System.Threading.Tasks; 4 | using CrossBusExplorer.Website.Extensions; 5 | using CrossBusExplorer.Website.Jobs; 6 | using MudBlazor; 7 | namespace CrossBusExplorer.Website.ViewModels; 8 | 9 | public class JobsViewModel : IJobsViewModel 10 | { 11 | private readonly ISnackbar _snackbar; 12 | public event PropertyChangedEventHandler? PropertyChanged; 13 | 14 | public JobsViewModel(ISnackbar snackbar) 15 | { 16 | _snackbar = snackbar; 17 | Jobs = new ObservableCollection(); 18 | } 19 | 20 | private ObservableCollection _jobs; 21 | public ObservableCollection Jobs 22 | { 23 | get => _jobs; 24 | set 25 | { 26 | _jobs = value; 27 | _jobs.CollectionChanged += (_, _) => this.Notify(PropertyChanged); 28 | } 29 | } 30 | public async Task ScheduleJob(IJob job) 31 | { 32 | job.PropertyChanged += (_, _) => HandleJobUpdate(job); 33 | Jobs.Add(job); 34 | await job.ExecuteAsync(); 35 | } 36 | 37 | private void HandleJobUpdate(IJob job) 38 | { 39 | if (job.Status != JobStatus.Running) 40 | { 41 | job.PropertyChanged -= (_, _) => HandleJobUpdate(job); 42 | _jobs.Remove(job); 43 | 44 | if (job.Status == JobStatus.Succeeded) 45 | { 46 | _snackbar.Add($"Job {job.Name} completed.", Severity.Success); 47 | } 48 | else if (job.Status == JobStatus.Failed) 49 | { 50 | _snackbar.Add( 51 | job.ErrorMessage ?? $"Error while executing job {job.Name}", 52 | Severity.Error); 53 | } 54 | else if (job.Status == JobStatus.Cancelled) 55 | { 56 | _snackbar.Add($"Job {job.Name} was cancelled.", Severity.Warning); 57 | } 58 | } 59 | 60 | this.Notify(PropertyChanged); 61 | } 62 | public void CancelJob(IJob job) 63 | { 64 | job.Cancel(); 65 | } 66 | } -------------------------------------------------------------------------------- /src/Ui/Website/ViewModels/QueueOperationEventHandler.cs: -------------------------------------------------------------------------------- 1 | using CrossBusExplorer.ServiceBus.Contracts.Types; 2 | using CrossBusExplorer.Website.Pages; 3 | namespace CrossBusExplorer.Website.ViewModels; 4 | 5 | public delegate void QueueOperationEventHandler( 6 | string connectionName, 7 | OperationType operationType, 8 | QueueInfo queueInfo); -------------------------------------------------------------------------------- /src/Ui/Website/ViewModels/SubscriptionOperationEventHandler.cs: -------------------------------------------------------------------------------- 1 | using CrossBusExplorer.ServiceBus.Contracts.Types; 2 | using CrossBusExplorer.Website.Pages; 3 | namespace CrossBusExplorer.Website.ViewModels; 4 | 5 | public delegate void SubscriptionOperationEventHandler( 6 | string connectionName, 7 | OperationType operationType, 8 | SubscriptionInfo subscription); -------------------------------------------------------------------------------- /src/Ui/Website/ViewModels/TopicAddedEventHandler.cs: -------------------------------------------------------------------------------- 1 | using CrossBusExplorer.ServiceBus.Contracts.Types; 2 | namespace CrossBusExplorer.Website.ViewModels; 3 | 4 | public delegate void TopicAddedEventHandler(string connectionName, TopicInfo topicInfo); -------------------------------------------------------------------------------- /src/Ui/Website/ViewModels/TopicRemovedEventHandler.cs: -------------------------------------------------------------------------------- 1 | namespace CrossBusExplorer.Website.ViewModels; 2 | 3 | public delegate void TopicRemovedEventHandler(string connectionName, string topicName); -------------------------------------------------------------------------------- /src/Ui/Website/Website.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | Debug;Release 6 | enable 7 | CrossBusExplorer.Website 8 | 9 | 10 | 11 | true 12 | 13 | 14 | 15 | false 16 | 17 | 18 | 19 | Logging 20 | 21 | 22 | 23 | NoLogging 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | <_ContentIncludedByDefault Remove="wwwroot\js\app.js" /> 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /src/Ui/Website/WellKnown.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using CrossBusExplorer.Website.Exceptions; 3 | using MudBlazor; 4 | namespace CrossBusExplorer.Website; 5 | 6 | internal static class WellKnown 7 | { 8 | internal static int ProgressCompleted = 100; 9 | internal static string DefaultConfirmSuccessResult => "confirm"; 10 | 11 | internal static class Regex 12 | { 13 | public static string TimeSpan = @"\d+\.((0?\d)|(1\d)|(2[0-3]))(:[0-5]\d){2}"; 14 | } 15 | 16 | internal static class Format 17 | { 18 | public static string DateFormat = "dd.MM.yyyy hh:MM:ss"; 19 | } 20 | 21 | public static class Converters 22 | { 23 | public static Converter TimeSpanConverter = new Converter 24 | { 25 | SetFunc = value => value?.ToString(@"dddd\.hh\:mm\:ss"), 26 | GetFunc = text => 27 | { 28 | if (TimeSpan.TryParse(text, out TimeSpan value)) 29 | { 30 | return value; 31 | } 32 | 33 | return null; 34 | } 35 | }; 36 | 37 | public static Converter DateTimeOffsetConverter = 38 | new Converter 39 | { 40 | SetFunc = value => value?.ToString(Format.DateFormat), 41 | GetFunc = text => 42 | { 43 | if (DateTimeOffset.TryParse(text, out DateTimeOffset value)) 44 | { 45 | return value; 46 | } 47 | 48 | return null; 49 | } 50 | }; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Ui/Website/_Imports.razor: -------------------------------------------------------------------------------- 1 | @using System.Net.Http 2 | @using System.Net.Http.Json 3 | @using Microsoft.AspNetCore.Components.Forms 4 | @using Microsoft.AspNetCore.Components.Routing 5 | @using Microsoft.AspNetCore.Components.Web 6 | @using Microsoft.JSInterop 7 | @using CrossBusExplorer.Website 8 | @using MudBlazor 9 | @using CrossBusExplorer.Website.Extensions --------------------------------------------------------------------------------