From 935767fcedc2dad60775127f2f39433c76710906 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 18 Nov 2020 09:53:52 +0300 Subject: [PATCH 01/20] Remove unnecessary module dbcontexts --- ...ojectNameHttpApiHostMigrationsDbContext.cs | 6 - .../20201019021119_Initial.Designer.cs | 382 ------------------ .../Migrations/20201019021119_Initial.cs | 212 ---------- ...ApiHostMigrationsDbContextModelSnapshot.cs | 380 ----------------- 4 files changed, 980 deletions(-) delete mode 100644 templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/Migrations/20201019021119_Initial.Designer.cs delete mode 100644 templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/Migrations/20201019021119_Initial.cs delete mode 100644 templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/Migrations/MyProjectNameHttpApiHostMigrationsDbContextModelSnapshot.cs diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/EntityFrameworkCore/MyProjectNameHttpApiHostMigrationsDbContext.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/EntityFrameworkCore/MyProjectNameHttpApiHostMigrationsDbContext.cs index 9156f1e3ac..64fa317c51 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/EntityFrameworkCore/MyProjectNameHttpApiHostMigrationsDbContext.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/EntityFrameworkCore/MyProjectNameHttpApiHostMigrationsDbContext.cs @@ -1,8 +1,5 @@ using Microsoft.EntityFrameworkCore; -using Volo.Abp.AuditLogging.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore; -using Volo.Abp.PermissionManagement.EntityFrameworkCore; -using Volo.Abp.SettingManagement.EntityFrameworkCore; namespace MyCompanyName.MyProjectName.EntityFrameworkCore { @@ -19,9 +16,6 @@ namespace MyCompanyName.MyProjectName.EntityFrameworkCore base.OnModelCreating(modelBuilder); modelBuilder.ConfigureMyProjectName(); - modelBuilder.ConfigureAuditLogging(); - modelBuilder.ConfigurePermissionManagement(); - modelBuilder.ConfigureSettingManagement(); } } } diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/Migrations/20201019021119_Initial.Designer.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/Migrations/20201019021119_Initial.Designer.cs deleted file mode 100644 index 119214a82e..0000000000 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/Migrations/20201019021119_Initial.Designer.cs +++ /dev/null @@ -1,382 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using MyCompanyName.MyProjectName.EntityFrameworkCore; -using Volo.Abp.EntityFrameworkCore; - -namespace MyCompanyName.MyProjectName.Migrations -{ - [DbContext(typeof(MyProjectNameHttpApiHostMigrationsDbContext))] - [Migration("20201019021119_Initial")] - partial class Initial - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .UseIdentityColumns() - .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) - .HasAnnotation("Relational:MaxIdentifierLength", 128) - .HasAnnotation("ProductVersion", "5.0.0-rc.2.20475.6"); - - modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLog", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uniqueidentifier"); - - b.Property("ApplicationName") - .HasMaxLength(96) - .HasColumnType("nvarchar(96)") - .HasColumnName("ApplicationName"); - - b.Property("BrowserInfo") - .HasMaxLength(512) - .HasColumnType("nvarchar(512)") - .HasColumnName("BrowserInfo"); - - b.Property("ClientId") - .HasMaxLength(64) - .HasColumnType("nvarchar(64)") - .HasColumnName("ClientId"); - - b.Property("ClientIpAddress") - .HasMaxLength(64) - .HasColumnType("nvarchar(64)") - .HasColumnName("ClientIpAddress"); - - b.Property("ClientName") - .HasMaxLength(128) - .HasColumnType("nvarchar(128)") - .HasColumnName("ClientName"); - - b.Property("Comments") - .HasMaxLength(256) - .HasColumnType("nvarchar(256)") - .HasColumnName("Comments"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasMaxLength(40) - .HasColumnType("nvarchar(40)") - .HasColumnName("ConcurrencyStamp"); - - b.Property("CorrelationId") - .HasMaxLength(64) - .HasColumnType("nvarchar(64)") - .HasColumnName("CorrelationId"); - - b.Property("Exceptions") - .HasMaxLength(4000) - .HasColumnType("nvarchar(4000)") - .HasColumnName("Exceptions"); - - b.Property("ExecutionDuration") - .HasColumnType("int") - .HasColumnName("ExecutionDuration"); - - b.Property("ExecutionTime") - .HasColumnType("datetime2"); - - b.Property("ExtraProperties") - .HasColumnType("nvarchar(max)") - .HasColumnName("ExtraProperties"); - - b.Property("HttpMethod") - .HasMaxLength(16) - .HasColumnType("nvarchar(16)") - .HasColumnName("HttpMethod"); - - b.Property("HttpStatusCode") - .HasColumnType("int") - .HasColumnName("HttpStatusCode"); - - b.Property("ImpersonatorTenantId") - .HasColumnType("uniqueidentifier") - .HasColumnName("ImpersonatorTenantId"); - - b.Property("ImpersonatorUserId") - .HasColumnType("uniqueidentifier") - .HasColumnName("ImpersonatorUserId"); - - b.Property("TenantId") - .HasColumnType("uniqueidentifier") - .HasColumnName("TenantId"); - - b.Property("TenantName") - .HasColumnType("nvarchar(max)"); - - b.Property("Url") - .HasMaxLength(256) - .HasColumnType("nvarchar(256)") - .HasColumnName("Url"); - - b.Property("UserId") - .HasColumnType("uniqueidentifier") - .HasColumnName("UserId"); - - b.Property("UserName") - .HasMaxLength(256) - .HasColumnType("nvarchar(256)") - .HasColumnName("UserName"); - - b.HasKey("Id"); - - b.HasIndex("TenantId", "ExecutionTime"); - - b.HasIndex("TenantId", "UserId", "ExecutionTime"); - - b.ToTable("AbpAuditLogs"); - }); - - modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLogAction", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uniqueidentifier"); - - b.Property("AuditLogId") - .HasColumnType("uniqueidentifier") - .HasColumnName("AuditLogId"); - - b.Property("ExecutionDuration") - .HasColumnType("int") - .HasColumnName("ExecutionDuration"); - - b.Property("ExecutionTime") - .HasColumnType("datetime2") - .HasColumnName("ExecutionTime"); - - b.Property("ExtraProperties") - .HasColumnType("nvarchar(max)") - .HasColumnName("ExtraProperties"); - - b.Property("MethodName") - .HasMaxLength(128) - .HasColumnType("nvarchar(128)") - .HasColumnName("MethodName"); - - b.Property("Parameters") - .HasMaxLength(2000) - .HasColumnType("nvarchar(2000)") - .HasColumnName("Parameters"); - - b.Property("ServiceName") - .HasMaxLength(256) - .HasColumnType("nvarchar(256)") - .HasColumnName("ServiceName"); - - b.Property("TenantId") - .HasColumnType("uniqueidentifier") - .HasColumnName("TenantId"); - - b.HasKey("Id"); - - b.HasIndex("AuditLogId"); - - b.HasIndex("TenantId", "ServiceName", "MethodName", "ExecutionTime"); - - b.ToTable("AbpAuditLogActions"); - }); - - modelBuilder.Entity("Volo.Abp.AuditLogging.EntityChange", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uniqueidentifier"); - - b.Property("AuditLogId") - .HasColumnType("uniqueidentifier") - .HasColumnName("AuditLogId"); - - b.Property("ChangeTime") - .HasColumnType("datetime2") - .HasColumnName("ChangeTime"); - - b.Property("ChangeType") - .HasColumnType("tinyint") - .HasColumnName("ChangeType"); - - b.Property("EntityId") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("nvarchar(128)") - .HasColumnName("EntityId"); - - b.Property("EntityTenantId") - .HasColumnType("uniqueidentifier"); - - b.Property("EntityTypeFullName") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("nvarchar(128)") - .HasColumnName("EntityTypeFullName"); - - b.Property("ExtraProperties") - .HasColumnType("nvarchar(max)") - .HasColumnName("ExtraProperties"); - - b.Property("TenantId") - .HasColumnType("uniqueidentifier") - .HasColumnName("TenantId"); - - b.HasKey("Id"); - - b.HasIndex("AuditLogId"); - - b.HasIndex("TenantId", "EntityTypeFullName", "EntityId"); - - b.ToTable("AbpEntityChanges"); - }); - - modelBuilder.Entity("Volo.Abp.AuditLogging.EntityPropertyChange", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uniqueidentifier"); - - b.Property("EntityChangeId") - .HasColumnType("uniqueidentifier"); - - b.Property("NewValue") - .HasMaxLength(512) - .HasColumnType("nvarchar(512)") - .HasColumnName("NewValue"); - - b.Property("OriginalValue") - .HasMaxLength(512) - .HasColumnType("nvarchar(512)") - .HasColumnName("OriginalValue"); - - b.Property("PropertyName") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("nvarchar(128)") - .HasColumnName("PropertyName"); - - b.Property("PropertyTypeFullName") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("nvarchar(64)") - .HasColumnName("PropertyTypeFullName"); - - b.Property("TenantId") - .HasColumnType("uniqueidentifier") - .HasColumnName("TenantId"); - - b.HasKey("Id"); - - b.HasIndex("EntityChangeId"); - - b.ToTable("AbpEntityPropertyChanges"); - }); - - modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uniqueidentifier"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("nvarchar(128)"); - - b.Property("ProviderKey") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("nvarchar(64)"); - - b.Property("ProviderName") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("nvarchar(64)"); - - b.Property("TenantId") - .HasColumnType("uniqueidentifier") - .HasColumnName("TenantId"); - - b.HasKey("Id"); - - b.HasIndex("Name", "ProviderName", "ProviderKey"); - - b.ToTable("AbpPermissionGrants"); - }); - - modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uniqueidentifier"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("nvarchar(128)"); - - b.Property("ProviderKey") - .HasMaxLength(64) - .HasColumnType("nvarchar(64)"); - - b.Property("ProviderName") - .HasMaxLength(64) - .HasColumnType("nvarchar(64)"); - - b.Property("Value") - .IsRequired() - .HasMaxLength(2048) - .HasColumnType("nvarchar(2048)"); - - b.HasKey("Id"); - - b.HasIndex("Name", "ProviderName", "ProviderKey"); - - b.ToTable("AbpSettings"); - }); - - modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLogAction", b => - { - b.HasOne("Volo.Abp.AuditLogging.AuditLog", null) - .WithMany("Actions") - .HasForeignKey("AuditLogId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Volo.Abp.AuditLogging.EntityChange", b => - { - b.HasOne("Volo.Abp.AuditLogging.AuditLog", null) - .WithMany("EntityChanges") - .HasForeignKey("AuditLogId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Volo.Abp.AuditLogging.EntityPropertyChange", b => - { - b.HasOne("Volo.Abp.AuditLogging.EntityChange", null) - .WithMany("PropertyChanges") - .HasForeignKey("EntityChangeId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLog", b => - { - b.Navigation("Actions"); - - b.Navigation("EntityChanges"); - }); - - modelBuilder.Entity("Volo.Abp.AuditLogging.EntityChange", b => - { - b.Navigation("PropertyChanges"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/Migrations/20201019021119_Initial.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/Migrations/20201019021119_Initial.cs deleted file mode 100644 index 71b8ab569f..0000000000 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/Migrations/20201019021119_Initial.cs +++ /dev/null @@ -1,212 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -namespace MyCompanyName.MyProjectName.Migrations -{ - public partial class Initial : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "AbpAuditLogs", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - ApplicationName = table.Column(type: "nvarchar(96)", maxLength: 96, nullable: true), - UserId = table.Column(type: "uniqueidentifier", nullable: true), - UserName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), - TenantId = table.Column(type: "uniqueidentifier", nullable: true), - TenantName = table.Column(type: "nvarchar(max)", nullable: true), - ImpersonatorUserId = table.Column(type: "uniqueidentifier", nullable: true), - ImpersonatorTenantId = table.Column(type: "uniqueidentifier", nullable: true), - ExecutionTime = table.Column(type: "datetime2", nullable: false), - ExecutionDuration = table.Column(type: "int", nullable: false), - ClientIpAddress = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), - ClientName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), - ClientId = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), - CorrelationId = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), - BrowserInfo = table.Column(type: "nvarchar(512)", maxLength: 512, nullable: true), - HttpMethod = table.Column(type: "nvarchar(16)", maxLength: 16, nullable: true), - Url = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), - Exceptions = table.Column(type: "nvarchar(4000)", maxLength: 4000, nullable: true), - Comments = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), - HttpStatusCode = table.Column(type: "int", nullable: true), - ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true), - ConcurrencyStamp = table.Column(type: "nvarchar(40)", maxLength: 40, nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpAuditLogs", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "AbpPermissionGrants", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - TenantId = table.Column(type: "uniqueidentifier", nullable: true), - Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), - ProviderName = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false), - ProviderKey = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpPermissionGrants", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "AbpSettings", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - Name = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), - Value = table.Column(type: "nvarchar(2048)", maxLength: 2048, nullable: false), - ProviderName = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true), - ProviderKey = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpSettings", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "AbpAuditLogActions", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - TenantId = table.Column(type: "uniqueidentifier", nullable: true), - AuditLogId = table.Column(type: "uniqueidentifier", nullable: false), - ServiceName = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: true), - MethodName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: true), - Parameters = table.Column(type: "nvarchar(2000)", maxLength: 2000, nullable: true), - ExecutionTime = table.Column(type: "datetime2", nullable: false), - ExecutionDuration = table.Column(type: "int", nullable: false), - ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpAuditLogActions", x => x.Id); - table.ForeignKey( - name: "FK_AbpAuditLogActions_AbpAuditLogs_AuditLogId", - column: x => x.AuditLogId, - principalTable: "AbpAuditLogs", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "AbpEntityChanges", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - AuditLogId = table.Column(type: "uniqueidentifier", nullable: false), - TenantId = table.Column(type: "uniqueidentifier", nullable: true), - ChangeTime = table.Column(type: "datetime2", nullable: false), - ChangeType = table.Column(type: "tinyint", nullable: false), - EntityTenantId = table.Column(type: "uniqueidentifier", nullable: true), - EntityId = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), - EntityTypeFullName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), - ExtraProperties = table.Column(type: "nvarchar(max)", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpEntityChanges", x => x.Id); - table.ForeignKey( - name: "FK_AbpEntityChanges_AbpAuditLogs_AuditLogId", - column: x => x.AuditLogId, - principalTable: "AbpAuditLogs", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "AbpEntityPropertyChanges", - columns: table => new - { - Id = table.Column(type: "uniqueidentifier", nullable: false), - TenantId = table.Column(type: "uniqueidentifier", nullable: true), - EntityChangeId = table.Column(type: "uniqueidentifier", nullable: false), - NewValue = table.Column(type: "nvarchar(512)", maxLength: 512, nullable: true), - OriginalValue = table.Column(type: "nvarchar(512)", maxLength: 512, nullable: true), - PropertyName = table.Column(type: "nvarchar(128)", maxLength: 128, nullable: false), - PropertyTypeFullName = table.Column(type: "nvarchar(64)", maxLength: 64, nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_AbpEntityPropertyChanges", x => x.Id); - table.ForeignKey( - name: "FK_AbpEntityPropertyChanges_AbpEntityChanges_EntityChangeId", - column: x => x.EntityChangeId, - principalTable: "AbpEntityChanges", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateIndex( - name: "IX_AbpAuditLogActions_AuditLogId", - table: "AbpAuditLogActions", - column: "AuditLogId"); - - migrationBuilder.CreateIndex( - name: "IX_AbpAuditLogActions_TenantId_ServiceName_MethodName_ExecutionTime", - table: "AbpAuditLogActions", - columns: new[] { "TenantId", "ServiceName", "MethodName", "ExecutionTime" }); - - migrationBuilder.CreateIndex( - name: "IX_AbpAuditLogs_TenantId_ExecutionTime", - table: "AbpAuditLogs", - columns: new[] { "TenantId", "ExecutionTime" }); - - migrationBuilder.CreateIndex( - name: "IX_AbpAuditLogs_TenantId_UserId_ExecutionTime", - table: "AbpAuditLogs", - columns: new[] { "TenantId", "UserId", "ExecutionTime" }); - - migrationBuilder.CreateIndex( - name: "IX_AbpEntityChanges_AuditLogId", - table: "AbpEntityChanges", - column: "AuditLogId"); - - migrationBuilder.CreateIndex( - name: "IX_AbpEntityChanges_TenantId_EntityTypeFullName_EntityId", - table: "AbpEntityChanges", - columns: new[] { "TenantId", "EntityTypeFullName", "EntityId" }); - - migrationBuilder.CreateIndex( - name: "IX_AbpEntityPropertyChanges_EntityChangeId", - table: "AbpEntityPropertyChanges", - column: "EntityChangeId"); - - migrationBuilder.CreateIndex( - name: "IX_AbpPermissionGrants_Name_ProviderName_ProviderKey", - table: "AbpPermissionGrants", - columns: new[] { "Name", "ProviderName", "ProviderKey" }); - - migrationBuilder.CreateIndex( - name: "IX_AbpSettings_Name_ProviderName_ProviderKey", - table: "AbpSettings", - columns: new[] { "Name", "ProviderName", "ProviderKey" }); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "AbpAuditLogActions"); - - migrationBuilder.DropTable( - name: "AbpEntityPropertyChanges"); - - migrationBuilder.DropTable( - name: "AbpPermissionGrants"); - - migrationBuilder.DropTable( - name: "AbpSettings"); - - migrationBuilder.DropTable( - name: "AbpEntityChanges"); - - migrationBuilder.DropTable( - name: "AbpAuditLogs"); - } - } -} diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/Migrations/MyProjectNameHttpApiHostMigrationsDbContextModelSnapshot.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/Migrations/MyProjectNameHttpApiHostMigrationsDbContextModelSnapshot.cs deleted file mode 100644 index 5ede5096a0..0000000000 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/Migrations/MyProjectNameHttpApiHostMigrationsDbContextModelSnapshot.cs +++ /dev/null @@ -1,380 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using MyCompanyName.MyProjectName.EntityFrameworkCore; -using Volo.Abp.EntityFrameworkCore; - -namespace MyCompanyName.MyProjectName.Migrations -{ - [DbContext(typeof(MyProjectNameHttpApiHostMigrationsDbContext))] - partial class MyProjectNameHttpApiHostMigrationsDbContextModelSnapshot : ModelSnapshot - { - protected override void BuildModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .UseIdentityColumns() - .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.SqlServer) - .HasAnnotation("Relational:MaxIdentifierLength", 128) - .HasAnnotation("ProductVersion", "5.0.0-rc.2.20475.6"); - - modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLog", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uniqueidentifier"); - - b.Property("ApplicationName") - .HasMaxLength(96) - .HasColumnType("nvarchar(96)") - .HasColumnName("ApplicationName"); - - b.Property("BrowserInfo") - .HasMaxLength(512) - .HasColumnType("nvarchar(512)") - .HasColumnName("BrowserInfo"); - - b.Property("ClientId") - .HasMaxLength(64) - .HasColumnType("nvarchar(64)") - .HasColumnName("ClientId"); - - b.Property("ClientIpAddress") - .HasMaxLength(64) - .HasColumnType("nvarchar(64)") - .HasColumnName("ClientIpAddress"); - - b.Property("ClientName") - .HasMaxLength(128) - .HasColumnType("nvarchar(128)") - .HasColumnName("ClientName"); - - b.Property("Comments") - .HasMaxLength(256) - .HasColumnType("nvarchar(256)") - .HasColumnName("Comments"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasMaxLength(40) - .HasColumnType("nvarchar(40)") - .HasColumnName("ConcurrencyStamp"); - - b.Property("CorrelationId") - .HasMaxLength(64) - .HasColumnType("nvarchar(64)") - .HasColumnName("CorrelationId"); - - b.Property("Exceptions") - .HasMaxLength(4000) - .HasColumnType("nvarchar(4000)") - .HasColumnName("Exceptions"); - - b.Property("ExecutionDuration") - .HasColumnType("int") - .HasColumnName("ExecutionDuration"); - - b.Property("ExecutionTime") - .HasColumnType("datetime2"); - - b.Property("ExtraProperties") - .HasColumnType("nvarchar(max)") - .HasColumnName("ExtraProperties"); - - b.Property("HttpMethod") - .HasMaxLength(16) - .HasColumnType("nvarchar(16)") - .HasColumnName("HttpMethod"); - - b.Property("HttpStatusCode") - .HasColumnType("int") - .HasColumnName("HttpStatusCode"); - - b.Property("ImpersonatorTenantId") - .HasColumnType("uniqueidentifier") - .HasColumnName("ImpersonatorTenantId"); - - b.Property("ImpersonatorUserId") - .HasColumnType("uniqueidentifier") - .HasColumnName("ImpersonatorUserId"); - - b.Property("TenantId") - .HasColumnType("uniqueidentifier") - .HasColumnName("TenantId"); - - b.Property("TenantName") - .HasColumnType("nvarchar(max)"); - - b.Property("Url") - .HasMaxLength(256) - .HasColumnType("nvarchar(256)") - .HasColumnName("Url"); - - b.Property("UserId") - .HasColumnType("uniqueidentifier") - .HasColumnName("UserId"); - - b.Property("UserName") - .HasMaxLength(256) - .HasColumnType("nvarchar(256)") - .HasColumnName("UserName"); - - b.HasKey("Id"); - - b.HasIndex("TenantId", "ExecutionTime"); - - b.HasIndex("TenantId", "UserId", "ExecutionTime"); - - b.ToTable("AbpAuditLogs"); - }); - - modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLogAction", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uniqueidentifier"); - - b.Property("AuditLogId") - .HasColumnType("uniqueidentifier") - .HasColumnName("AuditLogId"); - - b.Property("ExecutionDuration") - .HasColumnType("int") - .HasColumnName("ExecutionDuration"); - - b.Property("ExecutionTime") - .HasColumnType("datetime2") - .HasColumnName("ExecutionTime"); - - b.Property("ExtraProperties") - .HasColumnType("nvarchar(max)") - .HasColumnName("ExtraProperties"); - - b.Property("MethodName") - .HasMaxLength(128) - .HasColumnType("nvarchar(128)") - .HasColumnName("MethodName"); - - b.Property("Parameters") - .HasMaxLength(2000) - .HasColumnType("nvarchar(2000)") - .HasColumnName("Parameters"); - - b.Property("ServiceName") - .HasMaxLength(256) - .HasColumnType("nvarchar(256)") - .HasColumnName("ServiceName"); - - b.Property("TenantId") - .HasColumnType("uniqueidentifier") - .HasColumnName("TenantId"); - - b.HasKey("Id"); - - b.HasIndex("AuditLogId"); - - b.HasIndex("TenantId", "ServiceName", "MethodName", "ExecutionTime"); - - b.ToTable("AbpAuditLogActions"); - }); - - modelBuilder.Entity("Volo.Abp.AuditLogging.EntityChange", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uniqueidentifier"); - - b.Property("AuditLogId") - .HasColumnType("uniqueidentifier") - .HasColumnName("AuditLogId"); - - b.Property("ChangeTime") - .HasColumnType("datetime2") - .HasColumnName("ChangeTime"); - - b.Property("ChangeType") - .HasColumnType("tinyint") - .HasColumnName("ChangeType"); - - b.Property("EntityId") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("nvarchar(128)") - .HasColumnName("EntityId"); - - b.Property("EntityTenantId") - .HasColumnType("uniqueidentifier"); - - b.Property("EntityTypeFullName") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("nvarchar(128)") - .HasColumnName("EntityTypeFullName"); - - b.Property("ExtraProperties") - .HasColumnType("nvarchar(max)") - .HasColumnName("ExtraProperties"); - - b.Property("TenantId") - .HasColumnType("uniqueidentifier") - .HasColumnName("TenantId"); - - b.HasKey("Id"); - - b.HasIndex("AuditLogId"); - - b.HasIndex("TenantId", "EntityTypeFullName", "EntityId"); - - b.ToTable("AbpEntityChanges"); - }); - - modelBuilder.Entity("Volo.Abp.AuditLogging.EntityPropertyChange", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uniqueidentifier"); - - b.Property("EntityChangeId") - .HasColumnType("uniqueidentifier"); - - b.Property("NewValue") - .HasMaxLength(512) - .HasColumnType("nvarchar(512)") - .HasColumnName("NewValue"); - - b.Property("OriginalValue") - .HasMaxLength(512) - .HasColumnType("nvarchar(512)") - .HasColumnName("OriginalValue"); - - b.Property("PropertyName") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("nvarchar(128)") - .HasColumnName("PropertyName"); - - b.Property("PropertyTypeFullName") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("nvarchar(64)") - .HasColumnName("PropertyTypeFullName"); - - b.Property("TenantId") - .HasColumnType("uniqueidentifier") - .HasColumnName("TenantId"); - - b.HasKey("Id"); - - b.HasIndex("EntityChangeId"); - - b.ToTable("AbpEntityPropertyChanges"); - }); - - modelBuilder.Entity("Volo.Abp.PermissionManagement.PermissionGrant", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uniqueidentifier"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("nvarchar(128)"); - - b.Property("ProviderKey") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("nvarchar(64)"); - - b.Property("ProviderName") - .IsRequired() - .HasMaxLength(64) - .HasColumnType("nvarchar(64)"); - - b.Property("TenantId") - .HasColumnType("uniqueidentifier") - .HasColumnName("TenantId"); - - b.HasKey("Id"); - - b.HasIndex("Name", "ProviderName", "ProviderKey"); - - b.ToTable("AbpPermissionGrants"); - }); - - modelBuilder.Entity("Volo.Abp.SettingManagement.Setting", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uniqueidentifier"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(128) - .HasColumnType("nvarchar(128)"); - - b.Property("ProviderKey") - .HasMaxLength(64) - .HasColumnType("nvarchar(64)"); - - b.Property("ProviderName") - .HasMaxLength(64) - .HasColumnType("nvarchar(64)"); - - b.Property("Value") - .IsRequired() - .HasMaxLength(2048) - .HasColumnType("nvarchar(2048)"); - - b.HasKey("Id"); - - b.HasIndex("Name", "ProviderName", "ProviderKey"); - - b.ToTable("AbpSettings"); - }); - - modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLogAction", b => - { - b.HasOne("Volo.Abp.AuditLogging.AuditLog", null) - .WithMany("Actions") - .HasForeignKey("AuditLogId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Volo.Abp.AuditLogging.EntityChange", b => - { - b.HasOne("Volo.Abp.AuditLogging.AuditLog", null) - .WithMany("EntityChanges") - .HasForeignKey("AuditLogId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Volo.Abp.AuditLogging.EntityPropertyChange", b => - { - b.HasOne("Volo.Abp.AuditLogging.EntityChange", null) - .WithMany("PropertyChanges") - .HasForeignKey("EntityChangeId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Volo.Abp.AuditLogging.AuditLog", b => - { - b.Navigation("Actions"); - - b.Navigation("EntityChanges"); - }); - - modelBuilder.Entity("Volo.Abp.AuditLogging.EntityChange", b => - { - b.Navigation("PropertyChanges"); - }); -#pragma warning restore 612, 618 - } - } -} From 9be7823c56aa93d031eb8b1163e5065e4596b210 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 18 Nov 2020 09:54:16 +0300 Subject: [PATCH 02/20] Add scopes --- .../angular/projects/dev-app/src/environments/environment.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/module/angular/projects/dev-app/src/environments/environment.ts b/templates/module/angular/projects/dev-app/src/environments/environment.ts index 06981b5f87..1a0f7b33ce 100644 --- a/templates/module/angular/projects/dev-app/src/environments/environment.ts +++ b/templates/module/angular/projects/dev-app/src/environments/environment.ts @@ -14,7 +14,7 @@ export const environment = { redirectUri: baseUrl, clientId: 'MyProjectName_App', responseType: 'code', - scope: 'offline_access MyProjectName', + scope: 'offline_access MyProjectName role email openid profile', }, apis: { default: { From 54ec6bdd26643f6555c87e806948e08c1c10ae81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 18 Nov 2020 10:47:07 +0300 Subject: [PATCH 03/20] Update Abp-4_0.md --- docs/en/Migration-Guides/Abp-4_0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/Migration-Guides/Abp-4_0.md b/docs/en/Migration-Guides/Abp-4_0.md index 50d2d34bf1..8bc4924000 100644 --- a/docs/en/Migration-Guides/Abp-4_0.md +++ b/docs/en/Migration-Guides/Abp-4_0.md @@ -2,7 +2,7 @@ This document introduces the breaking changes done in the ABP Framework 4.0 and explains how to fix your 3.x based solutions while upgrading to the ABP Framework 4.0. -> See this blog post (TODO: LINK) to learn what's new with the ABP Framework 4.0. This document only focuses on the breaking changes. +> See [the blog post](https://blog.abp.io/abp/ABP.IO-Platform-v4.0-RC-Has-Been-Released-based-on-.NET-5.0) to learn what's new with the ABP Framework 4.0. This document only focuses on the breaking changes. ## Overall From 3f680c424c413d5cf0bd0b579c2a0b7f415e162d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 18 Nov 2020 12:16:33 +0300 Subject: [PATCH 04/20] Blazor navigation-menu document completed. --- docs/en/UI/AspNetCore/Navigation-Menu.md | 12 ++ docs/en/UI/Blazor/Navigation-Menu.md | 205 ++++++++++++++++++++++- 2 files changed, 216 insertions(+), 1 deletion(-) diff --git a/docs/en/UI/AspNetCore/Navigation-Menu.md b/docs/en/UI/AspNetCore/Navigation-Menu.md index c6fc1cead8..762d6a4b0b 100644 --- a/docs/en/UI/AspNetCore/Navigation-Menu.md +++ b/docs/en/UI/AspNetCore/Navigation-Menu.md @@ -13,6 +13,8 @@ So, ABP Framework **provides a menu infrastructure** where; In order to add menu items (or manipulate the existing items) you need to create a class implementing the `IMenuContributor` interface. +> The [application startup template](../../Startup-Templates/Application.md) already contains an implementation of the `IMenuContributor`. So, you can add items inside that class instead of creating a new one. + **Example: Add a *CRM* menu item with *Customers* and *Orders* sub menu items** ```csharp @@ -66,6 +68,16 @@ Configure(options => }); ```` +This example uses some localization keys as display names those should be defined in the localization file: + +````json +"Menu:CRM": "CRM", +"Menu:Orders": "Orders", +"Menu:Customers": "Customers" +```` + +See the [localization document](../../Localization.md) to learn more about the localization. + When you run the application, you will see the menu items added to the main menu: ![nav-main-menu](../../images/nav-main-menu.png) diff --git a/docs/en/UI/Blazor/Navigation-Menu.md b/docs/en/UI/Blazor/Navigation-Menu.md index 81fca9f5ec..d47ef9fca5 100644 --- a/docs/en/UI/Blazor/Navigation-Menu.md +++ b/docs/en/UI/Blazor/Navigation-Menu.md @@ -1,3 +1,206 @@ # Blazor UI: Navigation / Menu -TODO \ No newline at end of file +Every application has a main menu to allow users to navigate to pages/screens of the application. Some applications may contain more than one menu in different sections of the UI. + +ABP Framework is a [modular](../../Module-Development-Basics.md) application development framework. **Every module may need to add items to the menu**. + +So, ABP Framework **provides a menu infrastructure** where; + +* The application or the modules can add items to a menu, without knowing how the menu is rendered. +* The [theme](Theming.md) properly renders the menu. + +## Adding Menu Items + +In order to add menu items (or manipulate the existing items) you need to create a class implementing the `IMenuContributor` interface. + +> The [application startup template](../../Startup-Templates/Application.md) already contains an implementation of the `IMenuContributor`. So, you can add items inside that class instead of creating a new one. + +**Example: Add a *CRM* menu item with *Customers* and *Orders* sub menu items** + +```csharp +using System.Threading.Tasks; +using MyProject.Localization; +using Volo.Abp.UI.Navigation; + +namespace MyProject.Web.Menus +{ + public class MyProjectMenuContributor : IMenuContributor + { + public async Task ConfigureMenuAsync(MenuConfigurationContext context) + { + if (context.Menu.Name == StandardMenus.Main) + { + await ConfigureMainMenuAsync(context); + } + } + + private async Task ConfigureMainMenuAsync(MenuConfigurationContext context) + { + var l = context.GetLocalizer(); + + context.Menu.AddItem( + new ApplicationMenuItem("MyProject.Crm", l["Menu:CRM"]) + .AddItem(new ApplicationMenuItem( + name: "MyProject.Crm.Customers", + displayName: l["Menu:Customers"], + url: "/crm/customers") + ).AddItem(new ApplicationMenuItem( + name: "MyProject.Crm.Orders", + displayName: l["Menu:Orders"], + url: "/crm/orders") + ) + ); + } + } +} +``` + +* This example adds items only to the main menu (`StandardMenus.Main`: see the *Standard Menus* section below). +* It gets a `IStringLocalizer` from `context` to [localize](../../Localization.md) the display names of the menu items. +* Adds the Customers and Orders as children of the CRM menu. + +Once you create a menu contributor, you need to add it to the `AbpNavigationOptions` in the `ConfigureServices` method of your module: + +````csharp +Configure(options => +{ + options.MenuContributors.Add(new MyProjectMenuContributor()); +}); +```` + +This example uses some localization keys as display names those should be defined in the localization file: + +````json +"Menu:CRM": "CRM", +"Menu:Orders": "Orders", +"Menu:Customers": "Customers" +```` + +See the [localization document](../../Localization.md) to learn more about the localization. + +When you run the application, you will see the menu items added to the main menu: + +![nav-main-menu](D:/Github/abp/docs/en/images/nav-main-menu.png) + +> The menu is rendered by the current UI [theme](Theming.md). So, the look of the main menu can be completely different based on your theme. + +Here, a few notes on the menu contributors; + +* ABP Framework calls the `ConfigureMenuAsync` method **whenever need to render** the menu. +* Every menu item can have **children**. So, you can add menu items with **unlimited depth** (however, your UI theme may not support unlimited depth). +* Only leaf menu items have `url`s normally. When you click to a parent menu, its sub menu is opened or closed, you don't navigate the `url` of a parent menu item. +* If a menu item has no children and has no `url` defined, then it is not rendered on the UI. This simplifies to authorize the menu items: You only authorize the child items (see the next section). If none of the children are authorized, then the parent automatically disappears. + +### Menu Item Properties + +There are more options of a menu item (the constructor of the `ApplicationMenuItem` class). Here, the list of all available options; + +* `name` (`string`, required): The **unique name** of the menu item. +* `displayName` (`string`, required): Display name/text of the menu item. You can [localize](../../Localization.md) this as shown before. +* `url` (`string`): The URL of the menu item. +* `icon` (`string`): An icon name. Free [Font Awesome](https://fontawesome.com/) icon classes are supported out of the box. Example: `fa fa-book`. You can use any CSS font icon class as long as you include the necessary CSS files to your application. +* `order` (`int`): The order of the menu item. Default value is `1000`. Items are sorted by the adding order unless you specify an order value. +* `customData` (`object`): A custom object that you can associate to the menu item and use it while rendering the menu item. +* `target` (`string`): Target of the menu item. Can be `null` (default), "\_*blank*", "\_*self*", "\_*parent*", "\_*top*" or a frame name for web applications. +* `elementId` (`string`): Can be used to render the element with a specific HTML `id` attribute. +* `cssClass` (`string`): Additional string classes for the menu item. + +### Authorization + +As seen above, a menu contributor contributes to the menu dynamically. So, you can perform any custom logic or get menu items from any source. + +One use case is the [authorization](Authorization.md). You typically want to add menu items by checking a permission. + +**Example: Check if the current user has a permission** + +````csharp +if (await context.IsGrantedAsync("MyPermissionName")) +{ + //...add menu items +} +```` + +> You can use `context.AuthorizationService` to directly access to the `IAuthorizationService`. + +### Resolving Dependencies + +`context.ServiceProvider` can be used to resolve any service dependency. + +**Example: Get a service** + +````csharp +var myService = context.ServiceProvider.GetRequiredService(); +//...use the service +```` + +> You don't need to care about releasing/disposing services. ABP Framework handles it. + +### The Administration Menu + +There is a special menu item in the menu menu that is added by the ABP Framework: The *Administration* menu. It is typically used by the pre-built admin [application modules](../../Modules/Index.md): + +![nav-main-menu-administration](D:/Github/abp/docs/en/images/nav-main-menu-administration.png) + +If you want to add menu items under the *Administration* menu item, you can use the `context.Menu.GetAdministration()` extension method: + +````csharp +context.Menu.GetAdministration().AddItem(...) +```` + +### Manipulating the Existing Menu Items + +ABP Framework executes the menu contributors by the [module dependency order](../../Module-Development-Basics.md). So, you can manipulate the menu items that your application or module (directly or indirectly) depends on. + +**Example: Set an icon for the `Users` menu item added by the [Identity Module](../../Modules/Identity.md)** + +````csharp +var userMenu = context.Menu.FindMenuItem(IdentityMenuNames.Users); +userMenu.Icon = "fa fa-users"; +```` + +> `context.Menu` gives you ability to access to all the menu items those have been added by the previous menu contributors. + +## Standard Menus + +A menu is a **named** component. An application may contain more than one menus with different, unique names. There are two pre-defined standard menus: + +* `Main`: The main menu of the application. Contains links to the page of the application. Defined as a constant: `Volo.Abp.UI.Navigation.StandardMenus.Main`. +* `User`: User profile menu. Defined as a constant: `Volo.Abp.UI.Navigation.StandardMenus.User`. + +The `Main` menu already covered above. The `User` menu is available when a user has logged in: + +![user-menu](D:/Github/abp/docs/en/images/user-menu.png) + +You can add items to the `User` menu by checking the `context.Menu.Name` as shown below: + +```csharp +if (context.Menu.Name == StandardMenus.User) +{ + //...add items +} +``` + +## IMenuManager + +`IMenuManager` is generally used by the UI [theme](Theming.md) to render the menu items on the UI. So, **you generally don't need to directly use** the `IMenuManager`. + +**Example: Getting the `Main` menu items** + +```csharp +// Code behind file of a razor component +public partial class NavMenu +{ + private readonly IMenuManager _menuManager; + + public NavMenu(IMenuManager menuManager) + { + _menuManager = menuManager; + } + + protected override async Task OnInitializedAsync() + { + var menu = await _menuManager.GetAsync(StandardMenus.Main); + } +} +``` + From d7d6d83bb06ae77b9cebe79ad0ec37f76e67158d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 18 Nov 2020 14:03:09 +0300 Subject: [PATCH 05/20] Added empty blazor page alerts document --- docs/en/UI/Blazor/Page-Alerts.md | 3 +++ docs/en/docs-nav.json | 4 ++++ 2 files changed, 7 insertions(+) create mode 100644 docs/en/UI/Blazor/Page-Alerts.md diff --git a/docs/en/UI/Blazor/Page-Alerts.md b/docs/en/UI/Blazor/Page-Alerts.md new file mode 100644 index 0000000000..20a6fd4df5 --- /dev/null +++ b/docs/en/UI/Blazor/Page-Alerts.md @@ -0,0 +1,3 @@ +# Blazor UI: Page Alerts + +TODO \ No newline at end of file diff --git a/docs/en/docs-nav.json b/docs/en/docs-nav.json index 49f438f964..401f3d6ac3 100644 --- a/docs/en/docs-nav.json +++ b/docs/en/docs-nav.json @@ -594,6 +594,10 @@ "text": "Toolbars", "path": "UI/Blazor/Toolbars.md" }, + { + "text": "Page Alerts", + "path": "UI/Blazor/Page-Alerts.md" + }, { "text": "Customization / Overriding Components", "path": "UI/Blazor/Customization-Overriding-Components.md" From 273fb7bfa1da2c23ac44869fa2cca34b9b8cc2dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 18 Nov 2020 14:39:23 +0300 Subject: [PATCH 06/20] Documented Blazor Theming. --- docs/en/UI/Blazor/Basic-Theme.md | 3 + docs/en/UI/Blazor/Navigation-Menu.md | 3 +- docs/en/UI/Blazor/Theming.md | 206 +++++++++++++++++- .../basic-theme-application-layout-blazor.png | Bin 0 -> 51585 bytes 4 files changed, 210 insertions(+), 2 deletions(-) create mode 100644 docs/en/UI/Blazor/Basic-Theme.md create mode 100644 docs/en/images/basic-theme-application-layout-blazor.png diff --git a/docs/en/UI/Blazor/Basic-Theme.md b/docs/en/UI/Blazor/Basic-Theme.md new file mode 100644 index 0000000000..2001277b10 --- /dev/null +++ b/docs/en/UI/Blazor/Basic-Theme.md @@ -0,0 +1,3 @@ +# Blazor UI: Basic Theme + +TODO \ No newline at end of file diff --git a/docs/en/UI/Blazor/Navigation-Menu.md b/docs/en/UI/Blazor/Navigation-Menu.md index d47ef9fca5..4508b3846f 100644 --- a/docs/en/UI/Blazor/Navigation-Menu.md +++ b/docs/en/UI/Blazor/Navigation-Menu.md @@ -184,7 +184,7 @@ if (context.Menu.Name == StandardMenus.User) `IMenuManager` is generally used by the UI [theme](Theming.md) to render the menu items on the UI. So, **you generally don't need to directly use** the `IMenuManager`. -**Example: Getting the `Main` menu items** +**Example: Get the Main Menu to render in a razor component** ```csharp // Code behind file of a razor component @@ -200,6 +200,7 @@ public partial class NavMenu protected override async Task OnInitializedAsync() { var menu = await _menuManager.GetAsync(StandardMenus.Main); + //... } } ``` diff --git a/docs/en/UI/Blazor/Theming.md b/docs/en/UI/Blazor/Theming.md index c73c37dfdd..c8ebc6ee2f 100644 --- a/docs/en/UI/Blazor/Theming.md +++ b/docs/en/UI/Blazor/Theming.md @@ -1,3 +1,207 @@ # Blazor UI: Theming -TODO \ No newline at end of file +## Introduction + +ABP Framework provides a complete **UI Theming** system with the following goals: + +* Reusable [application modules](../../Modules/Index.md) are developed **theme-independent**, so they can work with any UI theme. +* UI theme is **decided by the final application**. +* The theme is distributed via a NuGet package, so it is **easily upgradable**. +* The final application can **customize** the selected theme. + +In order to accomplish these goals, ABP Framework; + +* Determines a set of **base libraries** used and adapted by all the themes. So, module and application developers can depend on and use these libraries without depending on a particular theme. +* Provides a system that consists of layout parts (like [navigation menus](Navigation-Menu.md) and [toolbars](Toolbars.md)) that is implemented by all the themes. So, the modules and the application to contribute to the layout to compose a consistent application UI. + +### Current Themes + +Currently, two themes are **officially provided**: + +* The [Basic Theme](Basic-Theme.md) is the minimalist theme with the plain Bootstrap style. It is **open source and free**. +* The [Lepton Theme](https://commercial.abp.io/themes) is a **commercial** theme developed by the core ABP team and is a part of the [ABP Commercial](https://commercial.abp.io/) license. + +## Overall + +### The Base Libraries + +All the themes must depend on the [Volo.Abp.AspNetCore.Components.WebAssembly.Theming](https://www.nuget.org/packages/Volo.Abp.AspNetCore.Components.WebAssembly.Theming) NuGet package, so they are indirectly depending on the following libraries: + +* [Twitter Bootstrap](https://getbootstrap.com/) as the fundamental HTML/CSS framework. +* [Blazorise](https://github.com/stsrki/Blazorise) as a component library that supports the Bootstrap and adds extra components like Data Grid and Tree. +* [FontAwesome](https://fontawesome.com/) as the fundamental CSS font library. +* [Flag Icon](https://github.com/lipis/flag-icon-css) as a library to show flags of countries. + +These libraries are selected as the base libraries and available to the applications and modules. + +> Bootstrap's JavaScript part is not used since the Blazorise library already provides the necessary functionalities to the Bootstrap components in a native way. + +### The Layout + +All themes must define a layout for the application. The following image shows the user management page in the [Basic Theme](Basic-Theme.md) application layout: + +![basic-theme-application-layout-blazor](../../images/basic-theme-application-layout-blazor.png) + +And the same page is shown below with the [Lepton Theme](https://commercial.abp.io/themes) application layout: + +![lepton-theme-application-layout](../../images/lepton-theme-application-layout.png) + +As you can see, the page is the same, but the look is completely different in the themes above. + +The application layout typically includes the following parts; + +* A [main menu](Navigation-Menu.md) +* Main [Toolbar](Toolbars.md) with the following components; + * User menu + * Language switch dropdown +* [Page alerts](Page-Alerts.md) +* The page content (aka `@Body`) + +## Implementing a Theme + +A theme is simply a Razor Class Library. + +### The Easy Way + +The easiest way to create a new theme is to copy the [Basic Theme Source Code](https://github.com/abpframework/abp/tree/dev/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme) and customize it. Once you get a copy of the theme in your solution, remove the `Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic` NuGet package and reference to the local project. + +### Global Styles / Scripts + +A theme generally needs to add a global style to the page. ABP provides a system to manage the [Global Styles and Scripts](Global-Scripts-Styles.md). A theme can implement the `IBundleContributer` to add global style or script files to the page. + +**Example: Adding a style to the page** + +````csharp +using Volo.Abp.Bundling; + +namespace MyTheme +{ + public class MyThemeBundleContributer : IBundleContributer + { + public void AddScripts(BundleContext context) + { + + } + + public void AddStyles(BundleContext context) + { + context.Add("_content/MyTheme/styles.css"); + } + } +} +```` + +`styles.css` file should be added into the `wwwroot` folder of the theme project for this example. When you use the `abp bundle` command, this class is automatically discovered and executed to add the style to the page. + +See the [Global Styles and Scripts](Global-Scripts-Styles.md) document for more. + +### Layout Parts + +A typical Layout consists of several parts. The theme should include the necessary parts in each layout. + +**Example: The Basic Theme has the following parts for the Application Layout** + +![basic-theme-application-layout-parts](D:/Github/abp/docs/en/images/basic-theme-application-layout-parts.png) + +The application code and the modules can only show contents in the Page Content part. If they need to change the other parts (to add a menu item, to add a toolbar item, to change the application name in the branding area...) they should use the ABP Framework APIs. + +The following sections explain the fundamental parts pre-defined by the ABP Framework and can be implemented by the themes. + +> It is a good practice to split the layout into components/partials, so the final application can override them partially for customization purpose. + +#### Branding + +`IBrandingProvider` service should be used to get the name and the logo URL of the application to render in the Branding part. + +The [Application Startup Template](../../Startup-Templates/Application.md) has an implementation of this interface to set the values by the application developer. + +#### Main Menu + +`IMenuManager` service is used to get the main menu items and render on the layout. + +**Example: Get the Main Menu to render in a razor component** + +```csharp +// Code behind file of a razor component +public partial class NavMenu +{ + private readonly IMenuManager _menuManager; + + public NavMenu(IMenuManager menuManager) + { + _menuManager = menuManager; + } + + protected override async Task OnInitializedAsync() + { + var menu = await _menuManager.GetAsync(StandardMenus.Main); + //... + } +} +``` + +See the [Navigation / Menus](Navigation-Menu.md) document to learn more about the navigation system. + +#### Main Toolbar + +`IToolbarManager` service is used to get the Main Toolbar items and render on the layout. Each item of this toolbar is a Razor Component, so it may include any type of UI elements. Inject the `IToolbarManager` and use the `GetAsync` to get the toolbar items: + +````csharp +var toolbar = await _toolbarManager.GetAsync(StandardToolbars.Main); +```` + +> See the [Toolbars](Toolbars.md) document to learn more on the toolbar system. + +The theme has a responsibility to add two pre-defined items to the main toolbar: Language Selection and User Menu. To do that, create a class implementing the `IToolbarContributor` interface and add it to the `AbpToolbarOptions` as shown below: + +```csharp +Configure(options => +{ + options.Contributors.Add(new BasicThemeMainTopToolbarContributor()); +}); +``` + +##### Language Selection + +Language Selection toolbar item is generally a dropdown that is used to switch between languages. `ILanguageProvider` is used to get the list of available languages and `CultureInfo.CurrentUICulture` is used to learn the current language. + +Local Storage is used to get and set the current language with the `Abp.SelectedLanguage` key. + +**Example: Get the currently selected language** + +````csharp +var selectedLanguageName = await JsRuntime.InvokeAsync( + "localStorage.getItem", + "Abp.SelectedLanguage" + ); +```` + +**Example: Set the selected language** + +````csharp +await JsRuntime.InvokeVoidAsync( + "localStorage.setItem", + "Abp.SelectedLanguage", + "en-US" + ); +```` + +The theme should reload the page after changing the language: + +````csharp +await JsRuntime.InvokeVoidAsync("location.reload"); +```` + +##### User Menu + +User menu includes links related to the user account. `IMenuManager` is used just like the Main Menu, but this time with `StandardMenus.User` parameter like shown below: + +````csharp +var menu = await _menuManager.GetAsync(StandardMenus.User); +```` + +[ICurrentUser](../../CurrentUser.md) and [ICurrentTenant](../../Multi-Tenancy.md) services can be used to obtain the current user and tenant names. + +#### Page Alerts + +`IAlertManager` service is used to get the current page alerts to render on the layout. See the [Page Alerts](Page-Alerts.md) document to learn more. \ No newline at end of file diff --git a/docs/en/images/basic-theme-application-layout-blazor.png b/docs/en/images/basic-theme-application-layout-blazor.png new file mode 100644 index 0000000000000000000000000000000000000000..f01becad073cde35b281d90bbd7e7585bc240990 GIT binary patch literal 51585 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�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 J<(&sl{s%5PXf*%; literal 0 HcmV?d00001 From 74fa3737104b4dc04eacb71feec7ed0e1fbdcdda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 18 Nov 2020 16:05:54 +0300 Subject: [PATCH 07/20] Added Blazor UI branding doc. --- docs/en/UI/AspNetCore/Branding.md | 2 +- docs/en/UI/Blazor/Branding.md | 37 +++++++++++++++++++ docs/en/docs-nav.json | 4 ++ .../MyProjectNameBrandingProvider.cs | 4 +- 4 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 docs/en/UI/Blazor/Branding.md diff --git a/docs/en/UI/AspNetCore/Branding.md b/docs/en/UI/AspNetCore/Branding.md index ee19cd5845..e4a9ee0f3b 100644 --- a/docs/en/UI/AspNetCore/Branding.md +++ b/docs/en/UI/AspNetCore/Branding.md @@ -11,7 +11,7 @@ The screenshot below shows *MyProject* as the application name: You can implement the `IBrandingProvider` interface or inherit from the `DefaultBrandingProvider` to set the application name: ````csharp -using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Components; +using Volo.Abp.Ui.Branding; using Volo.Abp.DependencyInjection; namespace MyProject.Web diff --git a/docs/en/UI/Blazor/Branding.md b/docs/en/UI/Blazor/Branding.md new file mode 100644 index 0000000000..94bcb2bad5 --- /dev/null +++ b/docs/en/UI/Blazor/Branding.md @@ -0,0 +1,37 @@ +# Blazor UI: Branding + +## IBrandingProvider + +`IBrandingProvider` is a simple interface that is used to show the application name and logo on the layout. + +The screenshot below shows *MyProject* as the application name: + +![branding-nobrand](../../images/branding-nobrand.png) + +You can implement the `IBrandingProvider` interface or inherit from the `DefaultBrandingProvider` to set the application name: + +````csharp +using Volo.Abp.DependencyInjection; +using Volo.Abp.Ui.Branding; + +namespace MyCompanyName.MyProjectName.Blazor +{ + [Dependency(ReplaceServices = true)] + public class MyProjectNameBrandingProvider : DefaultBrandingProvider + { + public override string AppName => "Book Store"; + } +} +```` + +The result will be like shown below: + +![branding-appname](../../images/branding-appname.png) + +`IBrandingProvider` has the following properties: + +* `AppName`: The application name. +* `LogoUrl`: A URL to show the application logo. +* `LogoReverseUrl`: A URL to show the application logo on a reverse color theme (dark, for example). + +> **Tip**: `IBrandingProvider` is used in every page refresh. For a multi-tenant application, you can return a tenant specific application name to customize it per tenant. diff --git a/docs/en/docs-nav.json b/docs/en/docs-nav.json index 401f3d6ac3..bd0c17e98e 100644 --- a/docs/en/docs-nav.json +++ b/docs/en/docs-nav.json @@ -598,6 +598,10 @@ "text": "Page Alerts", "path": "UI/Blazor/Page-Alerts.md" }, + { + "text": "Branding", + "path": "UI/Blazor/Branding.md" + }, { "text": "Customization / Overriding Components", "path": "UI/Blazor/Customization-Overriding-Components.md" diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor/MyProjectNameBrandingProvider.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor/MyProjectNameBrandingProvider.cs index cada0bba19..711f36ad33 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor/MyProjectNameBrandingProvider.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor/MyProjectNameBrandingProvider.cs @@ -1,7 +1,9 @@ -using Volo.Abp.Ui.Branding; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Ui.Branding; namespace MyCompanyName.MyProjectName.Blazor { + [Dependency(ReplaceServices = true)] public class MyProjectNameBrandingProvider : DefaultBrandingProvider { public override string AppName => "MyProjectName"; From f4ad66f2e56965b28a49ad2235e2dc9a20af8e92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 18 Nov 2020 16:14:06 +0300 Subject: [PATCH 08/20] Complete the basic theme --- docs/en/UI/Blazor/Basic-Theme.md | 57 +++++++++++++++++++++++++++++++- docs/en/UI/Blazor/Theming.md | 2 +- 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/docs/en/UI/Blazor/Basic-Theme.md b/docs/en/UI/Blazor/Basic-Theme.md index 2001277b10..40e687ca2e 100644 --- a/docs/en/UI/Blazor/Basic-Theme.md +++ b/docs/en/UI/Blazor/Basic-Theme.md @@ -1,3 +1,58 @@ # Blazor UI: Basic Theme -TODO \ No newline at end of file +The Basic Theme is a theme implementation for the Blazor UI. It is a minimalist theme that doesn't add any styling on top of the plain [Bootstrap](https://getbootstrap.com/). You can take the Basic Theme as the **base theme** and build your own theme or styling on top of it. See the *Customization* section. + +> If you are looking for a professional, enterprise ready theme, you can check the [Lepton Theme](https://commercial.abp.io/themes), which is a part of the [ABP Commercial](https://commercial.abp.io/). + +> See the [Theming document](Theming.md) to learn about themes. + +## Installation + +**This theme is already installed** when you create a new solution using the [startup templates](../../Startup-Templates/Index.md). If you need to manually install it, follow the steps below: + +* Install the [Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme](https://www.nuget.org/packages/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme) NuGet package to your web project. +* Add `AbpAspNetCoreComponentsWebAssemblyBasicThemeModule` into the `[DependsOn(...)]` attribute for your [module class](../../Module-Development-Basics.md) in the your Blazor UI project. +* Use `Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme.Themes.Basic.App` as the root component of your application in the `ConfigureServices` method of your module: + +````csharp +var builder = context.Services.GetSingletonInstance(); +builder.RootComponents.Add("#ApplicationContainer"); +```` + +`#ApplicationContainer` is a selector (like `
Loading...
`) in the `index.html`. + +## The Layout + +![basic-theme-application-layout](../../images/basic-theme-application-layout.png) + +Application Layout implements the following parts, in addition to the common parts mentioned above; + +* [Branding](Branding.md) Area + +* Main [Menu](Navigation-Menu.md) +* Main [Toolbar](Toolbars.md) with Language Selection & User Menu +* [Page Alerts](Page-Alerts.md) + +## Customization + +You have two options two customize this theme: + +### Overriding Styles / Components + +In this approach, you continue to use the the theme as NuGet and NPM packages and customize the parts you need to. There are several ways to customize it; + +#### Override the Styles + +You can simply override the styles in the Global Styles file of your application. + +#### Override the Components + +See the [Customization / Overriding Components](Customization-Overriding-Components.md) to learn how you can replace components, customize and extend the user interface. + +### Copy & Customize + +You can download the [source code](https://github.com/abpframework/abp/tree/dev/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme) of the Basic Theme, copy the project content into your solution, re-arrange the package/module dependencies (see the Installation section above to understand how it was installed to the project) and freely customize the theme based on your application requirements. + +## See Also + +* [Theming](Theming.md) \ No newline at end of file diff --git a/docs/en/UI/Blazor/Theming.md b/docs/en/UI/Blazor/Theming.md index c8ebc6ee2f..9850915ada 100644 --- a/docs/en/UI/Blazor/Theming.md +++ b/docs/en/UI/Blazor/Theming.md @@ -101,7 +101,7 @@ A typical Layout consists of several parts. The theme should include the necessa **Example: The Basic Theme has the following parts for the Application Layout** -![basic-theme-application-layout-parts](D:/Github/abp/docs/en/images/basic-theme-application-layout-parts.png) +![basic-theme-application-layout-parts](../../images/basic-theme-application-layout-parts.png) The application code and the modules can only show contents in the Page Content part. If they need to change the other parts (to add a menu item, to add a toolbar item, to change the application name in the branding area...) they should use the ABP Framework APIs. From c7599ee2cf3073819f6ad34df1cb9c1f2f365f05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 18 Nov 2020 16:16:51 +0300 Subject: [PATCH 09/20] Added blazor basic theme to the doc-nav. --- docs/en/docs-nav.json | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/en/docs-nav.json b/docs/en/docs-nav.json index bd0c17e98e..3a174bb7b1 100644 --- a/docs/en/docs-nav.json +++ b/docs/en/docs-nav.json @@ -588,7 +588,13 @@ }, { "text": "Theming", - "path": "UI/Blazor/Theming.md" + "path": "UI/Blazor/Theming.md", + "items": [ + { + "text": "The Basic Theme", + "path": "UI/Blazor/Basic-Theme.md" + } + ] }, { "text": "Toolbars", From a842dbbf1d8546c2f8617d4917df8b194fe085f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 18 Nov 2020 16:28:11 +0300 Subject: [PATCH 10/20] Update Basic-Theme.md --- docs/en/UI/Blazor/Basic-Theme.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/en/UI/Blazor/Basic-Theme.md b/docs/en/UI/Blazor/Basic-Theme.md index 40e687ca2e..926d15cf11 100644 --- a/docs/en/UI/Blazor/Basic-Theme.md +++ b/docs/en/UI/Blazor/Basic-Theme.md @@ -28,7 +28,6 @@ builder.RootComponents.Add("#ApplicationContainer"); Application Layout implements the following parts, in addition to the common parts mentioned above; * [Branding](Branding.md) Area - * Main [Menu](Navigation-Menu.md) * Main [Toolbar](Toolbars.md) with Language Selection & User Menu * [Page Alerts](Page-Alerts.md) From 4ecd0a6956115e900c8d55f8f2a31d69fa474881 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 18 Nov 2020 16:40:43 +0300 Subject: [PATCH 11/20] Fix image paths. --- docs/en/UI/Blazor/Navigation-Menu.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/en/UI/Blazor/Navigation-Menu.md b/docs/en/UI/Blazor/Navigation-Menu.md index 4508b3846f..331de7a4cb 100644 --- a/docs/en/UI/Blazor/Navigation-Menu.md +++ b/docs/en/UI/Blazor/Navigation-Menu.md @@ -80,7 +80,7 @@ See the [localization document](../../Localization.md) to learn more about the l When you run the application, you will see the menu items added to the main menu: -![nav-main-menu](D:/Github/abp/docs/en/images/nav-main-menu.png) +![nav-main-menu](../../images/nav-main-menu.png) > The menu is rendered by the current UI [theme](Theming.md). So, the look of the main menu can be completely different based on your theme. @@ -139,7 +139,7 @@ var myService = context.ServiceProvider.GetRequiredService(); There is a special menu item in the menu menu that is added by the ABP Framework: The *Administration* menu. It is typically used by the pre-built admin [application modules](../../Modules/Index.md): -![nav-main-menu-administration](D:/Github/abp/docs/en/images/nav-main-menu-administration.png) +![nav-main-menu-administration](../../images/nav-main-menu-administration.png) If you want to add menu items under the *Administration* menu item, you can use the `context.Menu.GetAdministration()` extension method: @@ -169,7 +169,7 @@ A menu is a **named** component. An application may contain more than one menus The `Main` menu already covered above. The `User` menu is available when a user has logged in: -![user-menu](D:/Github/abp/docs/en/images/user-menu.png) +![user-menu](../../images/user-menu.png) You can add items to the `User` menu by checking the `context.Menu.Name` as shown below: From b0324f6b759877f24f1b80376e5cc1a2ee63eddf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 18 Nov 2020 16:54:37 +0300 Subject: [PATCH 12/20] Documented Blazor UI: Toolbars --- docs/en/UI/Blazor/Toolbars.md | 74 +++++++++++++++++- .../blazor-notification-bell-component.png | Bin 0 -> 17540 bytes 2 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 docs/en/images/blazor-notification-bell-component.png diff --git a/docs/en/UI/Blazor/Toolbars.md b/docs/en/UI/Blazor/Toolbars.md index 25c5f077a2..011531a141 100644 --- a/docs/en/UI/Blazor/Toolbars.md +++ b/docs/en/UI/Blazor/Toolbars.md @@ -1,3 +1,75 @@ # Blazor UI: Toolbars -TODO \ No newline at end of file +The Toolbar system is used to define **toolbars** on the user interface. Modules (or your application) can add **items** to a toolbar, then the [theme](Theming.md) renders the toolbar on the **layout**. + +There is only one **standard toolbar** named "Main" (defined as a constant: `StandardToolbars.Main`). The [Basic Theme](Basic-Theme) renders the main toolbar as shown below: + +![bookstore-toolbar-highlighted](../../images/bookstore-toolbar-highlighted.png) + +In the screenshot above, there are two items added to the main toolbar: Language switch component & user menu. You can add your own items here. + +## Example: Add a Notification Icon + +In this example, we will add a **notification (bell) icon** to the left of the language switch item. A item in the toolbar should be a **Razor Component**. So, first, create a new razor component in your project (the location of the component doesn't matter): + +![bookstore-notification-view-component](../../images/blazor-notification-bell-component.png) + +The content of the `Notification.razor` is shown below: + +````html +@inherits Volo.Abp.AspNetCore.Components.AbpComponentBase +
+ +
+@code { + private async Task ShowNotifications() + { + await Message.Info("TODO: Show notifications"); + } +} +```` + +This sample simply shows a message. In real life, you probably want to call an HTTP API to get notifications and show on the UI. + +Now, we can create a class implementing the `IToolbarContributor` interface: + +````csharp +using System.Threading.Tasks; +using MyCompanyName.MyProjectName.Blazor.Components; +using Volo.Abp.AspNetCore.Components.WebAssembly.Theming.Toolbars; + +namespace MyCompanyName.MyProjectName.Blazor +{ + public class MyToolbarContributor : IToolbarContributor + { + public Task ConfigureToolbarAsync(IToolbarConfigurationContext context) + { + if (context.Toolbar.Name == StandardToolbars.Main) + { + context.Toolbar.Items.Insert(0, new ToolbarItem(typeof(Notification))); + } + + return Task.CompletedTask; + } + } +} +```` + +This class adds the `NotificationViewComponent` as the first item in the `Main` toolbar. + +Finally, you need to add this contributor to the `AbpToolbarOptions`, in the `ConfigureServices` of your [module](../../Module-Development-Basics.md): + +````csharp +Configure(options => +{ + options.Contributors.Add(new MyToolbarContributor()); +}); +```` + +That's all, you will see the notification icon on the toolbar when you run the application: + +![bookstore-notification-icon-on-toolbar](D:/Github/abp/docs/en/images/bookstore-notification-icon-on-toolbar.png) + +## IToolbarManager + +`IToolbarManager` is used to render the toolbar. It returns the toolbar items by a toolbar name. This is generally used by the [themes](Theming.md) to render the toolbar on the layout. \ No newline at end of file diff --git a/docs/en/images/blazor-notification-bell-component.png b/docs/en/images/blazor-notification-bell-component.png new file mode 100644 index 0000000000000000000000000000000000000000..65934ec24bc556adcc42461a36489b0c195ed787 GIT binary patch literal 17540 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 K5~X4veE$!J^(qno literal 0 HcmV?d00001 From b3bec0823b2927ead89bd98ddea0721496740fbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 18 Nov 2020 17:04:10 +0300 Subject: [PATCH 13/20] Blazor UI: Settings documented --- docs/en/UI/Blazor/Settings.md | 62 ++++++++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/docs/en/UI/Blazor/Settings.md b/docs/en/UI/Blazor/Settings.md index 276462c411..e146b7ea69 100644 --- a/docs/en/UI/Blazor/Settings.md +++ b/docs/en/UI/Blazor/Settings.md @@ -1,3 +1,63 @@ # Blazor UI: Settings -Blazor applications can reuse the same `ISettingProvider` service that is explained in the [settings document](../../Settings.md). \ No newline at end of file +Blazor applications can reuse the same `ISettingProvider` service that is explained in the [settings document](../../Settings.md). + +## ISettingProvider + +`ISettingProvider` is used to get the value of a setting or get the values of all the settings. + +**Example usages in a simple service** + +````csharp +public class MyService : ITransientDependency +{ + private readonly ISettingProvider _settingProvider; + + //Inject ISettingProvider in the constructor + public MyService(ISettingProvider settingProvider) + { + _settingProvider = settingProvider; + } + + public async Task FooAsync() + { + //Get a value as string. + string setting1 = await _settingProvider.GetOrNullAsync("MySettingName"); + + //Get a bool value and fallback to the default value (false) if not set. + bool setting2 = await _settingProvider.GetAsync("MyBoolSettingName"); + + //Get a bool value and fallback to the provided default value (true) if not set. + bool setting3 = await _settingProvider.GetAsync( + "MyBoolSettingName", defaultValue: true); + + //Get a bool value with the IsTrueAsync shortcut extension method + bool setting4 = await _settingProvider.IsTrueAsync("MyBoolSettingName"); + + //Get an int value or the default value (0) if not set + int setting5 = (await _settingProvider.GetAsync("MyIntegerSettingName")); + + //Get an int value or null if not provided + int? setting6 = (await _settingProvider + .GetOrNullAsync("MyIntegerSettingName"))?.To(); + } +} +```` + +**Example usage in a Razor Component** + +````csharp +@page "/" +@using Volo.Abp.Settings +@inject ISettingProvider SettingProvider +@code { + protected override async Task OnInitializedAsync() + { + bool settingValue = await SettingProvider.GetAsync("MyBoolSettingName"); + } +} +```` + +## See Also + +* [Settings](../../Settings.md) \ No newline at end of file From 842eee855a69fec3893f7c2449e9b747866911f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 18 Nov 2020 17:05:21 +0300 Subject: [PATCH 14/20] Update Toolbars.md --- docs/en/UI/Blazor/Toolbars.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/UI/Blazor/Toolbars.md b/docs/en/UI/Blazor/Toolbars.md index 011531a141..b8cca6077a 100644 --- a/docs/en/UI/Blazor/Toolbars.md +++ b/docs/en/UI/Blazor/Toolbars.md @@ -68,7 +68,7 @@ Configure(options => That's all, you will see the notification icon on the toolbar when you run the application: -![bookstore-notification-icon-on-toolbar](D:/Github/abp/docs/en/images/bookstore-notification-icon-on-toolbar.png) +![bookstore-notification-icon-on-toolbar](../../images/bookstore-notification-icon-on-toolbar.png) ## IToolbarManager From 6007e1b5b5841ee7b5c31bcf6d1b19bc7b581d96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 18 Nov 2020 17:25:26 +0300 Subject: [PATCH 15/20] Make MyProjectNameComponentBase abstract. --- .../MyProjectNameComponentBase.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor/MyProjectNameComponentBase.cs b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor/MyProjectNameComponentBase.cs index 91384e47c3..b6c05db0ab 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor/MyProjectNameComponentBase.cs +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor/MyProjectNameComponentBase.cs @@ -3,9 +3,9 @@ using Volo.Abp.AspNetCore.Components; namespace MyCompanyName.MyProjectName.Blazor { - public class MyProjectNameComponentBase : AbpComponentBase + public abstract class MyProjectNameComponentBase : AbpComponentBase { - public MyProjectNameComponentBase() + protected MyProjectNameComponentBase() { LocalizationResource = typeof(MyProjectNameResource); } From a6ceaf74c25cacd11d76c0d02f361cbe86f143ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 18 Nov 2020 17:25:42 +0300 Subject: [PATCH 16/20] Blazor UI: Localization document completed. --- docs/en/UI/Blazor/Localization.md | 77 ++++++++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) diff --git a/docs/en/UI/Blazor/Localization.md b/docs/en/UI/Blazor/Localization.md index e6cf761ce3..d42249388e 100644 --- a/docs/en/UI/Blazor/Localization.md +++ b/docs/en/UI/Blazor/Localization.md @@ -1,3 +1,78 @@ # Blazor UI: Localization -Blazor applications can reuse the same `IStringLocalizer` service that is explained in the [localization document](../../Localization.md). All the localization resources and texts available in the server side are usable in the Blazor application. \ No newline at end of file +Blazor applications can reuse the same `IStringLocalizer` service that is explained in the [localization document](../../Localization.md). + +All the localization resources and texts available in the server side are usable in the Blazor application. + +## IStringLocalizer + +`IStringLocalizer` (`T` is the localization resource class) can be injected in any service or component to use the localization service. + +### Razor Components + +Use `@inject IStringLocalizer` to use the localization in a razor component. + +**Example: Localization in a Razor Component** + +````csharp +@page "/" +@using MyCompanyName.MyProjectName.Localization +@using Microsoft.Extensions.Localization +@inject IStringLocalizer L + +

+ @L["LongWelcomeMessage"] +

+```` + +> `L` is a name that we love and use as the name of a `IStringLocalizer` instance, while you can give any name. + +#### The AbpComponentBase + +`AbpComponentBase` is a useful base class that you can derive the components from. It has some useful properties/methods you typically need in a component. + +The `AbpComponentBase` already defines a base `L` property (of type `IStringLocalizer`). It only requires to set the resource type (in the constructor of the derived class). If you created your application from the ABP's application startup template, then you should have a *YourProjectComponentBase* class in the Blazor project. Inherit components from this class to have the localizer pre-injected. + +**Example: Derive from the base component class** + +````csharp +@page "/" +@inherits MyProjectNameComponentBase + +

+ @L["LongWelcomeMessage"] +

+```` + +### Other Services + +`IStringLocalizer` can be injected into any service. + +**Example** + +````csharp +public class MyService : ITransientDependency +{ + private readonly IStringLocalizer _localizer; + + public MyService(IStringLocalizer localizer) + { + _localizer = localizer; + } + + public void Foo() + { + var str = _localizer["HelloWorld"]; + } +} +```` + +### Format Arguments + +Format arguments can be passed after the localization key. If your message is `Hello {0}, welcome!`, then you can pass the `{0}` argument to the localizer like `_localizer["HelloMessage", "John"]`. + +> Refer to the [Microsoft's localization documentation](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/localization) for details about using the localization. + +## See Also + +* [Localization](../../Localization.md) \ No newline at end of file From 26e6bb660a17fb7631e285e43f40ce85c83c157e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 18 Nov 2020 18:12:55 +0300 Subject: [PATCH 17/20] Extract Branding for the Basic Theme for the Blazor UI --- .../Themes/Basic/Branding.razor | 3 +++ .../Themes/Basic/MainLayout.razor | 4 +--- 2 files changed, 4 insertions(+), 3 deletions(-) create mode 100644 framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/Branding.razor diff --git a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/Branding.razor b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/Branding.razor new file mode 100644 index 0000000000..4810320664 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/Branding.razor @@ -0,0 +1,3 @@ +@using Volo.Abp.Ui.Branding +@inject IBrandingProvider BrandingProvider +
@BrandingProvider.AppName diff --git a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/MainLayout.razor b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/MainLayout.razor index 20b96bef45..e85e899123 100644 --- a/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/MainLayout.razor +++ b/framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/MainLayout.razor @@ -1,9 +1,7 @@ @inherits LayoutComponentBase -@using Volo.Abp.Ui.Branding -@inject IBrandingProvider BrandingProvider