mirror of https://github.com/abpframework/abp
commit
60f6c3bd4f
@ -0,0 +1,236 @@
|
||||
# Moving Background Job Execution To A Separate Application
|
||||
|
||||
In this article, I will show you how to move the background job execution to a separate application.
|
||||
|
||||
Here are some benefits of doing this:
|
||||
|
||||
* If your background jobs consume high system resources (CPU, RAM or Disk), then you can deploy that background application to a dedicated server so it won't affect your application's performance.
|
||||
* You can scale your background job application independently from your web application. For example, you can deploy multiple instances of your background job application to a Kubernetes cluster and scale it easily.
|
||||
|
||||
Here are some disadvantages of doing this:
|
||||
|
||||
* You need to deploy and maintain at least two applications instead of one.
|
||||
* You need to implement a mechanism to share the common code between your applications. For example, you can create a shared project and add it to your applications as a project reference.
|
||||
|
||||
## Source code
|
||||
|
||||
You can find the source code of the application at [abpframework/abp-samples](https://github.com/abpframework/abp-samples/tree/master/SeparateBackgroundJob).
|
||||
|
||||
You can check the PR to see the changes step by step: [abpframework/abp-samples#250](https://github.com/abpframework/abp-samples/pull/250)
|
||||
|
||||
## Creating the Web Application
|
||||
|
||||
First, we need to create a new web application using the ABP CLI:
|
||||
|
||||
```bash
|
||||
abp new SeparateBackgroundJob -t app
|
||||
```
|
||||
|
||||
* Create a shared project named `SeparateBackgroundJob.Common.Shared` to share the `BackgroundJob` and `BackgroundJobArgs` classes between the web and job executor applications.
|
||||
* Install the `Volo.Abp.BackgroundJobs.Abstractions` package to the `SeparateBackgroundJob.Common.Shared` project.
|
||||
|
||||
Add the `SeparateBackgroundJobCommonSharedModule` class to the `SeparateBackgroundJob.Common.Shared` project:
|
||||
|
||||
```csharp
|
||||
[DependsOn(typeof(AbpBackgroundJobsAbstractionsModule))]
|
||||
public class SeparateBackgroundJobCommonSharedModule : AbpModule
|
||||
{
|
||||
}
|
||||
```
|
||||
|
||||
Add the `MyReportJob` and `MyReportJobArgs` classes to the `SeparateBackgroundJob.Common.Shared` project:
|
||||
|
||||
```csharp
|
||||
public class MyReportJob : AsyncBackgroundJob<MyReportJobArgs>, ITransientDependency
|
||||
{
|
||||
public override Task ExecuteAsync(MyReportJobArgs args)
|
||||
{
|
||||
Logger.LogInformation("Executing MyReportJob with args: {0}", args.Content);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
public class MyReportJobArgs
|
||||
{
|
||||
public string? Content { get; set; }
|
||||
}
|
||||
```
|
||||
|
||||
Add the `SeparateBackgroundJob.Common.Shared` project reference to the `SeparateBackgroundJob.Domain` project and add `SeparateBackgroundJobCommonSharedModule` to the `DependsOn` attribute of the `SeparateBackgroundJobDomainModule` class:
|
||||
|
||||
```csharp
|
||||
[DependsOn(
|
||||
typeof(SeparateBackgroundJobDomainSharedModule),
|
||||
typeof(AbpAuditLoggingDomainModule),
|
||||
typeof(AbpBackgroundJobsDomainModule),
|
||||
typeof(AbpFeatureManagementDomainModule),
|
||||
typeof(AbpIdentityDomainModule),
|
||||
typeof(AbpOpenIddictDomainModule),
|
||||
typeof(AbpPermissionManagementDomainOpenIddictModule),
|
||||
typeof(AbpPermissionManagementDomainIdentityModule),
|
||||
typeof(AbpSettingManagementDomainModule),
|
||||
typeof(AbpTenantManagementDomainModule),
|
||||
typeof(AbpEmailingModule),
|
||||
typeof(SeparateBackgroundJobCommonSharedModule) //Add this line
|
||||
)]
|
||||
public class SeparateBackgroundJobDomainModule : AbpModule
|
||||
```
|
||||
|
||||
Open the `Index.cshtml` and replace the content with the following code:
|
||||
|
||||
```csharp
|
||||
@page
|
||||
@using Microsoft.AspNetCore.Mvc.Localization
|
||||
@using SeparateBackgroundJob.Localization
|
||||
@using Volo.Abp.Users
|
||||
@model SeparateBackgroundJob.Web.Pages.IndexModel
|
||||
@inject IHtmlLocalizer<SeparateBackgroundJobResource> L
|
||||
@inject ICurrentUser CurrentUser
|
||||
|
||||
@section styles {
|
||||
<abp-style src="/Pages/Index.css"/>
|
||||
}
|
||||
|
||||
@section scripts {
|
||||
<abp-script src="/Pages/Index.js"/>
|
||||
}
|
||||
|
||||
<div class="container">
|
||||
<abp-card>
|
||||
<abp-card-header>
|
||||
<abp-card-title>
|
||||
Add NEW BACKGROUND JOB
|
||||
</abp-card-title>
|
||||
</abp-card-header>
|
||||
<abp-card-body>
|
||||
<form id="NewItemForm" method="post" class="row row-cols-lg-auto g-3 align-items-center">
|
||||
<div class="col-12">
|
||||
<div class="input-group">
|
||||
<input id="ReportContent" required name="ReportContent" type="text" class="form-control" placeholder="enter text...">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<button type="submit" class="btn btn-primary">Add</button>
|
||||
</div>
|
||||
</form>
|
||||
</abp-card-body>
|
||||
</abp-card>
|
||||
</div>
|
||||
```
|
||||
|
||||
Open the `Index.cshtml.cs` and replace the content with the following code:
|
||||
|
||||
```csharp
|
||||
public class IndexModel : SeparateBackgroundJobPageModel
|
||||
{
|
||||
private readonly IBackgroundJobManager _backgroundJobManager;
|
||||
|
||||
[BindProperty(SupportsGet = true)]
|
||||
public string? ReportContent { get; set; }
|
||||
|
||||
public IndexModel(IBackgroundJobManager backgroundJobManager)
|
||||
{
|
||||
_backgroundJobManager = backgroundJobManager;
|
||||
}
|
||||
|
||||
public void OnGet()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public async Task OnPostAsync()
|
||||
{
|
||||
await _backgroundJobManager.EnqueueAsync(new MyReportJobArgs
|
||||
{
|
||||
Content = ReportContent
|
||||
});
|
||||
|
||||
Alerts.Success("Job is queued!");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Run the application and navigate to the home page. You should see the following page:
|
||||
|
||||
![1](images/1.png)
|
||||
|
||||
When you enter some text and click the **Add** button, the job will be queued and executed in the web application:
|
||||
|
||||
## Creating the Console Application
|
||||
|
||||
Now we split the background job execution to a separate console application.
|
||||
|
||||
Open the `SeparateBackgroundJobWebModule` class to disable the background job execution in the web application:
|
||||
|
||||
```csharp
|
||||
public class SeparateBackgroundJobWebModule : AbpModule
|
||||
{
|
||||
....
|
||||
|
||||
public override void ConfigureServices(ServiceConfigurationContext context)
|
||||
{
|
||||
...
|
||||
|
||||
//Disable background job execution in the web application
|
||||
Configure<AbpBackgroundJobOptions>(options =>
|
||||
{
|
||||
options.IsJobExecutionEnabled = false;
|
||||
});
|
||||
}
|
||||
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
* Create a new console application using the ABP CLI:
|
||||
|
||||
```bash
|
||||
abp new BackgroundJobExecutor -t console
|
||||
```
|
||||
|
||||
* Add the `BackgroundJobExecutor` project to the solution of the web application.
|
||||
* Add the `SeparateBackgroundJob.Common.Shared` project reference to the `BackgroundJobExecutor` project.
|
||||
* Install the `Volo.Abp.BackgroundJobs.EntityFrameworkCore` and `Volo.Abp.EntityFrameworkCore.SqlServer` packages to the `BackgroundJobExecutor` project.
|
||||
|
||||
Update the `BackgroundJobExecutorModule` class as follows:
|
||||
|
||||
```csharp
|
||||
[DependsOn(
|
||||
typeof(AbpAutofacModule),
|
||||
typeof(AbpBackgroundJobsEntityFrameworkCoreModule),
|
||||
typeof(AbpEntityFrameworkCoreSqlServerModule),
|
||||
typeof(SeparateBackgroundJobCommonSharedModule)
|
||||
)]
|
||||
public class BackgroundJobExecutorModule : AbpModule
|
||||
{
|
||||
public override void ConfigureServices(ServiceConfigurationContext context)
|
||||
{
|
||||
Configure<AbpDbContextOptions>(options =>
|
||||
{
|
||||
options.UseSqlServer();
|
||||
});
|
||||
}
|
||||
|
||||
....
|
||||
}
|
||||
```
|
||||
|
||||
Open the `appsettings.json` file to configure the [connection string](https://docs.abp.io/en/abp/latest/Connection-Strings#configure-the-connection-strings):
|
||||
|
||||
```json
|
||||
{
|
||||
"ConnectionStrings": {
|
||||
"AbpBackgroundJobs": "Server=(LocalDb)\\MSSQLLocalDB;Database=SeparateBackgroundJob;Trusted_Connection=True"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> You must use the same connection string for the web application, `AbpBackgroundJobs` is the default connection string name for the background job module.
|
||||
|
||||
The solution structure should look like this:
|
||||
|
||||
![solution](images/solution.png)
|
||||
|
||||
Now, run the web and console application. When you enter some text and click the **Add** button, the job will be queued and executed in the console application:
|
||||
|
||||
![2](images/2.png)
|
After Width: | Height: | Size: 140 KiB |
After Width: | Height: | Size: 376 KiB |
After Width: | Height: | Size: 102 KiB |
@ -0,0 +1,12 @@
|
||||
using System.Collections.Generic;
|
||||
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
|
||||
|
||||
namespace Volo.Abp.AspNetCore.Mvc.UI.Packages.Zxcvbn;
|
||||
|
||||
public class ZxcvbnScriptContributor : BundleContributor
|
||||
{
|
||||
public override void ConfigureBundle(BundleConfigurationContext context)
|
||||
{
|
||||
context.Files.AddIfNotContains("/libs/zxcvbn/zxcvbn.js");
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Volo.Abp.Cli.ProjectBuilding.Building;
|
||||
|
||||
namespace Volo.Abp.Cli.ProjectBuilding.Templates;
|
||||
|
||||
public class CheckRedisPreRequirements : ProjectBuildPipelineStep
|
||||
{
|
||||
public override void Execute(ProjectBuildContext context)
|
||||
{
|
||||
var modules = context.Files.Where(f => f.Name.EndsWith("Module.cs", StringComparison.OrdinalIgnoreCase));
|
||||
if (modules.Any(module => module.Content.Contains("Redis:Configuration")))
|
||||
{
|
||||
context.BuildArgs.ExtraProperties["PreRequirements:Redis"] = "true";
|
||||
}
|
||||
}
|
||||
}
|
@ -1,228 +1,229 @@
|
||||
{
|
||||
"culture": "en",
|
||||
"texts": {
|
||||
"AddSubMenuItem": "Add Sub Menu Item",
|
||||
"AreYouSure": "Are You Sure?",
|
||||
"BlogDeletionConfirmationMessage": "The blog '{0}' will be deleted. Are you sure?",
|
||||
"BlogFeatureNotAvailable": "This feature is not available now. Enable with 'GlobalFeatureManager' to use it.",
|
||||
"BlogId": "Blog",
|
||||
"BlogPostDeletionConfirmationMessage": "The blog post '{0}' will be deleted. Are you sure?",
|
||||
"BlogPosts": "Blog Posts",
|
||||
"Blogs": "Blogs",
|
||||
"ChoosePreference": "Choose Preference...",
|
||||
"Cms": "CMS",
|
||||
"CmsKit.Comments": "Comments",
|
||||
"CmsKit.Ratings": "Ratings",
|
||||
"CmsKit.Reactions": "Reactions",
|
||||
"CmsKit.Tags": "Tags",
|
||||
"CmsKit:0002": "Content already exists!",
|
||||
"CmsKit:0003": "The entity {0} is not taggable.",
|
||||
"CmsKit:Blog:0001": "The given slug ({Slug}) already exists!",
|
||||
"CmsKit:BlogPost:0001": "The given slug already exists!",
|
||||
"CmsKit:Comments:0001": "The entity {EntityType} is not commentable.",
|
||||
"CmsKit:Media:0001": "'{Name}' is not a valid media name.",
|
||||
"CmsKit:Media:0002": "The entity can't have media.",
|
||||
"CmsKit:Page:0001": "The given url ({Slug}) already exists. Please try with different url.",
|
||||
"CmsKit:Rating:0001": "The entity {EntityType} can't be rated.",
|
||||
"CmsKit:Reaction:0001": "The entity {EntityType} can't have reactions.",
|
||||
"CmsKit:Tag:0002": "The entity is not taggable!",
|
||||
"CommentAuthorizationExceptionMessage": "Those comments are not allowed for public display.",
|
||||
"CommentDeletionConfirmationMessage": "This comment and all replies will be deleted!",
|
||||
"Comments": "Comments",
|
||||
"Content": "Content",
|
||||
"ContentDeletionConfirmationMessage": "Are you sure to delete this content?",
|
||||
"Contents": "Contents",
|
||||
"CoverImage": "Cover Image",
|
||||
"CreateBlogPostPage": "New Blog Post",
|
||||
"CreationTime": "Creation Time",
|
||||
"Delete": "Delete",
|
||||
"Detail": "Detail",
|
||||
"Details": "Details",
|
||||
"DisplayName": "Display Name",
|
||||
"DoYouPreferAdditionalEmails": "Do you prefer additional emails?",
|
||||
"Edit": "Edit",
|
||||
"EndDate": "End Date",
|
||||
"EntityId": "Entity Id",
|
||||
"EntityType": "Entity Type",
|
||||
"ExportCSV": "Export CSV",
|
||||
"Features": "Features",
|
||||
"GenericDeletionConfirmationMessage": "Are you sure to delete '{0}'?",
|
||||
"IsActive": "Active",
|
||||
"LastModification": "Last Modification",
|
||||
"LastModificationTime": "Last Modification Time",
|
||||
"LoginToAddComment": "Login to add comment",
|
||||
"LoginToRate": "Login to rate",
|
||||
"LoginToReact": "Login to react",
|
||||
"LoginToReply": "Login to reply",
|
||||
"MainMenu": "Main Menu",
|
||||
"MakeMainMenu": "Make Main Menu",
|
||||
"Menu:CMS": "CMS",
|
||||
"Menus": "Menus",
|
||||
"MenuDeletionConfirmationMessage": "The menu '{0}' will be deleted. Are you sure?",
|
||||
"MenuItemDeletionConfirmationMessage": "Are sure to delete this menu item?",
|
||||
"MenuItemMoveConfirmMessage": "Are you sure you want to move '{0}' under '{1}'?",
|
||||
"MenuItems": "Menu Items",
|
||||
"Message": "Message",
|
||||
"MessageDeletionConfirmationMessage": "This comment will be deleted completely.",
|
||||
"NewBlog": "New Blog",
|
||||
"NewBlogPost": "New Blog Post",
|
||||
"NewMenu": "New Menu",
|
||||
"NewMenuItem": "New Root Menu Item",
|
||||
"NewPage": "New Page",
|
||||
"NewTag": "New Tag",
|
||||
"NoMenuItems": "There is no menu item yet!",
|
||||
"OK": "OK",
|
||||
"PageDeletionConfirmationMessage": "Are you sure to delete this page?",
|
||||
"PageId": "Page",
|
||||
"Pages": "Pages",
|
||||
"PageSlugInformation": "Slug is used on url. Your url will be '/{{slug}}'.",
|
||||
"Permission:BlogManagement": "Blog Management",
|
||||
"Permission:BlogManagement.Create": "Create",
|
||||
"Permission:BlogManagement.Delete": "Delete",
|
||||
"Permission:BlogManagement.Features": "Features",
|
||||
"Permission:BlogManagement.Update": "Update",
|
||||
"Permission:BlogPostManagement": "Blog Post Management",
|
||||
"Permission:BlogPostManagement.Create": "Create",
|
||||
"Permission:BlogPostManagement.Delete": "Delete",
|
||||
"Permission:BlogPostManagement.Update": "Update",
|
||||
"Permission:BlogPostManagement.Publish": "Publish",
|
||||
"Permission:CmsKit": "CmsKit Admin",
|
||||
"Permission:Comments": "Comment Management",
|
||||
"Permission:Comments.Delete": "Delete",
|
||||
"Permission:Contents": "Content Management",
|
||||
"Permission:Contents.Create": "Create Content",
|
||||
"Permission:Contents.Delete": "Delete Content",
|
||||
"Permission:Contents.Update": "Update Content",
|
||||
"Permission:MediaDescriptorManagement": "Media Management",
|
||||
"Permission:MediaDescriptorManagement:Create": "Create",
|
||||
"Permission:MediaDescriptorManagement:Delete": "Delete",
|
||||
"Permission:MenuItemManagement": "Menu Item Management",
|
||||
"Permission:MenuItemManagement.Create": "Create",
|
||||
"Permission:MenuItemManagement.Delete": "Delete",
|
||||
"Permission:MenuItemManagement.Update": "Update",
|
||||
"Permission:MenuManagement": "Menu Management",
|
||||
"Permission:MenuManagement.Create": "Create",
|
||||
"Permission:MenuManagement.Delete": "Delete",
|
||||
"Permission:MenuManagement.Update": "Update",
|
||||
"Permission:Menus": "Menu Management",
|
||||
"Permission:Menus.Create": "Create",
|
||||
"Permission:Menus.Delete": "Delete",
|
||||
"Permission:Menus.Update": "Update",
|
||||
"Permission:PageManagement": "Page Management",
|
||||
"Permission:PageManagement:Create": "Create",
|
||||
"Permission:PageManagement:Delete": "Delete",
|
||||
"Permission:PageManagement:Update": "Update",
|
||||
"Permission:PageManagement:SetAsHomePage": "Set As Home Page",
|
||||
"Permission:TagManagement": "Tag Management",
|
||||
"Permission:TagManagement.Create": "Create",
|
||||
"Permission:TagManagement.Delete": "Delete",
|
||||
"Permission:TagManagement.Update": "Update",
|
||||
"Permission:GlobalResources": "Global Resources",
|
||||
"Permission:CmsKitPublic": "CmsKit Public",
|
||||
"Permission:Comments.DeleteAll": "Delete All",
|
||||
"PickYourReaction": "Pick your reaction",
|
||||
"Rating": "Rating",
|
||||
"RatingUndoMessage": "Your rating will be undo.",
|
||||
"Reactions": "Reactions",
|
||||
"Read": "Read",
|
||||
"RepliesToThisComment": "Replies to this comment",
|
||||
"Reply": "Reply",
|
||||
"ReplyTo": "Reply to",
|
||||
"SamplePageMessage": "A sample page for the Pro module",
|
||||
"SaveChanges": "Save Changes",
|
||||
"Script": "Script",
|
||||
"SelectAll": "Select All",
|
||||
"Send": "Send",
|
||||
"SendMessage": "Send Message",
|
||||
"SelectedAuthor": "Author",
|
||||
"ShortDescription": "Short description",
|
||||
"Slug": "Slug",
|
||||
"Source": "Source",
|
||||
"SourceUrl": "Source Url",
|
||||
"Star": "Star",
|
||||
"StartDate": "Start Date",
|
||||
"Style": "Style",
|
||||
"Subject": "Subject",
|
||||
"SubjectPlaceholder": "Please type a subject",
|
||||
"Submit": "Submit",
|
||||
"Subscribe": "Subscribe",
|
||||
"SuccessfullySaved": "Successfully saved!",
|
||||
"TagDeletionConfirmationMessage": "Are you sure to delete '{0}' tag?",
|
||||
"Tags": "Tags",
|
||||
"Text": "Text",
|
||||
"ThankYou": "Thank you",
|
||||
"Title": "Title",
|
||||
"Undo": "Undo",
|
||||
"Update": "Update",
|
||||
"UpdatePreferenceSuccessMessage": "Your preferences have been saved.",
|
||||
"UpdateYourEmailPreferences": "Update your email preferences",
|
||||
"UnMakeMainMenu": "Unmake Main Menu",
|
||||
"UploadFailedMessage": "Upload failed.",
|
||||
"UserId": "User Id",
|
||||
"Username": "Username",
|
||||
"YourComment": "Your comment",
|
||||
"YourEmailAddress": "Your e-mail address",
|
||||
"YourFullName": "Your full name",
|
||||
"YourMessage": "Your Message",
|
||||
"YourReply": "Your reply",
|
||||
"MarkdownSupported": "<a href=\"https://www.markdownguide.org/basic-syntax/\">Markdown</a> supported.",
|
||||
"GlobalResources": "Global Resources",
|
||||
"SavedSuccessfully": "Saved successfully",
|
||||
"CmsKit.BlogPost.Status.0": "Draft",
|
||||
"CmsKit.BlogPost.Status.1": "Published",
|
||||
"CmsKit.BlogPost.Status.2": "Waiting for review",
|
||||
"BlogPostPublishConfirmationMessage": "Are you sure to publish the blog post \"{0}\"?",
|
||||
"SuccessfullyPublished": "Successfully published!",
|
||||
"Draft": "Draft",
|
||||
"Publish": "Publish",
|
||||
"BlogPostDraftConfirmationMessage": "Are you sure to set the blog post \"{0}\" as draft?",
|
||||
"BlogPostSendToReviewConfirmationMessage": "Are you sure to send the blog post \"{0}\" to admin review for publishing?",
|
||||
"SaveAsDraft": "Save as draft",
|
||||
"SendToReview": "Send to review",
|
||||
"SendToReviewToPublish": "Send to review to publish",
|
||||
"BlogPostSendToReviewSuccessMessage": "The blog post \"{0}\" has been sent to admin review for publishing.",
|
||||
"HasBlogPostWaitingForReviewMessage": "You have a blog post waiting for review. Click to list.",
|
||||
"SelectAStatus": "Select a status",
|
||||
"Status": "Status",
|
||||
"CmsKit.BlogPost.ScrollIndex": "Quick navigation bar in blog posts",
|
||||
"Add": "Add",
|
||||
"AddWidget": "Add Widget",
|
||||
"PleaseConfigureWidgets": "Please configure widgets",
|
||||
"SelectAnAuthor": "Select an Author",
|
||||
"InThisDocument": "In This Document",
|
||||
"GoToTop": "Go To Top",
|
||||
"SetAsHomePage": "Change Home Page Status",
|
||||
"CompletedSettingAsHomePage": "Set as home page",
|
||||
"IsHomePage": "Is Home Page",
|
||||
"RemovedSettingAsHomePage": "Removed setting the home page",
|
||||
"Feature:CmsKitGroup": "Cms Kit",
|
||||
"Feature:BlogEnable": "Blogpost",
|
||||
"Feature:BlogEnableDescription": "CMS Kit's blogpost system that allows create blogs and posts dynamically in the application.",
|
||||
"Feature:CommentEnable": "Commenting",
|
||||
"Feature:CommentEnableDescription": "CMS Kit's comment system allows commenting on entities such as BlogPost.",
|
||||
"Feature:GlobalResourceEnable": "Global resourcing",
|
||||
"Feature:GlobalResourceEnableDescription": "CMS Kit's global resoruces feature that allows managing global styles & scripts.",
|
||||
"Feature:MenuEnable": "Menu",
|
||||
"Feature:MenuEnableDescription": "CMS Kit's dynamic menu system that allows adding/removing application menus dynamically.",
|
||||
"Feature:PageEnable": "Paging",
|
||||
"Feature:PageEnableDescription": "CMS Kit's page system that allows creating static pages with specific URL.",
|
||||
"Feature:RatingEnable": "Rating",
|
||||
"Feature:RatingEnableDescription": "CMS Kit's rating system that allows users to rate entities such as BlogPost.",
|
||||
"Feature:ReactionEnable": "Reaction",
|
||||
"Feature:ReactionEnableDescription": "CMS Kit's reaction system that allows users to send reactions to entities such as BlogPost, Comments, etc.",
|
||||
"Feature:TagEnable": "Taging",
|
||||
"Feature:TagEnableDescription": "CMS Kit's tag system that allows tagging entities such as BlogPost.",
|
||||
"DeleteBlogPostMessage": "The blog will be deleted. Are you sure?",
|
||||
"CaptchaCode": "Captcha code",
|
||||
"CommentTextRequired": "Comment is required",
|
||||
"CaptchaCodeErrorMessage": "The answer you entered for the CAPTCHA was not correct. Please try again",
|
||||
"CaptchaCodeMissingMessage": "The captcha code is missing!",
|
||||
"UnAllowedExternalUrlMessage": "You included an unallowed external URL. Please try again without the external URL.",
|
||||
"URL": "URL",
|
||||
"PopularTags": "Popular Tags",
|
||||
"RemoveCoverImageConfirmationMessage": "Are you sure you want to remove the cover image?",
|
||||
"RemoveCoverImage": "Remove cover image",
|
||||
"CssClass": "CSS Class",
|
||||
"TagsHelpText": "Tags should be comma-separated (e.g.: tag1, tag2, tag3)"
|
||||
}
|
||||
"texts": {
|
||||
"AddSubMenuItem": "Add Sub Menu Item",
|
||||
"AreYouSure": "Are You Sure?",
|
||||
"BlogDeletionConfirmationMessage": "The blog '{0}' will be deleted. Are you sure?",
|
||||
"BlogFeatureNotAvailable": "This feature is not available now. Enable with 'GlobalFeatureManager' to use it.",
|
||||
"BlogId": "Blog",
|
||||
"BlogPostDeletionConfirmationMessage": "The blog post '{0}' will be deleted. Are you sure?",
|
||||
"BlogPosts": "Blog Posts",
|
||||
"Blogs": "Blogs",
|
||||
"ChoosePreference": "Choose Preference...",
|
||||
"Cms": "CMS",
|
||||
"CmsKit.Comments": "Comments",
|
||||
"CmsKit.Ratings": "Ratings",
|
||||
"CmsKit.Reactions": "Reactions",
|
||||
"CmsKit.Tags": "Tags",
|
||||
"CmsKit:0002": "Content already exists!",
|
||||
"CmsKit:0003": "The entity {0} is not taggable.",
|
||||
"CmsKit:Blog:0001": "The given slug ({Slug}) already exists!",
|
||||
"CmsKit:BlogPost:0001": "The given slug already exists!",
|
||||
"CmsKit:Comments:0001": "The entity {EntityType} is not commentable.",
|
||||
"CmsKit:Media:0001": "'{Name}' is not a valid media name.",
|
||||
"CmsKit:Media:0002": "The entity can't have media.",
|
||||
"CmsKit:Page:0001": "The given url ({Slug}) already exists. Please try with different url.",
|
||||
"CmsKit:Rating:0001": "The entity {EntityType} can't be rated.",
|
||||
"CmsKit:Reaction:0001": "The entity {EntityType} can't have reactions.",
|
||||
"CmsKit:Tag:0002": "The entity is not taggable!",
|
||||
"CommentAuthorizationExceptionMessage": "Those comments are not allowed for public display.",
|
||||
"CommentDeletionConfirmationMessage": "This comment and all replies will be deleted!",
|
||||
"Comments": "Comments",
|
||||
"Content": "Content",
|
||||
"ContentDeletionConfirmationMessage": "Are you sure to delete this content?",
|
||||
"Contents": "Contents",
|
||||
"CoverImage": "Cover Image",
|
||||
"CreateBlogPostPage": "New Blog Post",
|
||||
"CreationTime": "Creation Time",
|
||||
"Delete": "Delete",
|
||||
"Detail": "Detail",
|
||||
"Details": "Details",
|
||||
"DisplayName": "Display Name",
|
||||
"DoYouPreferAdditionalEmails": "Do you prefer additional emails?",
|
||||
"Edit": "Edit",
|
||||
"EndDate": "End Date",
|
||||
"EntityId": "Entity Id",
|
||||
"EntityType": "Entity Type",
|
||||
"ExportCSV": "Export CSV",
|
||||
"Features": "Features",
|
||||
"GenericDeletionConfirmationMessage": "Are you sure to delete '{0}'?",
|
||||
"IsActive": "Active",
|
||||
"LastModification": "Last Modification",
|
||||
"LastModificationTime": "Last Modification Time",
|
||||
"LoginToAddComment": "Login to add comment",
|
||||
"LoginToRate": "Login to rate",
|
||||
"LoginToReact": "Login to react",
|
||||
"LoginToReply": "Login to reply",
|
||||
"MainMenu": "Main Menu",
|
||||
"MakeMainMenu": "Make Main Menu",
|
||||
"Menu:CMS": "CMS",
|
||||
"Menus": "Menus",
|
||||
"MenuDeletionConfirmationMessage": "The menu '{0}' will be deleted. Are you sure?",
|
||||
"MenuItemDeletionConfirmationMessage": "Are sure to delete this menu item?",
|
||||
"MenuItemMoveConfirmMessage": "Are you sure you want to move '{0}' under '{1}'?",
|
||||
"MenuItems": "Menu Items",
|
||||
"Message": "Message",
|
||||
"MessageDeletionConfirmationMessage": "This comment will be deleted completely.",
|
||||
"NewBlog": "New Blog",
|
||||
"NewBlogPost": "New Blog Post",
|
||||
"NewMenu": "New Menu",
|
||||
"NewMenuItem": "New Root Menu Item",
|
||||
"NewPage": "New Page",
|
||||
"NewTag": "New Tag",
|
||||
"NoMenuItems": "There is no menu item yet!",
|
||||
"OK": "OK",
|
||||
"PageDeletionConfirmationMessage": "Are you sure to delete this page?",
|
||||
"PageId": "Page",
|
||||
"Pages": "Pages",
|
||||
"PageSlugInformation": "Slug is used on url. Your url will be '/{{slug}}'.",
|
||||
"Permission:BlogManagement": "Blog Management",
|
||||
"Permission:BlogManagement.Create": "Create",
|
||||
"Permission:BlogManagement.Delete": "Delete",
|
||||
"Permission:BlogManagement.Features": "Features",
|
||||
"Permission:BlogManagement.Update": "Update",
|
||||
"Permission:BlogPostManagement": "Blog Post Management",
|
||||
"Permission:BlogPostManagement.Create": "Create",
|
||||
"Permission:BlogPostManagement.Delete": "Delete",
|
||||
"Permission:BlogPostManagement.Update": "Update",
|
||||
"Permission:BlogPostManagement.Publish": "Publish",
|
||||
"Permission:CmsKit": "CmsKit Admin",
|
||||
"Permission:Comments": "Comment Management",
|
||||
"Permission:Comments.Delete": "Delete",
|
||||
"Permission:Contents": "Content Management",
|
||||
"Permission:Contents.Create": "Create Content",
|
||||
"Permission:Contents.Delete": "Delete Content",
|
||||
"Permission:Contents.Update": "Update Content",
|
||||
"Permission:MediaDescriptorManagement": "Media Management",
|
||||
"Permission:MediaDescriptorManagement:Create": "Create",
|
||||
"Permission:MediaDescriptorManagement:Delete": "Delete",
|
||||
"Permission:MenuItemManagement": "Menu Item Management",
|
||||
"Permission:MenuItemManagement.Create": "Create",
|
||||
"Permission:MenuItemManagement.Delete": "Delete",
|
||||
"Permission:MenuItemManagement.Update": "Update",
|
||||
"Permission:MenuManagement": "Menu Management",
|
||||
"Permission:MenuManagement.Create": "Create",
|
||||
"Permission:MenuManagement.Delete": "Delete",
|
||||
"Permission:MenuManagement.Update": "Update",
|
||||
"Permission:Menus": "Menu Management",
|
||||
"Permission:Menus.Create": "Create",
|
||||
"Permission:Menus.Delete": "Delete",
|
||||
"Permission:Menus.Update": "Update",
|
||||
"Permission:PageManagement": "Page Management",
|
||||
"Permission:PageManagement:Create": "Create",
|
||||
"Permission:PageManagement:Delete": "Delete",
|
||||
"Permission:PageManagement:Update": "Update",
|
||||
"Permission:PageManagement:SetAsHomePage": "Set As Home Page",
|
||||
"Permission:TagManagement": "Tag Management",
|
||||
"Permission:TagManagement.Create": "Create",
|
||||
"Permission:TagManagement.Delete": "Delete",
|
||||
"Permission:TagManagement.Update": "Update",
|
||||
"Permission:GlobalResources": "Global Resources",
|
||||
"Permission:CmsKitPublic": "CmsKit Public",
|
||||
"Permission:Comments.DeleteAll": "Delete All",
|
||||
"PickYourReaction": "Pick your reaction",
|
||||
"Rating": "Rating",
|
||||
"RatingUndoMessage": "Your rating will be undo.",
|
||||
"Reactions": "Reactions",
|
||||
"Read": "Read",
|
||||
"RepliesToThisComment": "Replies to this comment",
|
||||
"Reply": "Reply",
|
||||
"ReplyTo": "Reply to",
|
||||
"SamplePageMessage": "A sample page for the Pro module",
|
||||
"SaveChanges": "Save Changes",
|
||||
"Script": "Script",
|
||||
"SelectAll": "Select All",
|
||||
"Send": "Send",
|
||||
"SendMessage": "Send Message",
|
||||
"SelectedAuthor": "Author",
|
||||
"ShortDescription": "Short description",
|
||||
"Slug": "Slug",
|
||||
"Source": "Source",
|
||||
"SourceUrl": "Source Url",
|
||||
"Star": "Star",
|
||||
"StartDate": "Start Date",
|
||||
"Style": "Style",
|
||||
"Subject": "Subject",
|
||||
"SubjectPlaceholder": "Please type a subject",
|
||||
"Submit": "Submit",
|
||||
"Subscribe": "Subscribe",
|
||||
"SuccessfullySaved": "Successfully saved!",
|
||||
"TagDeletionConfirmationMessage": "Are you sure to delete '{0}' tag?",
|
||||
"Tags": "Tags",
|
||||
"Text": "Text",
|
||||
"ThankYou": "Thank you",
|
||||
"Title": "Title",
|
||||
"Undo": "Undo",
|
||||
"Update": "Update",
|
||||
"UpdatePreferenceSuccessMessage": "Your preferences have been saved.",
|
||||
"UpdateYourEmailPreferences": "Update your email preferences",
|
||||
"UnMakeMainMenu": "Unmake Main Menu",
|
||||
"UploadFailedMessage": "Upload failed.",
|
||||
"UserId": "User Id",
|
||||
"Username": "Username",
|
||||
"YourComment": "Your comment",
|
||||
"YourEmailAddress": "Your e-mail address",
|
||||
"YourFullName": "Your full name",
|
||||
"YourMessage": "Your Message",
|
||||
"YourReply": "Your reply",
|
||||
"MarkdownSupported": "<a href=\"https://www.markdownguide.org/basic-syntax/\">Markdown</a> supported.",
|
||||
"GlobalResources": "Global Resources",
|
||||
"SavedSuccessfully": "Saved successfully",
|
||||
"CmsKit.BlogPost.Status.0": "Draft",
|
||||
"CmsKit.BlogPost.Status.1": "Published",
|
||||
"CmsKit.BlogPost.Status.2": "Waiting for review",
|
||||
"BlogPostPublishConfirmationMessage": "Are you sure to publish the blog post \"{0}\"?",
|
||||
"SuccessfullyPublished": "Successfully published!",
|
||||
"Draft": "Draft",
|
||||
"Publish": "Publish",
|
||||
"BlogPostDraftConfirmationMessage": "Are you sure to set the blog post \"{0}\" as draft?",
|
||||
"BlogPostSendToReviewConfirmationMessage": "Are you sure to send the blog post \"{0}\" to admin review for publishing?",
|
||||
"SaveAsDraft": "Save as draft",
|
||||
"SendToReview": "Send to review",
|
||||
"SendToReviewToPublish": "Send to review to publish",
|
||||
"BlogPostSendToReviewSuccessMessage": "The blog post \"{0}\" has been sent to admin review for publishing.",
|
||||
"HasBlogPostWaitingForReviewMessage": "You have a blog post waiting for review. Click to list.",
|
||||
"SelectAStatus": "Select a status",
|
||||
"Status": "Status",
|
||||
"CmsKit.BlogPost.ScrollIndex": "Quick navigation bar in blog posts",
|
||||
"CmsKit.BlogPost.PreventXssFeature": "Prevent XSS",
|
||||
"Add": "Add",
|
||||
"AddWidget": "Add Widget",
|
||||
"PleaseConfigureWidgets": "Please configure widgets",
|
||||
"SelectAnAuthor": "Select an Author",
|
||||
"InThisDocument": "In This Document",
|
||||
"GoToTop": "Go To Top",
|
||||
"SetAsHomePage": "Change Home Page Status",
|
||||
"CompletedSettingAsHomePage": "Set as home page",
|
||||
"IsHomePage": "Is Home Page",
|
||||
"RemovedSettingAsHomePage": "Removed setting the home page",
|
||||
"Feature:CmsKitGroup": "Cms Kit",
|
||||
"Feature:BlogEnable": "Blogpost",
|
||||
"Feature:BlogEnableDescription": "CMS Kit's blogpost system that allows create blogs and posts dynamically in the application.",
|
||||
"Feature:CommentEnable": "Commenting",
|
||||
"Feature:CommentEnableDescription": "CMS Kit's comment system allows commenting on entities such as BlogPost.",
|
||||
"Feature:GlobalResourceEnable": "Global resourcing",
|
||||
"Feature:GlobalResourceEnableDescription": "CMS Kit's global resoruces feature that allows managing global styles & scripts.",
|
||||
"Feature:MenuEnable": "Menu",
|
||||
"Feature:MenuEnableDescription": "CMS Kit's dynamic menu system that allows adding/removing application menus dynamically.",
|
||||
"Feature:PageEnable": "Paging",
|
||||
"Feature:PageEnableDescription": "CMS Kit's page system that allows creating static pages with specific URL.",
|
||||
"Feature:RatingEnable": "Rating",
|
||||
"Feature:RatingEnableDescription": "CMS Kit's rating system that allows users to rate entities such as BlogPost.",
|
||||
"Feature:ReactionEnable": "Reaction",
|
||||
"Feature:ReactionEnableDescription": "CMS Kit's reaction system that allows users to send reactions to entities such as BlogPost, Comments, etc.",
|
||||
"Feature:TagEnable": "Taging",
|
||||
"Feature:TagEnableDescription": "CMS Kit's tag system that allows tagging entities such as BlogPost.",
|
||||
"DeleteBlogPostMessage": "The blog will be deleted. Are you sure?",
|
||||
"CaptchaCode": "Captcha code",
|
||||
"CommentTextRequired": "Comment is required",
|
||||
"CaptchaCodeErrorMessage": "The answer you entered for the CAPTCHA was not correct. Please try again",
|
||||
"CaptchaCodeMissingMessage": "The captcha code is missing!",
|
||||
"UnAllowedExternalUrlMessage": "You included an unallowed external URL. Please try again without the external URL.",
|
||||
"URL": "URL",
|
||||
"PopularTags": "Popular Tags",
|
||||
"RemoveCoverImageConfirmationMessage": "Are you sure you want to remove the cover image?",
|
||||
"RemoveCoverImage": "Remove cover image",
|
||||
"CssClass": "CSS Class",
|
||||
"TagsHelpText": "Tags should be comma-separated (e.g.: tag1, tag2, tag3)"
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
||||
import { Tree, readProjectConfiguration } from '@nx/devkit';
|
||||
|
||||
import { changeThemeGenerator } from './generator';
|
||||
import { ChangeThemeGeneratorSchema } from './schema';
|
||||
|
||||
describe('change-theme generator', () => {
|
||||
let tree: Tree;
|
||||
const options: ChangeThemeGeneratorSchema = { name: 'test' };
|
||||
|
||||
beforeEach(() => {
|
||||
tree = createTreeWithEmptyWorkspace();
|
||||
});
|
||||
|
||||
it('should run successfully', async () => {
|
||||
await changeThemeGenerator(tree, options);
|
||||
const config = readProjectConfiguration(tree, 'test');
|
||||
expect(config).toBeDefined();
|
||||
});
|
||||
});
|
@ -0,0 +1,26 @@
|
||||
import { Tree } from '@nx/devkit';
|
||||
import { wrapAngularDevkitSchematic } from '@nx/devkit/ngcli-adapter';
|
||||
import { ChangeThemeGeneratorSchema } from './schema';
|
||||
import { ThemeOptionsEnum } from './theme-options.enum';
|
||||
|
||||
export async function changeThemeGenerator(host: Tree, schema: ChangeThemeGeneratorSchema) {
|
||||
const schematicPath = schema.localPath || '@abp/ng.schematics';
|
||||
|
||||
const runAngularLibrarySchematic = wrapAngularDevkitSchematic(
|
||||
schema.localPath ? `${host.root}${schematicPath}` : schematicPath,
|
||||
'change-theme',
|
||||
);
|
||||
|
||||
await runAngularLibrarySchematic(host, {
|
||||
...schema,
|
||||
});
|
||||
|
||||
return () => {
|
||||
const destTheme = Object.values(ThemeOptionsEnum).find(
|
||||
(theme, index) => index + 1 === schema.name,
|
||||
);
|
||||
console.log(`✅️ Switched to Theme ${destTheme}`);
|
||||
};
|
||||
}
|
||||
|
||||
export default changeThemeGenerator;
|
@ -0,0 +1,3 @@
|
||||
export * from './theme-options.enum';
|
||||
export * from './schema';
|
||||
export * from './generator';
|
@ -0,0 +1,5 @@
|
||||
export interface ChangeThemeGeneratorSchema {
|
||||
name: number;
|
||||
targetOption: string;
|
||||
localPath?: string;
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/schema",
|
||||
"$id": "SchematicsABPThemeChanger",
|
||||
"title": "ABP Theme Style Generator API Schema",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"description": "The name of theme will change.",
|
||||
"type": "number",
|
||||
"$default": {
|
||||
"$source": "argv",
|
||||
"index": 0
|
||||
},
|
||||
"enum": [1, 2, 3, 4],
|
||||
"x-prompt": {
|
||||
"message": "Which theme would you like to use?",
|
||||
"type": "list",
|
||||
"items": [
|
||||
{ "value": 1, "label": "Basic" },
|
||||
{ "value": 2, "label": "Lepton" },
|
||||
{ "value": 3, "label": "LeptonXLite" },
|
||||
{ "value": 4, "label": "LeptonX" }
|
||||
]
|
||||
}
|
||||
},
|
||||
"targetProject": {
|
||||
"description": "The name of the project will change the style.The project type must be 'application'",
|
||||
"type": "string",
|
||||
"x-prompt": "Please enter the project name",
|
||||
"$default": {
|
||||
"$source": "argv",
|
||||
"index": 1
|
||||
}
|
||||
},
|
||||
"localPath": {
|
||||
"description": "If set value schematics will work on given path",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["name", "targetProject"]
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
// this enum create by https://raw.githubusercontent.com/abpframework/abp/rel-7.4/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Theme.cs
|
||||
|
||||
export enum ThemeOptionsEnum {
|
||||
Basic = 1,
|
||||
Lepton = 2,
|
||||
LeptonXLite = 3,
|
||||
LeptonX = 4,
|
||||
}
|
@ -1 +1,3 @@
|
||||
export * from './generators/generate-proxy'
|
||||
export * from './generators/change-theme';
|
||||
export * from './generators/generate-proxy';
|
||||
export * from './generators/update-version';
|
||||
|
@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
mappings: {
|
||||
"@node_modules/zxcvbn/dist/zxcvbn.js": "@libs/zxcvbn/"
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
{
|
||||
"version": "7.4.0-rc.3",
|
||||
"name": "@abp/zxcvbn",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"dependencies": {
|
||||
"@abp/core": "~7.4.0-rc.3",
|
||||
"zxcvbn" : "^4.4.2"
|
||||
},
|
||||
"gitHead": "bb4ea17d5996f01889134c138d00b6c8f858a431",
|
||||
"homepage": "https://abp.io",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/abpframework/abp.git"
|
||||
},
|
||||
"license": "LGPL-3.0",
|
||||
"keywords": [
|
||||
"aspnetcore",
|
||||
"boilerplate",
|
||||
"framework",
|
||||
"web",
|
||||
"best-practices",
|
||||
"angular",
|
||||
"maui",
|
||||
"blazor",
|
||||
"mvc",
|
||||
"csharp",
|
||||
"webapp"
|
||||
]
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue