diff --git a/.github/workflows/auto-pr.yml b/.github/workflows/auto-pr.yml
index 526cfc144b..d394ca56b3 100644
--- a/.github/workflows/auto-pr.yml
+++ b/.github/workflows/auto-pr.yml
@@ -1,4 +1,4 @@
-name: Merge branch dev with rel-8.3
+name: Merge branch prerel-9.0 with rel-8.3
on:
push:
branches:
@@ -7,7 +7,7 @@ permissions:
contents: read
jobs:
- merge-dev-with-rel-8-3:
+ merge-prerel-9-0-with-rel-8-3:
permissions:
contents: write # for peter-evans/create-pull-request to create branch
pull-requests: write # for peter-evans/create-pull-request to create a PR
@@ -15,7 +15,7 @@ jobs:
steps:
- uses: actions/checkout@v2
with:
- ref: dev
+ ref: prerel-9.0
- name: Reset promotion branch
run: |
git fetch origin rel-8.3:rel-8.3
@@ -24,8 +24,8 @@ jobs:
uses: peter-evans/create-pull-request@v3
with:
branch: auto-merge/rel-8-3/${{github.run_number}}
- title: Merge branch dev with rel-8.3
- body: This PR generated automatically to merge dev with rel-8.3. Please review the changed files before merging to prevent any errors that may occur.
+ title: Merge branch prerel-9.0 with rel-8.3
+ body: This PR generated automatically to merge prerel-9.0 with rel-8.3. Please review the changed files before merging to prevent any errors that may occur.
reviewers: maliming
token: ${{ github.token }}
- name: Merge Pull Request
@@ -33,4 +33,4 @@ jobs:
GH_TOKEN: ${{ secrets.BOT_SECRET }}
run: |
gh pr review auto-merge/rel-8-3/${{github.run_number}} --approve
- gh pr merge auto-merge/rel-8-3/${{github.run_number}} --merge --auto --delete-branch
\ No newline at end of file
+ gh pr merge auto-merge/rel-8-3/${{github.run_number}} --merge --auto --delete-branch
diff --git a/docs/en/deployment/ssl.md b/docs/en/deployment/ssl.md
index e1f463dba8..3b95e96a66 100644
--- a/docs/en/deployment/ssl.md
+++ b/docs/en/deployment/ssl.md
@@ -1,4 +1,4 @@
-# Configuring Configuring SSL certificate(HTTPS)
+# Configuring SSL certificate(HTTPS)
A website needs an SSL certificate in order to keep user data secure, verify ownership of the website, prevent attackers from creating a fake version of the site, and gain user trust.
diff --git a/docs/en/docs-nav.json b/docs/en/docs-nav.json
index 434219902c..27aac91ddf 100644
--- a/docs/en/docs-nav.json
+++ b/docs/en/docs-nav.json
@@ -1,41 +1,41 @@
{
"items": [
{
- "text": "Get started",
+ "text": "Get Started",
"items": [
{
"text": "Overview",
"path": "get-started"
},
{
- "text": "Single-layer solution",
+ "text": "Single Layer Web Application",
"path": "get-started/single-layer-web-application.md"
},
{
- "text": "Layered solution",
+ "text": "Layered Web Application",
"path": "get-started/layered-web-application.md"
},
{
- "text": "Microservice solution",
+ "text": "Microservice Solution",
"path": "get-started/microservice.md"
},
{
"text": "Others",
"items": [
{
- "text": "Empty ASP.NET Core application",
+ "text": "Empty ASP.NET Core MVC / Razor Pages Application",
"path": "get-started/empty-aspnet-core-application.md"
},
{
- "text": "MAUI application",
+ "text": "MAUI Application Startup Template",
"path": "get-started/maui.md"
},
{
- "text": "WPF application",
+ "text": "WPF Application Startup Template",
"path": "get-started/wpf.md"
},
{
- "text": "Console application",
+ "text": "Console Application Startup Template",
"path": "get-started/console.md"
}
]
@@ -57,36 +57,36 @@
"path": "tutorials/todo"
},
{
- "text": "Single-layer solution",
+ "text": "Single-Layer Solution",
"path": "tutorials/todo/single-layer"
},
{
- "text": "Layered solution",
+ "text": "Layered Solution",
"path": "tutorials/todo/layered"
}
]
},
{
- "text": "Book Store Application",
+ "text": "Web Application Development",
"items": [
{
"text": "Overview",
"path": "tutorials/book-store"
},
{
- "text": "1: Creating the server side",
+ "text": "1: Creating the Server Side",
"path": "tutorials/book-store/part-01.md"
},
{
- "text": "2: The Book List page",
+ "text": "2: The Book List Page",
"path": "tutorials/book-store/part-02.md"
},
{
- "text": "3: Creating, updating and deleting books",
+ "text": "3: Creating, Updating and Deleting Books",
"path": "tutorials/book-store/part-03.md"
},
{
- "text": "4: Integration tests",
+ "text": "4: Integration Tests",
"path": "tutorials/book-store/part-04.md"
},
{
@@ -94,23 +94,23 @@
"path": "tutorials/book-store/part-05.md"
},
{
- "text": "6: Authors: Domain layer",
+ "text": "6: Authors: Domain Layer",
"path": "tutorials/book-store/part-06.md"
},
{
- "text": "7: Authors: Database integration",
+ "text": "7: Authors: Database Integration",
"path": "tutorials/book-store/part-07.md"
},
{
- "text": "8: Authors: Application layer",
+ "text": "8: Authors: Application Layer",
"path": "tutorials/book-store/part-08.md"
},
{
- "text": "9: Authors: User interface",
+ "text": "9: Authors: User Interface",
"path": "tutorials/book-store/part-09.md"
},
{
- "text": "10: Book to author relation",
+ "text": "10: Book to Author Relation",
"path": "tutorials/book-store/part-10.md"
}
]
@@ -123,35 +123,35 @@
"path": "tutorials/modular-crm/index.md"
},
{
- "text": "1: Creating the initial solution",
+ "text": "1: Creating the Initial Solution",
"path": "tutorials/modular-crm/part-01.md"
},
{
- "text": "2: Creating the initial Products module",
+ "text": "2: Creating the Initial Products Module",
"path": "tutorials/modular-crm/part-02.md"
},
{
- "text": "3: Building the Products module",
+ "text": "3: Building the Products Module",
"path": "tutorials/modular-crm/part-03.md"
},
{
- "text": "4: Creating the initial Ordering module",
+ "text": "4: Creating the Initial Ordering Module",
"path": "tutorials/modular-crm/part-04.md"
},
{
- "text": "5: Building the Ordering module",
+ "text": "5: Building the Ordering Module",
"path": "tutorials/modular-crm/part-05.md"
},
{
- "text": "6: Integrating the modules: Implementing Integration Services",
+ "text": "6: Integrating the Modules: Implementing Integration Services",
"path": "tutorials/modular-crm/part-06.md"
},
{
- "text": "7: Integrating the modules: Communication via Messages (Events)",
+ "text": "7: Integrating the Modules: Communication via Messages (Events)",
"path": "tutorials/modular-crm/part-07.md"
},
{
- "text": "8: Integrating the modules: Joining the Products and Orders Data",
+ "text": "8: Integrating the Modules: Joining the Products and Orders Data",
"path": "tutorials/modular-crm/part-08.md"
}
]
@@ -177,7 +177,7 @@
"path": "cli"
},
{
- "text": "Examples for the new command",
+ "text": "New Solution Sample Commands",
"path": "cli/new-command-samples.md"
}
]
@@ -256,7 +256,7 @@
"path": "suite/add-solution.md"
},
{
- "text": "Creating new ABP solution",
+ "text": "Creating New ABP Solution",
"path": "suite/create-solution.md"
},
{
@@ -271,7 +271,7 @@
"path": "suite/creating-many-to-many-relationship.md"
},
{
- "text": "Generating from an Existing Database",
+ "text": "Generating From an Existing Database",
"path": "suite/generating-entities-from-an-existing-database-table.md"
},
{
@@ -301,7 +301,7 @@
"path": "suite/editing-templates.md"
},
{
- "text": "How to uninstall",
+ "text": "How to Uninstall",
"path": "suite/how-to-uninstall.md"
}
]
@@ -336,7 +336,7 @@
]
},
{
- "text": "Caching",
+ "text": "Distributed Caching",
"items": [
{
"text": "Overview",
@@ -653,7 +653,7 @@
"path": "framework/architecture"
},
{
- "text": "Best Practices",
+ "text": "Module Development Best Practices & Conventions",
"items": [
{
"text": "Overview",
@@ -1184,7 +1184,7 @@
"text": "Other Components",
"items": [
{
- "text": "SubmitButton",
+ "text": "SubmitButton Component",
"path": "framework/ui/blazor/components/submit-button.md"
}
]
@@ -1226,6 +1226,10 @@
{
"text": "Angular",
"items": [
+ {
+ "text": "Overview",
+ "path": "framework/ui/angular/overview.md"
+ },
{
"text": "Quick Start",
"path": "framework/ui/angular/quick-start.md"
@@ -1278,7 +1282,7 @@
"path": "framework/ui/angular/http-requests.md"
},
{
- "text": "Customize Error Handling",
+ "text": "Error Handling",
"path": "framework/ui/angular/http-error-handling.md"
}
]
@@ -1438,6 +1442,10 @@
"text": "Modifying the Menu",
"path": "framework/ui/angular/modifying-the-menu.md"
},
+ {
+ "text": "Manage Profile Page Tabs",
+ "path": "framework/ui/angular/manage-profile-page-tabs.md"
+ },
{
"text": "Sorting Navigation Elements",
"path": "framework/ui/angular/sorting-navigation-elements.md"
@@ -1491,6 +1499,18 @@
{
"text": "Card",
"path": "framework/ui/angular/card-component.md"
+ },
+ {
+ "text": "Password Complexity Indicator",
+ "path": "framework/ui/angular/password-complexity-indicator-component.md"
+ },
+ {
+ "text": "Lookup Components(Pro)",
+ "path": "framework/ui/angular/lookup-components.md"
+ },
+ {
+ "text": "Entity Filters(Pro)",
+ "path": "framework/ui/angular/entity-filters.md"
}
]
}
@@ -1631,7 +1651,7 @@
"path": "solution-templates/microservice"
},
{
- "text": "Application Module",
+ "text": "Module Solution",
"path": "solution-templates/application-module"
}
]
@@ -1946,7 +1966,7 @@
"path": "others/why-abp-platform.md"
},
{
- "text": "Free license vs Pro licenses?",
+ "text": "Free (Open Source) License vs Commercial (Pro) Licenses",
"path": "others/free-licenses-vs-pro-licenses.md"
},
{
@@ -1954,7 +1974,7 @@
"path": "others/penetration-test-report.md"
},
{
- "text": "ASP.NET Zero vs ABP",
+ "text": "ABP vs ASP.NET Zero",
"path": "others/aspnet-zero-vs-abp.md"
},
{
diff --git a/docs/en/framework/ui/angular/entity-filters.md b/docs/en/framework/ui/angular/entity-filters.md
new file mode 100644
index 0000000000..75a197b81b
--- /dev/null
+++ b/docs/en/framework/ui/angular/entity-filters.md
@@ -0,0 +1,143 @@
+# Entity Filters
+
+Every CRUD page includes some sort of inputs to filter the listed data. Some of the inputs are common among all of the entities like the `Search` box. In addition, every entity has its own advanced filters depending on its fields. To reduce the amount of code written on every CRUD page, the Angular UI of ABP Commercial introduces a new type of component called `abp-advanced-entity-filters`
+
+## Setup
+
+The components are in the _@volo/abp.commercial.ng.ui_ package, which is included in the ABP templates. So, as long as your project is a product of these templates and unless you delete the package, you have access to the entity filter components.
+You can either import the `CommercialUiModule` which contains other components as well as `AdvancedEntityFilters` or you can directly import the `AdvancedEntityFiltersModule` if you do not need other components. Here is how you import them in your Angular module:
+
+```javascript
+import {
+ CommercialUiModule,
+ AdvancedEntityFiltersModule,
+} from "@volo/abp.commercial.ng.ui";
+
+@NgModule({
+ imports: [
+ // other imports
+ CommercialUiModule,
+
+ // OR
+
+ AdvancedEntityFiltersModule,
+ ],
+ // rest of the module metadata
+})
+export class YourModule {}
+```
+
+## Usage
+
+Let's take a look at the `Users` page from the `Identity` module.
+
+
+
+As shown in the screenshot, `abp-advanced-entity-filters` usually contain two parts, an entity filter (common among entities), i.e. `abp-entity-filter`, and entity-specific filters which are encapsulated within the `abp-advanced-entity-filters-form` component.
+
+`users.component.html`
+
+```html
+
+
+
+
+
+```
+
+The `abp-advanced-entity-filters` already contains the `abp-entity-filter` component so you do not need to pass it. However, the `abp-entity-filter` component needs an instance of `ListService` which is usually stored in the `list` field of the page. You can also change the placeholder of the component via `entityFilterPlaceholder` input which is passed into the `abpLocalization` pipe so that it uses the translated text. Default is `'AbpUi::PagerSearch'`
+
+E.g
+
+```html
+
+
+
+```
+
+### Inputs
+
+- `list`: an instance of `ListService`
+- `entityFilterPlaceholder`: the placeholder of `abp-entity-filter` component. Default: `'AbpUi::PagerSearch'`
+- `localizationSourceName`: the localization source of the current page. E.g: `AbpIdentity`
+
+### Inner components
+
+Some entities are simple and do not require any filter other than the `abp-entity-filter`. In this case, you can simply use the `abp-advanced-entity-filters` without anything in between.
+
+E.g.
+
+Let's remove `form` from the `Users` page
+
+```html
+
+
+```
+
+
+
+If your component needs other filters, you can pass your own `form` within the `abp-advanced-entity-filters-form` component. This will render your form as well as a toggle (`abp-advanced-entity-filters-toggle`) to show and hide the form
+
+E.g.
+
+```html
+
+
+
+
+
+```
+
+
+
+Last but not least, if you need to render some content above the `abp-entity-filter` component, you can use the `abp-advanced-entity-filters-above-search`.
+
+E.g.
+
+```html
+
+
+
Custom Content above entity-filter
+
+
+
+
+
+
+```
+
+
diff --git a/docs/en/framework/ui/angular/environment.md b/docs/en/framework/ui/angular/environment.md
index 33f53b7836..7fd1b1273a 100644
--- a/docs/en/framework/ui/angular/environment.md
+++ b/docs/en/framework/ui/angular/environment.md
@@ -101,6 +101,22 @@ export interface RemoteEnv {
- `method`: HTTP method to be used when retrieving environment config. Default: `GET`
- `headers`: If extra headers are needed for the request, it can be set through this field.
+## Provide Environment Variable to Core Module
+
+`environment` variable comes from angular host application.
+
+```js
+import { environment } from '../environments/environment';
+
+@NgModule({
+ imports: [
+ //...other imports
+ CoreModule.forRoot({
+ environment
+ }),
+ ]
+})
+```
## EnvironmentService
` EnvironmentService` is a singleton service, i.e. provided in root level of your application, and keeps the environment in the internal store.
diff --git a/docs/en/framework/ui/angular/images/angular-advanced-entity-filters-with-custom-content-above-filter.png b/docs/en/framework/ui/angular/images/angular-advanced-entity-filters-with-custom-content-above-filter.png
index ac81a885ec..0feab57342 100644
Binary files a/docs/en/framework/ui/angular/images/angular-advanced-entity-filters-with-custom-content-above-filter.png and b/docs/en/framework/ui/angular/images/angular-advanced-entity-filters-with-custom-content-above-filter.png differ
diff --git a/docs/en/framework/ui/angular/images/angular-advanced-entity-filters-with-form.png b/docs/en/framework/ui/angular/images/angular-advanced-entity-filters-with-form.png
index d0827ed369..ef469a3d9d 100644
Binary files a/docs/en/framework/ui/angular/images/angular-advanced-entity-filters-with-form.png and b/docs/en/framework/ui/angular/images/angular-advanced-entity-filters-with-form.png differ
diff --git a/docs/en/framework/ui/angular/images/angular-advanced-entity-filters-without-form.png b/docs/en/framework/ui/angular/images/angular-advanced-entity-filters-without-form.png
index 3c3707a857..18b7780008 100644
Binary files a/docs/en/framework/ui/angular/images/angular-advanced-entity-filters-without-form.png and b/docs/en/framework/ui/angular/images/angular-advanced-entity-filters-without-form.png differ
diff --git a/docs/en/framework/ui/angular/images/angular-advanced-entity-filters.png b/docs/en/framework/ui/angular/images/angular-advanced-entity-filters.png
index 5ae22b56a4..3f381a1cc6 100644
Binary files a/docs/en/framework/ui/angular/images/angular-advanced-entity-filters.png and b/docs/en/framework/ui/angular/images/angular-advanced-entity-filters.png differ
diff --git a/docs/en/framework/ui/angular/images/angular-lookup-select.gif b/docs/en/framework/ui/angular/images/angular-lookup-select.gif
new file mode 100644
index 0000000000..4194d362f5
Binary files /dev/null and b/docs/en/framework/ui/angular/images/angular-lookup-select.gif differ
diff --git a/docs/en/framework/ui/angular/images/angular-lookup-typeahead.gif b/docs/en/framework/ui/angular/images/angular-lookup-typeahead.gif
new file mode 100644
index 0000000000..6f75cc536d
Binary files /dev/null and b/docs/en/framework/ui/angular/images/angular-lookup-typeahead.gif differ
diff --git a/docs/en/framework/ui/angular/images/grouped-menu-mobile.png b/docs/en/framework/ui/angular/images/grouped-menu-mobile.png
new file mode 100644
index 0000000000..9c2e176437
Binary files /dev/null and b/docs/en/framework/ui/angular/images/grouped-menu-mobile.png differ
diff --git a/docs/en/framework/ui/angular/images/grouped-menu.png b/docs/en/framework/ui/angular/images/grouped-menu.png
new file mode 100644
index 0000000000..f5b079796a
Binary files /dev/null and b/docs/en/framework/ui/angular/images/grouped-menu.png differ
diff --git a/docs/en/framework/ui/angular/images/manage-profile-page-new-tab.png b/docs/en/framework/ui/angular/images/manage-profile-page-new-tab.png
index 6d3145ccd4..2700ccbe90 100644
Binary files a/docs/en/framework/ui/angular/images/manage-profile-page-new-tab.png and b/docs/en/framework/ui/angular/images/manage-profile-page-new-tab.png differ
diff --git a/docs/en/framework/ui/angular/images/manage-profile-page.png b/docs/en/framework/ui/angular/images/manage-profile-page.png
index a699c29743..3df5c0f395 100644
Binary files a/docs/en/framework/ui/angular/images/manage-profile-page.png and b/docs/en/framework/ui/angular/images/manage-profile-page.png differ
diff --git a/docs/en/framework/ui/angular/lookup-components.md b/docs/en/framework/ui/angular/lookup-components.md
new file mode 100644
index 0000000000..ce1e32eefd
--- /dev/null
+++ b/docs/en/framework/ui/angular/lookup-components.md
@@ -0,0 +1,98 @@
+# Lookup Components
+
+The Angular UI of ABP Commercial introduces some components with `abp-lookup-...` selector prefix. These components are used for retrieving relational entity data.
+
+## Setup
+
+The components are in the _@volo/abp.commercial.ng.ui_ package, which is included in the ABP templates. So, as long as your project is a product of these templates and unless you delete the package, you have access to the lookup components. Here is how you import them in your Angular module:
+
+```javascript
+import { CommercialUiModule } from '@volo/abp.commercial.ng.ui';
+
+@NgModule({
+ imports: [
+ // other imports
+ CommercialUiModule,
+ ],
+ // rest of the module metadata
+})
+export class YourModule {}
+```
+
+Now you can use the lookup components in your components declared by this module.
+
+## Lookup HTTP Requests
+
+The lookup requests are used by all lookup components to get the related entity records. Because of lexical this, _they must be arrow functions_.
+
+```javascript
+@Injectable({
+ providedIn: 'root'
+})
+export class AuthorService {
+ getCountryLookup = (input: LookupRequestDto) =>
+ this.restService.request>>({
+ method: 'GET',
+ url: '/api/app/authors/country-lookup',
+ params: { filter: input.filter, skipCount: input.skipCount, maxResultCount: input.maxResultCount },
+ },
+ { apiName: this.apiName });
+
+ // rest of the service is removed for brevity
+}
+```
+
+## Lookup Typeahead Component
+
+Typeahead is a good choice when you have an unknown number of records for the related entity or you want to improve the UX with a search ability. Although not the best scenario, the country picker below shows how the lookup typeahead works:
+
+
+
+Here is how it is used in the template.
+
+```html
+
+```
+
+The available properties are as follows:
+
+- **cid:** The id of the form control (e.g. an input or a select element) inside the lookup component. Lets form controls respond to `