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. + +![ABP Angular UI Users Page with Advanced Entity Filters](./images/angular-advanced-entity-filters.png) + +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 + + +``` + +![ABP Angular UI Users Page with Advanced Entity Filters without form](./images/angular-advanced-entity-filters-without-form.png) + +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 + + +
+ +
+
+
+``` + +![ABP Angular UI Users Page with Advanced Entity Filters with form](./images/angular-advanced-entity-filters-with-form.png) + +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

+
+ + +
+ +
+
+
+``` + +![ABP Angular UI Users Page with Advanced Entity Filters with custom content above filter](./images/angular-advanced-entity-filters-with-custom-content-above-filter.png) 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: + +![ABP Angular UI Typeahead Lookup](./images/angular-lookup-typeahead.gif) + +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 `