diff --git a/docs/en/Authorization.md b/docs/en/Authorization.md
index de89920946..1bceda951f 100644
--- a/docs/en/Authorization.md
+++ b/docs/en/Authorization.md
@@ -204,6 +204,10 @@ If you define and register a policy to the ASP.NET Core authorization system wit
See [policy based authorization](https://docs.microsoft.com/en-us/aspnet/core/security/authorization/policies) document to learn how to define a custom policy.
+### Changing Permission Definitions of a Depended Module
+
+A class deriving from the `PermissionDefinitionProvider` (just like the example above) can also get existing permission definitions (defined by the depended [modules](Module-Development-Basics.md)) and change their definitions.
+
## IAuthorizationService
ASP.NET Core provides the `IAuthorizationService` that can be used to check for authorization. Once you inject, you can use it in your code to conditionally control the authorization.
diff --git a/docs/en/Customizing-Application-Modules-Guide.md b/docs/en/Customizing-Application-Modules-Guide.md
index 9989c6fc09..7f913f366a 100644
--- a/docs/en/Customizing-Application-Modules-Guide.md
+++ b/docs/en/Customizing-Application-Modules-Guide.md
@@ -53,3 +53,10 @@ This section suggests some approaches if you decided to use pre-built applicatio
* [Overriding Services](Customizing-Application-Modules-Overriding-Services.md)
* [Overriding the User Interface](Customizing-Application-Modules-Overriding-User-Interface.md)
+### See Also
+
+Also, see the following documents:
+
+* See [the localization document](Localization.md) to learn how to extend existing localization resources.
+* See [the settings document](Settings.md) to learn how to change setting definitions of a depended module.
+* See [the authorization document](Authorization.md) to learn how to change permission definitions of a depended module.
\ No newline at end of file
diff --git a/docs/en/Modules/Account.md b/docs/en/Modules/Account.md
new file mode 100644
index 0000000000..6901b38f59
--- /dev/null
+++ b/docs/en/Modules/Account.md
@@ -0,0 +1,3 @@
+# Account Module
+
+TODO
\ No newline at end of file
diff --git a/docs/en/Themes/Basic.md b/docs/en/Themes/Basic.md
new file mode 100644
index 0000000000..a0165c803a
--- /dev/null
+++ b/docs/en/Themes/Basic.md
@@ -0,0 +1,3 @@
+## Basic Theme
+
+TODO
\ No newline at end of file
diff --git a/docs/en/Tutorials/Part-1.md b/docs/en/Tutorials/Part-1.md
index 05fd29fd41..20b64f3189 100644
--- a/docs/en/Tutorials/Part-1.md
+++ b/docs/en/Tutorials/Part-1.md
@@ -727,7 +727,7 @@ $(function () {
* `abp.libs.datatables.createAjax` is a helper function to adapt ABP's dynamic JavaScript API proxies to [Datatable](https://datatables.net/)'s format.
* `abp.libs.datatables.normalizeConfiguration` is another helper function. There's no requirement to use it, but it simplifies the [Datatables](https://datatables.net/) configuration by providing conventional values for missing options.
-* `acme.bookStore.book.getList` is the function to get list of books (as described in [dynamic JavaScript proxies](#Dynamic JavaScript proxies)).
+* `acme.bookStore.book.getList` is the function to get list of books (as described in [dynamic JavaScript proxies](#dynamic-javascript-proxies)).
* See [Datatables documentation](https://datatables.net/manual/) for all configuration options.
It's end of this part. The final UI of this work is shown as below:
diff --git a/docs/en/Tutorials/Part-2.md b/docs/en/Tutorials/Part-2.md
index 8408cf6bfb..08e17e0e3f 100644
--- a/docs/en/Tutorials/Part-2.md
+++ b/docs/en/Tutorials/Part-2.md
@@ -641,7 +641,6 @@ Open `book-list.component.html` file in `books\book-list` folder and replace the
= {
+ name: "Home",
+ path: "home",
+ children: [
+ {
+ name: "Dashboard",
+ path: "dashboard"
+ }
+ ]
+};
+
+this.config.dispatchPatchRouteByName("::Menu:Home", newRouteConfig);
+// returns a state stream which emits after dispatch action is complete
+```
+
+### How to Add a New Route Configuration
+
+The `dispatchAddRoute` adds a new route to the configuration state in the `Store`. For this, the route config should be passed as the parameter of the method.
+
+```js
+// this.config is instance of ConfigStateService
+
+const newRoute: ABP.Route = {
+ name: "My New Page",
+ iconClass: "fa fa-dashboard",
+ path: "page",
+ invisible: false,
+ order: 2,
+ requiredPolicy: "MyProjectName::MyNewPage"
+};
+
+this.config.dispatchAddRoute(newRoute);
+// returns a state stream which emits after dispatch action is complete
+```
+
+The `newRoute` will be placed as at root level, i.e. without any parent routes and its url will be stored as `'/path'`.
+
+If you want **to add a child route, you can do this:**
+
+```js
+// this.config is instance of ConfigStateService
+
+const newRoute: ABP.Route = {
+ parentName: "AbpAccount::Login",
+ name: "My New Page",
+ iconClass: "fa fa-dashboard",
+ path: "page",
+ invisible: false,
+ order: 2,
+ requiredPolicy: "MyProjectName::MyNewPage"
+};
+
+this.config.dispatchAddRoute(newRoute);
+// returns a state stream which emits after dispatch action is complete
+```
+
+The `newRoute` will then be placed as a child of the parent route named `'AbpAccount::Login'` and its url will be set as `'/account/login/page'`.
+
+#### Route Configuration Properties
+
+Please refer to `ABP.Route` type for all the properties you can pass to `dispatchSetEnvironment` in its parameter. It can be found in the [common.ts file](https://github.com/abpframework/abp/blob/dev/npm/ng-packs/packages/core/src/lib/models/common.ts#L27).
+
+### How to Set the Environment
+
+The `dispatchSetEnvironment` places environment variables passed to it in the `Store` under the configuration state. Here is how it is used:
+
+```js
+// this.config is instance of ConfigStateService
+
+this.config.dispatchSetEnvironment({
+ /* environment properties here */
+});
+// returns a state stream which emits after dispatch action is complete
+```
+
+Note that **you do not have to call this method at application initiation**, because the environment variables are already being stored at start.
+
+#### Environment Properties
+
+Please refer to `Config.Environment` type for all the properties you can pass to `dispatchSetEnvironment` as parameter. It can be found in the [config.ts file](https://github.com/abpframework/abp/blob/dev/npm/ng-packs/packages/core/src/lib/models/config.ts#L13).
diff --git a/docs/en/UI/Angular/AddingSettingTab.md b/docs/en/UI/Angular/Custom-Setting-Page.md
similarity index 66%
rename from docs/en/UI/Angular/AddingSettingTab.md
rename to docs/en/UI/Angular/Custom-Setting-Page.md
index 2eb4e9bb61..7c51cf2cca 100644
--- a/docs/en/UI/Angular/AddingSettingTab.md
+++ b/docs/en/UI/Angular/Custom-Setting-Page.md
@@ -1,6 +1,6 @@
-## Creating a Settings Tab
+# Custom Setting Page
-There are several settings tabs from different modules. You can add custom settings tabs to your project in 3 steps.
+There are several settings tabs from different modules. You can add custom settings page to your project in 3 steps.
1. Create a Component
@@ -11,12 +11,11 @@ import { Component } from '@angular/core';
@Component({
selector: 'app-your-custom-settings',
template: `
- your-custom-settings works! mySetting: {%{{{ mySetting$ | async }}}%}
+ custom-settings works!
`,
})
export class YourCustomSettingsComponent {
- @Select(ConfigState.getSetting('MyProjectName.MySetting1')) // Gets a setting. MyProjectName.MySetting1 is a setting key.
- mySetting$: Observable; // The selected setting is set to the mySetting variable as Observable.
+ // Your component logic
}
```
@@ -38,6 +37,6 @@ ngOnInit() {
}
```
-Open the `setting-management` page to see the changes:
+Navigate to `/setting-management` route to see the changes:

diff --git a/docs/en/UI/Angular/images/custom-settings.png b/docs/en/UI/Angular/images/custom-settings.png
index 32d7516849..05dd3f695a 100644
Binary files a/docs/en/UI/Angular/images/custom-settings.png and b/docs/en/UI/Angular/images/custom-settings.png differ
diff --git a/docs/en/UI/AspNetCore/Bundling-Minification.md b/docs/en/UI/AspNetCore/Bundling-Minification.md
index 8868d441e1..fc4ddaced3 100644
--- a/docs/en/UI/AspNetCore/Bundling-Minification.md
+++ b/docs/en/UI/AspNetCore/Bundling-Minification.md
@@ -143,7 +143,7 @@ This time, no file defined in the tag helper definition because the bundle files
### Configuring An Existing Bundle
-ABP supports [modularity](../Module-Development-Basics.md) for bundling as well. A module can modify an existing bundle that is created by a dependant module. Example:
+ABP supports [modularity](../Module-Development-Basics.md) for bundling as well. A module can modify an existing bundle that is created by a depended module. Example:
````C#
[DependsOn(typeof(MyWebModule))]
diff --git a/docs/en/UI/AspNetCore/Customization-User-Interface.md b/docs/en/UI/AspNetCore/Customization-User-Interface.md
index ce50141ac0..ef4d1e97f7 100644
--- a/docs/en/UI/AspNetCore/Customization-User-Interface.md
+++ b/docs/en/UI/AspNetCore/Customization-User-Interface.md
@@ -2,7 +2,17 @@
This document explains how to override the user interface of a depended [application module](../../Modules/Index.md) for ASP.NET Core MVC / Razor Page applications.
-## Overriding a Page Model
+## Overriding a Page
+
+This section covers the [Razor Pages](https://docs.microsoft.com/en-us/aspnet/core/razor-pages/) development, which is the recommended approach to create server rendered user interface for ASP.NET Core. Pre-built modules typically uses the Razor Pages approach instead of the classic MVC pattern (next sections will cover the MVC pattern too).
+
+You typically have three kind of override requirement for a page:
+
+* Overriding **only the Page Model** (C#) side to perform additional logic without changing the page UI.
+* Overring **only the Razor Page** (.chtml file) to change the UI without changing the c# behind the page.
+* **Completely overriding** the page.
+
+### Overriding a Page Model (C#)
````csharp
using System.Threading.Tasks;
@@ -36,5 +46,425 @@ namespace Acme.BookStore.Web.Pages.Identity.Users
}
````
-This class replaces `EditModalModel` for the users and overrides the `OnPostAsync` method.
+* This class inherits from and replaces the `EditModalModel` for the users and overrides the `OnPostAsync` method to perform additional logic before and after the underlying code.
+* It uses `ExposeServices` and `Dependency` attributes to replace the class.
+
+### Overriding a Razor Page (.CSHTML)
+
+Overriding a `.cshtml` file (razor page, razor view, view component... etc.) is possible through the [Virtual File System](../../Virtual-File-System.md).
+
+Virtual File system allows us to **embed resources into assemblies**. In this way, pre-built modules define the razor pages inside their NuGet packages. When you depend a module, you can override any file added to the virtual file system by that module, including pages/views.
+
+#### Example
+
+This example overrides the **login page** UI defined by the [Account Module](../../Modules/Account.md).
+
+Physical files override the embedded files defined in the same location. The account module defines a `Login.cshtml` file under the `Pages/Account` folder. So, you can override it by creating a file in the same path:
+
+
+
+You typically want to copy the original `.cshtml` file of the module, then make the necessary changes. You can find the original file [here](https://github.com/abpframework/abp/blob/dev/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml). Do not copy the `Login.cshtml.cs` file which is the code behind file for the razor page and we don't want to override it yet (see the next section).
+
+That's all, you can change the file content however you like.
+
+### Completely Overriding a Razor Page
+
+You may want to completely override a page; the razor and the c# file related to the page.
+
+In such a case;
+
+1. Override the C# page model class just like described above, but don't replace the existing page model class.
+2. Override the Razor Page just described above, but also change the @model directive to point your new page model.
+
+#### Example
+
+This example overrides the **login page** defined by the [Account Module](../../Modules/Account.md).
+
+Create a page model class deriving from the ` LoginModel ` (defined in the ` Volo.Abp.Account.Web.Pages.Account ` namespace):
+
+````csharp
+public class MyLoginModel : LoginModel
+{
+ public MyLoginModel(
+ IAuthenticationSchemeProvider schemeProvider,
+ IOptions accountOptions
+ ) : base(
+ schemeProvider,
+ accountOptions)
+ {
+
+ }
+
+ public override Task OnPostAsync(string action)
+ {
+ //TODO: Add logic
+ return base.OnPostAsync(action);
+ }
+
+ //TODO: Add new methods and properties...
+}
+````
+
+You can override any method or add new properties/methods if needed.
+
+> Notice that we didn't use `[Dependency(ReplaceServices = true)]` or `[ExposeServices(typeof(LoginModel))]` since we don't want to replace the existing class in the dependency injection, we define a new one.
+
+Copy `Login.cshtml` file into your solution as just described above. Change the **@model** directive to point to the `MyLoginModel`:
+
+````xml
+@page
+...
+@model Acme.BookStore.Web.Pages.Account.MyLoginModel
+...
+````
+
+That's all! Make any change in the view and run your application.
+
+#### Replacing Page Model Without Inheritance
+
+You don't have to inherit from the original page model class (like done in the previous example). Instead, you can completely **re-implement** the page yourself. In this case, just derive from `PageModel`, `AbpPageModel` or any suitable base class you need.
+
+## Overriding a View Component
+
+The ABP Framework, pre-built themes and modules define some **re-usable view components**. These view components can be replaced just like a page described above.
+
+### Example
+
+The screenshot below was taken from the **basic theme** comes with the application startup template.
+
+
+
+[The basic theme](../../Themes/Basic.md) defines some view components for the layout. For example, the highlighted area with the red rectangle above is called **Brand component**. You probably want to customize this component by adding your **own application logo**. Let's see how to do it.
+
+First, create your logo and place under a folder in your web application. We used `wwwroot/logos/bookstore-logo.png` path. Then copy the Brand component's view ([from here](https://github.com/abpframework/abp/blob/dev/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Brand/Default.cshtml)) from the basic theme files under the `Themes/Basic/Components/Brand` folder. The result should be similar the picture below:
+
+
+
+Then change the `Default.cshtml` as you like. Example content can be like that:
+
+````xml
+
+
+
+````
+
+Now, you can run the application to see the result:
+
+
+
+If you need, you can also replace [the code behind c# class](https://github.com/abpframework/abp/blob/dev/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Brand/MainNavbarBrandViewComponent.cs) of the component just using the dependency injection system.
+
+### Overriding the Theme
+
+Just as explained above, you can replace any component, layout or c# class of the used theme. See the [theming document](Theming.md) for more information on the theming system.
+
+## Overriding Static Resources
+
+Overriding a static embedded resource (like JavaScript, Css or image files) of a module is pretty easy. Just place a file in the same path in your solution and let the Virtual File System to handle it.
+
+## Manipulating the Bundles
+
+The [Bundling & Minification](Bundling-Minification.md) system provides an **extensible and dynamic** system to create **script** and **style** bundles. It allows you to extend and manipulate the existing bundles.
+
+### Example: Add a Global CSS File
+
+For example, ABP Framework defines a **global style bundle** which is added to every page (actually, added to the layout by the themes). Let's add a **custom style file** to the end of the bundle files, so we can override any global style.
+
+First, create a CSS file and locate it in a folder inside the `wwwroot`:
+
+
+
+Define some custom CSS rules inside the file. Example:
+
+````css
+.card-title {
+ color: orange;
+ font-size: 2em;
+ text-decoration: underline;
+}
+
+.btn-primary {
+ background-color: red;
+}
+````
+
+Then add this file to the standard global style bundle in the `ConfigureServices` method of your [module](../../Module-Development-Basics.md):
+
+````csharp
+Configure(options =>
+{
+ options.StyleBundles.Configure(
+ StandardBundles.Styles.Global, //The bundle name!
+ bundleConfiguration =>
+ {
+ bundleConfiguration.AddFiles("/styles/my-global-styles.css");
+ }
+ );
+});
+````
+
+#### The Global Script Bundle
+
+Just like the `StandardBundles.Styles.Global`, there is a `StandardBundles.Scripts.Global` that you can add files or manipulate the existing ones.
+
+### Example: Manipulate the Bundle Files
+
+The example above adds a new file to the bundle. You can do more if you create a **bundle contributor** class. Example:
+
+````csharp
+public class MyGlobalStyleBundleContributor : BundleContributor
+{
+ public override void ConfigureBundle(BundleConfigurationContext context)
+ {
+ context.Files.Clear();
+ context.Files.Add("/styles/my-global-styles.css");
+ }
+}
+````
+
+Then you can add the contributor to an existing bundle:
+
+````csharp
+Configure(options =>
+{
+ options.StyleBundles.Configure(
+ StandardBundles.Styles.Global,
+ bundleConfiguration =>
+ {
+ bundleConfiguration.AddContributors(typeof(MyGlobalStyleBundleContributor));
+ }
+ );
+});
+````
+
+It is not a good idea to clear all CSS files. In a real world scenario, you can find and replace a specific file with your own file.
+
+### Example: Add a JavaScript File for a Specific Page
+
+The examples above works with the global bundle added to the layout. What if you want to add a CSS/JavaScript file (or replace a file) for a specific page defines inside a depended module?
+
+Assume that you want to run a **JavaScript code** once the user enters to the **Role Management** page of the Identity Module.
+
+First, create a standard JavaScript file under the `wwwroot`, `Pages` or `Views` folder (ABP support to add static resources inside these folders by default). We prefer the `Pages/Identity/Roles` folder to follow the conventions:
+
+
+
+Content of the file is simple:
+
+````js
+$(function() {
+ abp.log.info('My custom role script file has been loaded!');
+});
+````
+
+Then add this file to the bundle of the role management page:
+
+````csharp
+Configure(options =>
+{
+ options.ScriptBundles
+ .Configure(
+ typeof(Volo.Abp.Identity.Web.Pages.Identity.Roles.IndexModel).FullName,
+ bundleConfig =>
+ {
+ bundleConfig.AddFiles("/Pages/Identity/Roles/my-role-script.js");
+ });
+});
+````
+
+`typeof(Volo.Abp.Identity.Web.Pages.Identity.Roles.IndexModel).FullName` is the safe way to get the bundle name for the role management page.
+
+> Notice that not every page defines such page bundles. They define only if needed.
+
+In addition to adding new CSS/JavaScript file to a page, you also can replace the existing one (by defining a bundle contributor).
+
+## Layout Customization
+
+Layouts are defined by the theme ([see the theming](Theming.md)) by design. They are not included in a downloaded application solution. In this way you can easily **upgrade** the theme and get new features. You can not **directly change** the layout code in your application unless you replace it by your own layout (will be explained in the next sections).
+
+There are some common ways to **customize the layout** described in the next sections.
+
+### Menu Contributors
+
+There are two **standard menus** defined by the ABP Framework:
+
+
+
+* `StandardMenus.Main`: The main menu of the application.
+* `StandardMenus.User`: The user menu (generally at the top right of the screen).
+
+Rendering the menus is a responsibility of the theme, but **menu items** are determined by the modules and your application code. Just implement the `IMenuContributor` interface and **manipulate the menu items** in the `ConfigureMenuAsync` method.
+
+Menu contributors are executed whenever need to render the menu. There is already a menu contributor defined in the **application startup template**, so you can take it as an example and improve if necessary. See the [navigation menu](Navigation-Menu.md) document for more.
+
+### Toolbar Contributors
+
+[Toolbar system](Toolbars.md) is used to define **toolbars** on the user interface. Modules (or your application) can add **items** to a toolbar, then the theme renders the toolbar on the **layout**.
+
+There is only one **standard toolbar** (named "Main" - defined as a constant: `StandardToolbars.Main`). For the basic theme, it is rendered as shown below:
+
+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 **view component**. So, first, create a new view component in your project:
+
+
+
+**NotificationViewComponent.cs**
+
+````csharp
+public class NotificationViewComponent : AbpViewComponent
+{
+ public async Task InvokeAsync()
+ {
+ return View("/Pages/Shared/Components/Notification/Default.cshtml");
+ }
+}
+````
+
+**Default.cshtml**
+
+````xml
+
+
+
+````
+
+Now, we can create a class implementing the `IToolbarContributor` interface:
+
+````csharp
+public class MyToolbarContributor : IToolbarContributor
+{
+ public Task ConfigureToolbarAsync(IToolbarConfigurationContext context)
+ {
+ if (context.Toolbar.Name == StandardToolbars.Main)
+ {
+ context.Toolbar.Items
+ .Insert(0, new ToolbarItem(typeof(NotificationViewComponent)));
+ }
+
+ 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:
+
+````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:
+
+
+
+`NotificationViewComponent` in this sample simply returns a view without any data. In real life, you probably want to **query database** (or call an HTTP API) to get notifications and pass to the view. If you need, you can add a `JavaScript` or `CSS` file to the global bundle (as described before) for your toolbar item.
+
+See the [toolbars document](Toolbars.md) for more about the toolbar system.
+
+### Layout Hooks
+
+[Layout Hooks](Layout-Hooks.md) system allows you to **add code** at some specific parts of the layout. All layouts of all themes should implement these hooks. Then you can then add a **view component** into a hook point.
+
+#### Example: Add Google Analytics Script
+
+Assume that you need to add the Google Analytics script to the layout (that will be available for all the pages). First, **create a view component** in your project:
+
+
+
+**NotificationViewComponent.cs**
+
+````csharp
+public class GoogleAnalyticsViewComponent : AbpViewComponent
+{
+ public IViewComponentResult Invoke()
+ {
+ return View("/Pages/Shared/Components/GoogleAnalytics/Default.cshtml");
+ }
+}
+````
+
+**Default.cshtml**
+
+````html
+
+````
+
+Change `UA-xxxxxx-1` with your own code.
+
+You can then add this component to any of the hook points in the `ConfigureServices` of your module:
+
+````csharp
+Configure(options =>
+{
+ options.Add(
+ LayoutHooks.Head.Last, //The hook name
+ typeof(GoogleAnalyticsViewComponent) //The component to add
+ );
+});
+````
+
+Now, the GA code will be inserted in the `head` of the page as the last item. You (or the modules you are using) can add multiple items to the same hook. All of them will be added to the layout.
+
+The configuration above adds the `GoogleAnalyticsViewComponent` to all layouts. You may want to only add to a specific layout:
+
+````csharp
+Configure(options =>
+{
+ options.Add(
+ LayoutHooks.Head.Last,
+ typeof(GoogleAnalyticsViewComponent),
+ layout: StandardLayouts.Application //Set the layout to add
+ );
+});
+````
+
+See the layouts section below to learn more about the layout system.
+
+### Layouts
+
+Layout system allows themes to define standard, named layouts and allows any page to select a proper layout for its purpose. There are three pre-defined layouts:
+
+* "**Application**": The main (and the default) layout for an application. It typically contains header, menu (sidebar), footer, toolbar... etc.
+* "**Account**": This layout is used by login, register and other similar pages. It is used for the pages under the `/Pages/Account` folder by default.
+* "**Empty**": Empty and minimal layout.
+
+These names are defined in the `StandardLayouts` class as constants. You can definitely create your own layouts, but these are standard layout names and implemented by all the themes out of the box.
+
+#### Layout Location
+
+You can find the layout files [here](https://github.com/abpframework/abp/tree/dev/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts) for the basic theme. You can take them as references to build your own layouts or you can override them if necessary.
+
+#### ITheme
+
+ABP Framework uses the `ITheme` service to get the layout location by the layout name. You can replace this service to dynamically select the layout location.
+
+#### IThemeManager
+
+`IThemeManager` is used to obtain the current theme and get the layout path. Any page can determine the layout of its own. Example:
+
+````html
+@using Volo.Abp.AspNetCore.Mvc.UI.Theming
+@inject IThemeManager ThemeManager
+@{
+ Layout = ThemeManager.CurrentTheme.GetLayout(StandardLayouts.Empty);
+}
+````
+
+This page will use the empty layout. You use `ThemeManager.CurrentTheme.GetEmptyLayout();` extension method as a shortcut.
+If you want to set the layout for all the pages under a specific folder, then write the code above in a `_ViewStart.cshtml` file under that folder.
\ No newline at end of file
diff --git a/docs/en/UI/AspNetCore/Layout-Hooks.md b/docs/en/UI/AspNetCore/Layout-Hooks.md
new file mode 100644
index 0000000000..49b334c6c0
--- /dev/null
+++ b/docs/en/UI/AspNetCore/Layout-Hooks.md
@@ -0,0 +1,3 @@
+# Layout Hooks
+
+TODO
\ No newline at end of file
diff --git a/docs/en/UI/AspNetCore/Navigation-Menu.md b/docs/en/UI/AspNetCore/Navigation-Menu.md
new file mode 100644
index 0000000000..4e0164ec72
--- /dev/null
+++ b/docs/en/UI/AspNetCore/Navigation-Menu.md
@@ -0,0 +1,3 @@
+# Navigation Menu
+
+TODO
\ No newline at end of file
diff --git a/docs/en/UI/AspNetCore/Tag-Helpers/Buttons.md b/docs/en/UI/AspNetCore/Tag-Helpers/Buttons.md
index ba1bfb4032..ae62c7f2b7 100644
--- a/docs/en/UI/AspNetCore/Tag-Helpers/Buttons.md
+++ b/docs/en/UI/AspNetCore/Tag-Helpers/Buttons.md
@@ -1,30 +1,26 @@
# Buttons
-ABP framework has a special Tag Helper to create bootstrap button easily.
+## Introduction
-``
+`abp-button` is the main element to create buttons.
-## Attributes
+Basic usage:
-`` has 7 different attribute.
+````xml
+Click Me
+````
-* [`button-type`](#button-type)
-* [`size`](#size)
-* [`busy-text`](#busy-text)
-* [`text`](#text)
-* [`icon`](#icon)
-* [`disabled`](#disabled)
-* [`icon-type`](#icon-type)
+## Demo
-### `button-type`
+See the [buttons demo page](https://bootstrap-taghelpers.abp.io/Components/Buttons) to see it in action.
-`button-type` is a selectable parameter. It's default value is `Default`.
+## Attributes
-`Button`
+### button-type
-You can choose one of the button type listed below.
+A value indicates the main style/type of the button. Should be one of the following values:
-* `Default`
+* `Default` (default value)
* `Primary`
* `Secondary`
* `Success`
@@ -43,15 +39,11 @@ You can choose one of the button type listed below.
* `Outline_Dark`
* `Link`
-### `size`
-
-`size` is a selectable parameter. It's default value is `Default`.
+### size
-`Button`
+A value indicates the size of the button. Should be one of the following values:
-You can choose one of the size type listed below.
-
-* `Default`
+* `Default` (default value)
* `Small`
* `Medium`
* `Large`
@@ -60,35 +52,35 @@ You can choose one of the size type listed below.
* `Block_Medium`
* `Block_Large`
-### `busy-text`
-
-`busy-text` is a string parameter. It shows the text while the button is busy.
-
-### `text`
+### busy-text
-`text` is a string parameter that displaying on button.
+A text that is shown when the button is busy.
-### `icon`
+### text
-`icon` is a string parameter. It is depending to [`icon-type`](#`icon-type`). For default, we use [Font Awesome](https://fontawesome.com/) for icons. To use it, you need to set `icon` parameter as a icon name.
+The text of the button. This is a shortcut if you simply want to set a text to the button. Example:
-##### Example
+````xml
+
+````
-[fa-address-card](https://fontawesome.com/icons/address-card): 
+In this case, you can use a self-closing tag to make it shorter.
-``
+### icon
-> Don't forget: You dont need to write prefix! It will add automatically "fa" prefix for [Font Awesome](https://fontawesome.com/) icons while you did not change `icon-type`.
+Used to set an icon for the button. It works with the [Font Awesome](https://fontawesome.com/) icon classes by default. Example:
-### `disabled`
+````xml
+
+````
-`disabled` is a boolean parameter. If you set it `true`, your button will be disabled.
+##### icon-type
-### `icon-type`
+If you don't want to use font-awesome, you have two options:
-`icon-type` is a selectable parameter. It's default value is `FontAwesome`. You can create your own icon type provider and change it.
+1. Set `icon-type` to `Other` and write the CSS class of the font icon you're using.
+2. If you don't use a font icon use the opening and closing tags manually and write any code inside the tags.
-You can choose one of the icon type listed below.
+### disabled
-* `FontAwesome`
-* `Other`
+Set `true` to make the button initially disabled.
\ No newline at end of file
diff --git a/docs/en/UI/AspNetCore/Tag-Helpers/Index.md b/docs/en/UI/AspNetCore/Tag-Helpers/Index.md
index bdeb7668b7..d7e393933e 100644
--- a/docs/en/UI/AspNetCore/Tag-Helpers/Index.md
+++ b/docs/en/UI/AspNetCore/Tag-Helpers/Index.md
@@ -1,3 +1,26 @@
-## ABP Tag Helpers
+# ABP Tag Helpers
-"ABP tag helpers" documentation is creating now. You can see a [demo of components](http://bootstrap-taghelpers.abp.io/) for now.
\ No newline at end of file
+ABP Framework defines a set of **tag helper components** to simply the user interface development for ASP.NET Core (MVC / Razor Pages) applications.
+
+## Bootstrap Component Wrappers
+
+Most of the tag helpers are [Bootstrap](https://getbootstrap.com/) (v4+) wrappers. Coding bootstrap is not so easy, not so type-safe and contains too much repetitive HTML tags. ABP Tag Helpers makes it **easier** and **type safe**.
+
+We don't aim to wrap bootstrap components 100%. Writing **native bootstrap style code** is still possible (actually, tag helpers generates native bootstrap code in the end), but we suggest to use the tag helpers wherever possible.
+
+ABP Framework also adds some **useful features** to the standard bootstrap components.
+
+Here, the list of components those are wrapped by the ABP Framework:
+
+* [Buttons](Buttons.md)
+* ...
+
+> Until all the tag helpers are documented, you can visit https://bootstrap-taghelpers.abp.io/ to see them with live samples.
+
+## Form Elements
+
+See [demo](https://bootstrap-taghelpers.abp.io/Components/FormElements).
+
+## Dynamic Inputs
+
+See [demo](https://bootstrap-taghelpers.abp.io/Components/DynamicForms).
\ No newline at end of file
diff --git a/docs/en/UI/AspNetCore/Tag-Helpers/fa-address-card.png b/docs/en/UI/AspNetCore/Tag-Helpers/fa-address-card.png
deleted file mode 100644
index a3b2c815b8..0000000000
Binary files a/docs/en/UI/AspNetCore/Tag-Helpers/fa-address-card.png and /dev/null differ
diff --git a/docs/en/UI/AspNetCore/Theming.md b/docs/en/UI/AspNetCore/Theming.md
index 470ef1a458..e41545635c 100644
--- a/docs/en/UI/AspNetCore/Theming.md
+++ b/docs/en/UI/AspNetCore/Theming.md
@@ -1,3 +1,3 @@
-# Theming
+# ASP.NET Core MVC / Razor Pages Theming
TODO
\ No newline at end of file
diff --git a/docs/en/UI/AspNetCore/Toolbars.md b/docs/en/UI/AspNetCore/Toolbars.md
new file mode 100644
index 0000000000..cc3bcd95be
--- /dev/null
+++ b/docs/en/UI/AspNetCore/Toolbars.md
@@ -0,0 +1,3 @@
+# Toolbars
+
+TODO
\ No newline at end of file
diff --git a/docs/en/docs-nav.json b/docs/en/docs-nav.json
index c3af945e85..c273e59346 100644
--- a/docs/en/docs-nav.json
+++ b/docs/en/docs-nav.json
@@ -293,16 +293,7 @@
},
{
"text": "Tag Helpers",
- "items": [
- {
- "text": "Live Demo",
- "path": "UI/AspNetCore/Tag-Helpers/Index.md"
- },
- {
- "text": "Buttons",
- "path": "UI/AspNetCore/Tag-Helpers/Buttons.md"
- }
- ]
+ "path": "UI/AspNetCore/Tag-Helpers/Index.md"
},
{
"text": "Widgets",
@@ -325,9 +316,17 @@
"text": "Permission Management",
"path": "UI/Angular/Permission-Management.md"
},
+ {
+ "text": "Config State",
+ "path": "UI/Angular/Config-State.md"
+ },
{
"text": "Component Replacement",
"path": "UI/Angular/Component-Replacement.md"
+ },
+ {
+ "text": "Custom Setting Page",
+ "path": "UI/Angular/Custom-Setting-Page.md"
}
]
}
diff --git a/docs/en/images/bookstore-added-brand-files.png b/docs/en/images/bookstore-added-brand-files.png
new file mode 100644
index 0000000000..15ef283a2a
Binary files /dev/null and b/docs/en/images/bookstore-added-brand-files.png differ
diff --git a/docs/en/images/bookstore-added-logo.png b/docs/en/images/bookstore-added-logo.png
new file mode 100644
index 0000000000..55af77a5f4
Binary files /dev/null and b/docs/en/images/bookstore-added-logo.png differ
diff --git a/docs/en/images/bookstore-added-role-js-file.png b/docs/en/images/bookstore-added-role-js-file.png
new file mode 100644
index 0000000000..00881bf808
Binary files /dev/null and b/docs/en/images/bookstore-added-role-js-file.png differ
diff --git a/docs/en/images/bookstore-brand-area-highlighted.png b/docs/en/images/bookstore-brand-area-highlighted.png
new file mode 100644
index 0000000000..7ab1b8fb7f
Binary files /dev/null and b/docs/en/images/bookstore-brand-area-highlighted.png differ
diff --git a/docs/en/images/bookstore-global-css-file.png b/docs/en/images/bookstore-global-css-file.png
new file mode 100644
index 0000000000..e764fef8ee
Binary files /dev/null and b/docs/en/images/bookstore-global-css-file.png differ
diff --git a/docs/en/images/bookstore-google-analytics-view-component.png b/docs/en/images/bookstore-google-analytics-view-component.png
new file mode 100644
index 0000000000..e548a00935
Binary files /dev/null and b/docs/en/images/bookstore-google-analytics-view-component.png differ
diff --git a/docs/en/images/bookstore-menus-highlighted.png b/docs/en/images/bookstore-menus-highlighted.png
new file mode 100644
index 0000000000..c4f3237b00
Binary files /dev/null and b/docs/en/images/bookstore-menus-highlighted.png differ
diff --git a/docs/en/images/bookstore-notification-icon-on-toolbar.png b/docs/en/images/bookstore-notification-icon-on-toolbar.png
new file mode 100644
index 0000000000..817491e9eb
Binary files /dev/null and b/docs/en/images/bookstore-notification-icon-on-toolbar.png differ
diff --git a/docs/en/images/bookstore-notification-view-component.png b/docs/en/images/bookstore-notification-view-component.png
new file mode 100644
index 0000000000..3fc300efe1
Binary files /dev/null and b/docs/en/images/bookstore-notification-view-component.png differ
diff --git a/docs/en/images/bookstore-toolbar-highlighted.png b/docs/en/images/bookstore-toolbar-highlighted.png
new file mode 100644
index 0000000000..f2b7c3f57e
Binary files /dev/null and b/docs/en/images/bookstore-toolbar-highlighted.png differ
diff --git a/docs/en/images/overriding-login-cshtml.png b/docs/en/images/overriding-login-cshtml.png
new file mode 100644
index 0000000000..d6daa4a141
Binary files /dev/null and b/docs/en/images/overriding-login-cshtml.png differ
diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/BasicTheme.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/BasicTheme.cs
index 01d3a35db2..60d1307b38 100644
--- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/BasicTheme.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/BasicTheme.cs
@@ -8,7 +8,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic
{
public const string Name = "Basic";
- public string GetLayout(string name, bool fallbackToDefault = true)
+ public virtual string GetLayout(string name, bool fallbackToDefault = true)
{
switch (name)
{
diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/AngularModuleSourceCodeAdder.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/AngularModuleSourceCodeAdder.cs
new file mode 100644
index 0000000000..2d1e237933
--- /dev/null
+++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/AngularModuleSourceCodeAdder.cs
@@ -0,0 +1,198 @@
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using Volo.Abp.DependencyInjection;
+
+namespace Volo.Abp.Cli.ProjectModification
+{
+ public class AngularModuleSourceCodeAdder : ITransientDependency
+ {
+ public async Task AddAsync(string solutionFilePath, string angularPath)
+ {
+ var angularProjectsPath = Path.Combine(angularPath, "projects");
+
+ var projects = await CopyAndGetNamesOfAngularProjectsAsync(solutionFilePath, angularProjectsPath);
+
+ if (!projects.Any())
+ {
+ return;
+ }
+
+ await ReplaceProjectNamesAndCopySourCodeRequirementsToProjectsAsync(angularProjectsPath, projects);
+
+ await RemoveRedundantFilesAsync(angularProjectsPath, projects);
+
+ await AddPathsToTsConfigAsync(angularPath, angularProjectsPath, projects);
+
+ await AddProjectToAngularJsonAsync(angularPath, projects);
+ }
+
+ private async Task AddProjectToAngularJsonAsync(string angularPath, List projects)
+ {
+ var angularJsonFilePath = Path.Combine(angularPath, "angular.json");
+ var fileContent = File.ReadAllText(angularJsonFilePath);
+
+ var json = JObject.Parse(fileContent);
+
+ var projectsJobject = (JObject)json["projects"];
+
+ foreach (var project in projects)
+ {
+ projectsJobject.Add(project, new JObject(
+ new JProperty("projectType", "library"),
+ new JProperty("root", $"projects/{project}"),
+ new JProperty("sourceRoot", $"projects/{project}/src"),
+ new JProperty("prefix", "lib"),
+ new JProperty("architect", new JObject(
+ new JProperty("build", new JObject(
+ new JProperty("builder", "@angular-devkit/build-ng-package:build"),
+ new JProperty("options", new JObject(
+ new JProperty("tsConfig", $"projects/{project}/tsconfig.lib.json"),
+ new JProperty("project", $"projects/{project}/ng-package.json")
+ )),
+ new JProperty("configurations", new JObject(
+ new JProperty("production", new JObject(
+ new JProperty("tsConfig", $"projects/{project}/tsconfig.lib.prod.json")))
+ )))),
+ new JProperty("test", new JObject(
+ new JProperty("builder", "@angular-devkit/build-angular:karma"),
+ new JProperty("options", new JObject(
+ new JProperty("main", $"projects/{project}/src/test.ts"),
+ new JProperty("tsConfig", $"projects/{project}/tsconfig.spec.json"),
+ new JProperty("karmaConfig", $"projects/{project}/karma.conf.js")
+ )
+ ))),
+ new JProperty("lint", new JObject(
+ new JProperty("builder", "@angular-devkit/build-angular:tslint"),
+ new JProperty("options", new JObject(
+ new JProperty("tsConfig", new JArray(new JValue($"projects/{project}/tsconfig.lib.json"), new JValue($"projects/{project}/tsconfig.spec.json"))),
+ new JProperty("exclude", new JArray(new JValue("**/node_modules/**")))
+ ))
+ ))
+ ))
+ ));
+ }
+
+ File.WriteAllText(angularJsonFilePath, json.ToString(Formatting.Indented));
+ }
+
+ private async Task AddPathsToTsConfigAsync(string angularPath, string angularProjectsPath, List projects)
+ {
+ var tsConfigPath = Path.Combine(angularPath, "tsconfig.json");
+ var fileContent = File.ReadAllText(tsConfigPath);
+
+ var tsConfigAsJson = JObject.Parse(fileContent);
+
+ var compilerOptions = (JObject)tsConfigAsJson["compilerOptions"];
+
+ foreach (var project in projects)
+ {
+ var projectPackageName = await GetProjectPackageNameAsync(angularProjectsPath, project);
+
+ var property = new JProperty($"{projectPackageName}",
+ new JArray(new object[] { $"projects/{project}/src/public-api.ts" })
+ );
+ var property2 = new JProperty($"{projectPackageName}/*",
+ new JArray(new object[] { $"projects/{project}/src/lib/*" })
+ );
+
+ if (compilerOptions["paths"] == null)
+ {
+
+ compilerOptions.Add("paths", new JObject());
+ }
+
+ ((JObject)compilerOptions["paths"]).Add(property);
+ ((JObject)compilerOptions["paths"]).Add(property2);
+ }
+
+ File.WriteAllText(tsConfigPath, tsConfigAsJson.ToString(Formatting.Indented));
+ }
+
+ private async Task GetProjectPackageNameAsync(string angularProjectsPath, string project)
+ {
+ var packageJsonPath = Path.Combine(angularProjectsPath, project, "package.json");
+
+ var fileContent = File.ReadAllText(packageJsonPath);
+
+ return (string)JObject.Parse(fileContent)["name"];
+ }
+
+ private async Task RemoveRedundantFilesAsync(string angularProjectsPath, List projects)
+ {
+ foreach (var project in projects)
+ {
+ var jestConfigPath = Path.Combine(angularProjectsPath, project, "jest.config.js");
+
+ File.Delete(jestConfigPath);
+
+ var testPath = Path.Combine(angularProjectsPath, project, "src", "test.ts");
+
+ File.Delete(testPath);
+ }
+ }
+
+ private async Task ReplaceProjectNamesAndCopySourCodeRequirementsToProjectsAsync(string angularProjectsPath, List projects)
+ {
+ foreach (var project in projects)
+ {
+ var sourceCodeReqFolder = Path.Combine(angularProjectsPath, project, "source-code-requirements");
+
+ Directory.CreateDirectory(sourceCodeReqFolder);
+
+ var filesUnderSourceCodeReqFolder = Directory.GetFiles(sourceCodeReqFolder);
+
+ foreach (var fileUnderSourceCodeReqFolder in filesUnderSourceCodeReqFolder)
+ {
+ var newDest = Path.Combine(angularProjectsPath, project, Path.GetFileName(fileUnderSourceCodeReqFolder));
+ File.Move(fileUnderSourceCodeReqFolder, newDest);
+
+ var fileContent = File.ReadAllText(newDest);
+ fileContent = fileContent.Replace("{{project-name}}", project);
+ fileContent = fileContent.Replace("{{library-name-kebab-case}}", project);
+ File.WriteAllText(newDest, fileContent);
+ }
+ }
+ }
+
+ private async Task> CopyAndGetNamesOfAngularProjectsAsync(string solutionFilePath, string angularProjectsPath)
+ {
+ var projects = new List();
+
+ if (!Directory.Exists(angularProjectsPath))
+ {
+ Directory.CreateDirectory(angularProjectsPath);
+ }
+
+ var angularPathsInDownloadedSourceCode = Directory.GetDirectories(Path.Combine(Path.Combine(Path.GetDirectoryName(solutionFilePath), "modules"))).Select(p => Path.Combine(p, "angular"))
+ .Where(Directory.Exists);
+
+
+ foreach (var folder in angularPathsInDownloadedSourceCode)
+ {
+ var projectsInFolder = Directory.GetDirectories(folder);
+ foreach (var projectInFolder in projectsInFolder)
+ {
+ var projectName = Path.GetFileName(projectInFolder.TrimEnd('\\').TrimEnd('/'));
+
+ var destDirName = Path.Combine(angularProjectsPath, projectName);
+ if (Directory.Exists(destDirName))
+ {
+ Directory.Delete(projectInFolder, true);
+ continue;
+ }
+
+
+ projects.Add(projectName);
+
+ Directory.Move(projectInFolder, destDirName);
+ }
+ }
+
+ return projects;
+ }
+ }
+}
diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs
index 8ded87bf6f..dcb36d7bae 100644
--- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs
+++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs
@@ -30,6 +30,7 @@ namespace Volo.Abp.Cli.ProjectModification
public SourceCodeDownloadService SourceCodeDownloadService { get; }
public SolutionFileModifier SolutionFileModifier { get; }
public NugetPackageToLocalReferenceConverter NugetPackageToLocalReferenceConverter { get; }
+ public AngularModuleSourceCodeAdder AngularModuleSourceCodeAdder { get; }
public SolutionModuleAdder(
IJsonSerializer jsonSerializer,
@@ -42,7 +43,8 @@ namespace Volo.Abp.Cli.ProjectModification
IRemoteServiceExceptionHandler remoteServiceExceptionHandler,
SourceCodeDownloadService sourceCodeDownloadService,
SolutionFileModifier solutionFileModifier,
- NugetPackageToLocalReferenceConverter nugetPackageToLocalReferenceConverter)
+ NugetPackageToLocalReferenceConverter nugetPackageToLocalReferenceConverter,
+ AngularModuleSourceCodeAdder angularModuleSourceCodeAdder)
{
JsonSerializer = jsonSerializer;
ProjectNugetPackageAdder = projectNugetPackageAdder;
@@ -55,6 +57,7 @@ namespace Volo.Abp.Cli.ProjectModification
SourceCodeDownloadService = sourceCodeDownloadService;
SolutionFileModifier = solutionFileModifier;
NugetPackageToLocalReferenceConverter = nugetPackageToLocalReferenceConverter;
+ AngularModuleSourceCodeAdder = angularModuleSourceCodeAdder;
Logger = NullLogger.Instance;
}
@@ -83,11 +86,25 @@ namespace Volo.Abp.Cli.ProjectModification
await DownloadSourceCodesToSolutionFolder(module, modulesFolderInSolution, version);
await SolutionFileModifier.AddModuleToSolutionFileAsync(module, solutionFile);
await NugetPackageToLocalReferenceConverter.Convert(module, solutionFile);
+
+ await HandleAngularProject(module, solutionFile);
}
ModifyDbContext(projectFiles, module, startupProject, skipDbMigrations);
}
+ private async Task HandleAngularProject(ModuleWithMastersInfo module, string solutionFilePath)
+ {
+ var angularPath = Path.Combine(Path.GetDirectoryName(Path.GetDirectoryName(solutionFilePath)), "angular");
+
+ if (!Directory.Exists(angularPath))
+ {
+ return;
+ }
+
+ await AngularModuleSourceCodeAdder.AddAsync(solutionFilePath, angularPath);
+ }
+
private async Task DownloadSourceCodesToSolutionFolder(ModuleWithMastersInfo module, string modulesFolderInSolution, string version = null)
{
await SourceCodeDownloadService.DownloadAsync(
diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ar.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ar.json
new file mode 100644
index 0000000000..3fb22139b7
--- /dev/null
+++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/ar.json
@@ -0,0 +1,62 @@
+{
+ "culture": "ar",
+ "texts": {
+ "InternalServerErrorMessage": "حدث خطأ داخلي أثناء طلبك!",
+ "ValidationErrorMessage": "طلبك غير صحيح!",
+ "ValidationNarrativeErrorMessageTitle": "تم الكشف عن الأخطاء التالية أثناء التحقق .",
+ "DefaultErrorMessage": "حدث خطأ!",
+ "DefaultErrorMessageDetail": "لم يتم إرسال تفاصيل الخطأ بواسطة الخادم.",
+ "DefaultErrorMessage401": "أنت غير مصدق!",
+ "DefaultErrorMessage401Detail": "يجب عليك تسجيل الدخول لأداء هذه العملية.",
+ "DefaultErrorMessage403": "أنك غير مخول!",
+ "DefaultErrorMessage403Detail": "لا يسمح لك بإجراء هذه العملية!",
+ "DefaultErrorMessage404": "المورد غير موجود!",
+ "DefaultErrorMessage404Detail": "لم يتم العثور على المورد المطلوب على الخادم!",
+ "EntityNotFoundErrorMessage": "لا يوجد كيان {0} بالمعرف = {1}!",
+ "Languages": "اللغات",
+ "Error": "خطأ",
+ "AreYouSure": "هل أنت متأكد؟",
+ "Cancel": "إلغاء",
+ "Yes": "نعم",
+ "No": "لا",
+ "Ok": "حسنا",
+ "Close": "أغلق",
+ "Save": "حفظ",
+ "SavingWithThreeDot": "حفظ...",
+ "Actions": "أجراءات",
+ "Delete": "حذف",
+ "Edit": "تعديل",
+ "Refresh": "تحديث",
+ "Language": "لغة",
+ "LoadMore": "تحميل المزيد",
+ "ProcessingWithThreeDot": "معالجة...",
+ "LoadingWithThreeDot": "جار التحميل...",
+ "Welcome": "أهلا بك",
+ "Login": "تسجيل الدخول",
+ "Register": "تسجيل",
+ "Logout": "تسجيل خروج",
+ "Submit": "إرسال",
+ "Back": "عودة",
+ "PagerSearch": "بحث",
+ "PagerNext": "التالى",
+ "PagerPrevious": "السابق",
+ "PagerFirst": "الأول",
+ "PagerLast": "الاخير",
+ "PagerInfo": "عرض _START_ الي _END_ من _TOTAL_ إدخالات",
+ "PagerInfoEmpty": "عرض 0 الي 0 من 0 إدخالات",
+ "PagerInfoFiltered": "(تمت تصفيته من _MAX_ مجموع الإدخالات)",
+ "NoDataAvailableInDatatable": "لا توجد بيانات متاحة في الجدول",
+ "PagerShowMenuEntries": "عرض _MENU_ إدخالات",
+ "DatatableActionDropdownDefaultText": "أجراءات",
+ "ChangePassword": "تغيير كلمة السر",
+ "PersonalInfo": "ملفي الشخصي",
+ "AreYouSureYouWantToCancelEditingWarningMessage": "لم تحفظ التغييرات.",
+ "UnhandledException": "استثناء غير معالج!",
+ "401Message": "غير مصرح",
+ "403Message": "ممنوع",
+ "404Message": "الصفحة غير موجودة",
+ "500Message": "خطأ في الخادم الداخلي",
+ "GoHomePage": "اذهب الى الصفحة الرئيسية",
+ "GoBack": "عد"
+ }
+}
diff --git a/npm/ng-packs/package.json b/npm/ng-packs/package.json
index b8ec511a18..e020b3f235 100644
--- a/npm/ng-packs/package.json
+++ b/npm/ng-packs/package.json
@@ -21,19 +21,19 @@
"generate:changelog": "conventional-changelog -p angular -i CHANGELOG.md -s"
},
"devDependencies": {
- "@abp/ng.account": "^2.1.0",
- "@abp/ng.account.config": "^2.1.0",
- "@abp/ng.core": "^2.1.0",
- "@abp/ng.feature-management": "^2.1.0",
- "@abp/ng.identity": "^2.1.0",
- "@abp/ng.identity.config": "^2.1.0",
- "@abp/ng.permission-management": "^2.1.0",
- "@abp/ng.setting-management": "^2.1.0",
- "@abp/ng.setting-management.config": "^2.1.0",
- "@abp/ng.tenant-management": "^2.1.0",
- "@abp/ng.tenant-management.config": "^2.1.0",
- "@abp/ng.theme.basic": "^2.1.0",
- "@abp/ng.theme.shared": "^2.1.0",
+ "@abp/ng.account": "~2.1.0",
+ "@abp/ng.account.config": "~2.1.0",
+ "@abp/ng.core": "~2.1.0",
+ "@abp/ng.feature-management": "~2.1.0",
+ "@abp/ng.identity": "~2.1.0",
+ "@abp/ng.identity.config": "~2.1.0",
+ "@abp/ng.permission-management": "~2.1.0",
+ "@abp/ng.setting-management": "~2.1.0",
+ "@abp/ng.setting-management.config": "~2.1.0",
+ "@abp/ng.tenant-management": "~2.1.0",
+ "@abp/ng.tenant-management.config": "~2.1.0",
+ "@abp/ng.theme.basic": "~2.1.0",
+ "@abp/ng.theme.shared": "~2.1.0",
"@angular-builders/jest": "^8.2.0",
"@angular-devkit/build-angular": "~0.803.21",
"@angular-devkit/build-ng-packagr": "~0.803.21",
diff --git a/npm/ng-packs/packages/account/package.json b/npm/ng-packs/packages/account/package.json
index d4b136a17d..84d4b6bf56 100644
--- a/npm/ng-packs/packages/account/package.json
+++ b/npm/ng-packs/packages/account/package.json
@@ -7,8 +7,8 @@
"url": "https://github.com/abpframework/abp.git"
},
"dependencies": {
- "@abp/ng.account.config": "^2.2.0",
- "@abp/ng.theme.shared": "^2.2.0"
+ "@abp/ng.account.config": "~2.2.0",
+ "@abp/ng.theme.shared": "~2.2.0"
},
"publishConfig": {
"access": "public"
diff --git a/npm/ng-packs/packages/core/src/lib/states/config.state.ts b/npm/ng-packs/packages/core/src/lib/states/config.state.ts
index 3e4c544f11..f424d83cb2 100644
--- a/npm/ng-packs/packages/core/src/lib/states/config.state.ts
+++ b/npm/ng-packs/packages/core/src/lib/states/config.state.ts
@@ -156,7 +156,7 @@ export class ConfigState {
const selector = createSelector([ConfigState], (state: Config.State) => {
if (!state.localization) return defaultValue || key;
- const { defaultResourceName } = state.environment.localization;
+ const defaultResourceName = snq(() => state.environment.localization.defaultResourceName);
if (keys[0] === '') {
if (!defaultResourceName) {
throw new Error(
@@ -170,7 +170,7 @@ export class ConfigState {
);
}
- keys[0] = snq(() => defaultResourceName);
+ keys[0] = defaultResourceName;
}
let localization = (keys as any).reduce((acc, val) => {
diff --git a/npm/ng-packs/packages/feature-management/package.json b/npm/ng-packs/packages/feature-management/package.json
index 4ac09b6f9c..f4518675c6 100644
--- a/npm/ng-packs/packages/feature-management/package.json
+++ b/npm/ng-packs/packages/feature-management/package.json
@@ -7,7 +7,7 @@
"url": "https://github.com/abpframework/abp.git"
},
"dependencies": {
- "@abp/ng.theme.shared": "^2.2.0"
+ "@abp/ng.theme.shared": "~2.2.0"
},
"publishConfig": {
"access": "public"
diff --git a/npm/ng-packs/packages/identity/package.json b/npm/ng-packs/packages/identity/package.json
index 67a19edb65..d003761f4c 100644
--- a/npm/ng-packs/packages/identity/package.json
+++ b/npm/ng-packs/packages/identity/package.json
@@ -7,9 +7,9 @@
"url": "https://github.com/abpframework/abp.git"
},
"dependencies": {
- "@abp/ng.identity.config": "^2.2.0",
- "@abp/ng.permission-management": "^2.2.0",
- "@abp/ng.theme.shared": "^2.2.0"
+ "@abp/ng.identity.config": "~2.2.0",
+ "@abp/ng.permission-management": "~2.2.0",
+ "@abp/ng.theme.shared": "~2.2.0"
},
"publishConfig": {
"access": "public"
diff --git a/npm/ng-packs/packages/permission-management/package.json b/npm/ng-packs/packages/permission-management/package.json
index cc0c80f01d..cb114343cb 100644
--- a/npm/ng-packs/packages/permission-management/package.json
+++ b/npm/ng-packs/packages/permission-management/package.json
@@ -7,7 +7,7 @@
"url": "https://github.com/abpframework/abp.git"
},
"dependencies": {
- "@abp/ng.theme.shared": "^2.2.0"
+ "@abp/ng.theme.shared": "~2.2.0"
},
"publishConfig": {
"access": "public"
diff --git a/npm/ng-packs/packages/setting-management/package.json b/npm/ng-packs/packages/setting-management/package.json
index 5947478234..78b733b3b1 100644
--- a/npm/ng-packs/packages/setting-management/package.json
+++ b/npm/ng-packs/packages/setting-management/package.json
@@ -7,8 +7,8 @@
"url": "https://github.com/abpframework/abp.git"
},
"dependencies": {
- "@abp/ng.setting-management.config": "^2.2.0",
- "@abp/ng.theme.shared": "^2.2.0"
+ "@abp/ng.setting-management.config": "~2.2.0",
+ "@abp/ng.theme.shared": "~2.2.0"
},
"publishConfig": {
"access": "public"
diff --git a/npm/ng-packs/packages/tenant-management/package.json b/npm/ng-packs/packages/tenant-management/package.json
index a53304ba9c..4e17d00c9c 100644
--- a/npm/ng-packs/packages/tenant-management/package.json
+++ b/npm/ng-packs/packages/tenant-management/package.json
@@ -7,9 +7,9 @@
"url": "https://github.com/abpframework/abp.git"
},
"dependencies": {
- "@abp/ng.feature-management": "^2.2.0",
- "@abp/ng.tenant-management.config": "^2.2.0",
- "@abp/ng.theme.shared": "^2.2.0"
+ "@abp/ng.feature-management": "~2.2.0",
+ "@abp/ng.tenant-management.config": "~2.2.0",
+ "@abp/ng.theme.shared": "~2.2.0"
},
"publishConfig": {
"access": "public"
diff --git a/npm/ng-packs/packages/theme-basic/package.json b/npm/ng-packs/packages/theme-basic/package.json
index 9bfc619578..7ac94efb0a 100644
--- a/npm/ng-packs/packages/theme-basic/package.json
+++ b/npm/ng-packs/packages/theme-basic/package.json
@@ -7,7 +7,7 @@
"url": "https://github.com/abpframework/abp.git"
},
"dependencies": {
- "@abp/ng.theme.shared": "^2.2.0"
+ "@abp/ng.theme.shared": "~2.2.0"
},
"publishConfig": {
"access": "public"
diff --git a/npm/ng-packs/packages/theme-shared/package.json b/npm/ng-packs/packages/theme-shared/package.json
index 1776bb0a12..efd21cd245 100644
--- a/npm/ng-packs/packages/theme-shared/package.json
+++ b/npm/ng-packs/packages/theme-shared/package.json
@@ -7,7 +7,7 @@
"url": "https://github.com/abpframework/abp.git"
},
"dependencies": {
- "@abp/ng.core": "^2.2.0",
+ "@abp/ng.core": "~2.2.0",
"@fortawesome/fontawesome-free": "^5.12.1",
"@ng-bootstrap/ng-bootstrap": "^5.3.0",
"@ngx-validate/core": "^0.0.7",
diff --git a/samples/BookStore-Angular-MongoDb/angular/package.json b/samples/BookStore-Angular-MongoDb/angular/package.json
index 18d8a6ca48..8b5656ea8f 100644
--- a/samples/BookStore-Angular-MongoDb/angular/package.json
+++ b/samples/BookStore-Angular-MongoDb/angular/package.json
@@ -13,11 +13,11 @@
},
"private": true,
"dependencies": {
- "@abp/ng.account": "^2.1.0",
- "@abp/ng.identity": "^2.1.0",
- "@abp/ng.setting-management": "^2.1.0",
- "@abp/ng.tenant-management": "^2.1.0",
- "@abp/ng.theme.basic": "^2.1.0",
+ "@abp/ng.account": "~2.2.0",
+ "@abp/ng.identity": "~2.2.0",
+ "@abp/ng.setting-management": "~2.2.0",
+ "@abp/ng.tenant-management": "~2.2.0",
+ "@abp/ng.theme.basic": "~2.2.0",
"@angular/animations": "~8.2.14",
"@angular/common": "~8.2.14",
"@angular/compiler": "~8.2.14",
diff --git a/templates/app/angular/package.json b/templates/app/angular/package.json
index faf50f8c72..20b3d0ea23 100644
--- a/templates/app/angular/package.json
+++ b/templates/app/angular/package.json
@@ -1,5 +1,5 @@
{
- "name": "ng9-abp",
+ "name": "MyProjectName",
"version": "0.0.0",
"scripts": {
"ng": "ng",
diff --git a/templates/module/angular/package.json b/templates/module/angular/package.json
index 34ea25858d..bd98cfb809 100644
--- a/templates/module/angular/package.json
+++ b/templates/module/angular/package.json
@@ -12,11 +12,11 @@
},
"private": true,
"dependencies": {
- "@abp/ng.account": "^2.2.0",
- "@abp/ng.theme.basic": "^2.2.0",
- "@abp/ng.identity": "^2.2.0",
- "@abp/ng.tenant-management": "^2.2.0",
- "@abp/ng.setting-management": "^2.2.0",
+ "@abp/ng.account": "~2.2.0",
+ "@abp/ng.theme.basic": "~2.2.0",
+ "@abp/ng.identity": "~2.2.0",
+ "@abp/ng.tenant-management": "~2.2.0",
+ "@abp/ng.setting-management": "~2.2.0",
"@angular/animations": "~8.2.14",
"@angular/common": "~8.2.14",
"@angular/compiler": "~8.2.14",
diff --git a/templates/module/angular/projects/my-project-name-config/package.json b/templates/module/angular/projects/my-project-name-config/package.json
index 6900d392a2..a7e2e66bf3 100644
--- a/templates/module/angular/projects/my-project-name-config/package.json
+++ b/templates/module/angular/projects/my-project-name-config/package.json
@@ -2,6 +2,6 @@
"name": "my-project-name.config",
"version": "0.0.1",
"peerDependencies": {
- "@abp/ng.core": ">=2.2.0"
+ "@abp/ng.core": "~2.2.0"
}
}
diff --git a/templates/module/angular/projects/my-project-name/package.json b/templates/module/angular/projects/my-project-name/package.json
index d9e41b2608..d41e9f74be 100644
--- a/templates/module/angular/projects/my-project-name/package.json
+++ b/templates/module/angular/projects/my-project-name/package.json
@@ -2,7 +2,7 @@
"name": "my-project-name",
"version": "0.0.1",
"dependencies": {
- "@abp/ng.theme.shared": "^2.2.0",
+ "@abp/ng.theme.shared": "~2.2.0",
"my-project-name.config": "^0.0.1"
}
}
diff --git a/templates/module/aspnet-core/src/MyCompanyName.MyProjectName.Domain.Shared/Localization/MyProjectName/sl.json b/templates/module/aspnet-core/src/MyCompanyName.MyProjectName.Domain.Shared/Localization/MyProjectName/sl.json
new file mode 100644
index 0000000000..687d42579c
--- /dev/null
+++ b/templates/module/aspnet-core/src/MyCompanyName.MyProjectName.Domain.Shared/Localization/MyProjectName/sl.json
@@ -0,0 +1,6 @@
+{
+ "culture": "sl",
+ "texts": {
+ "ManageYourProfile": "Upravljajte svojim profilom"
+ }
+}
\ No newline at end of file
diff --git a/templates/module/aspnet-core/src/MyCompanyName.MyProjectName.Domain.Shared/Localization/MyProjectName/zh-Hans.json b/templates/module/aspnet-core/src/MyCompanyName.MyProjectName.Domain.Shared/Localization/MyProjectName/zh-Hans.json
new file mode 100644
index 0000000000..99586f01c9
--- /dev/null
+++ b/templates/module/aspnet-core/src/MyCompanyName.MyProjectName.Domain.Shared/Localization/MyProjectName/zh-Hans.json
@@ -0,0 +1,6 @@
+{
+ "culture": "zh-Hans",
+ "texts": {
+ "ManageYourProfile": "管理个人资料"
+ }
+}
\ No newline at end of file
diff --git a/templates/module/aspnet-core/src/MyCompanyName.MyProjectName.Domain.Shared/Localization/MyProjectName/zh-Hant.json b/templates/module/aspnet-core/src/MyCompanyName.MyProjectName.Domain.Shared/Localization/MyProjectName/zh-Hant.json
new file mode 100644
index 0000000000..ceea055597
--- /dev/null
+++ b/templates/module/aspnet-core/src/MyCompanyName.MyProjectName.Domain.Shared/Localization/MyProjectName/zh-Hant.json
@@ -0,0 +1,6 @@
+{
+ "culture": "zh-Hant",
+ "texts": {
+ "ManageYourProfile": "管理個人資料"
+ }
+}
\ No newline at end of file