From aab32ad8c5dc6c968f42f4e6ee57953f68eec5a8 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Fri, 27 Mar 2020 09:10:45 +0300 Subject: [PATCH 01/11] chore: set dev-app as default project --- npm/ng-packs/angular.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/npm/ng-packs/angular.json b/npm/ng-packs/angular.json index d0289505fe..af185688b2 100644 --- a/npm/ng-packs/angular.json +++ b/npm/ng-packs/angular.json @@ -526,5 +526,5 @@ } } }, - "defaultProject": "core" + "defaultProject": "dev-app" } From 83645730b9bc38eae238861c9432acb05518189f Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Fri, 27 Mar 2020 09:16:45 +0300 Subject: [PATCH 02/11] refactor: deprecate the requirements obj --- .../apps/dev-app/src/app/app.module.ts | 3 -- .../packages/core/src/lib/models/common.ts | 6 ++- templates/app/angular/src/app/app.module.ts | 6 +-- .../module/angular/src/app/app.module.ts | 46 +++++++++---------- 4 files changed, 27 insertions(+), 34 deletions(-) diff --git a/npm/ng-packs/apps/dev-app/src/app/app.module.ts b/npm/ng-packs/apps/dev-app/src/app/app.module.ts index f1324c233a..64f8150f01 100644 --- a/npm/ng-packs/apps/dev-app/src/app/app.module.ts +++ b/npm/ng-packs/apps/dev-app/src/app/app.module.ts @@ -21,9 +21,6 @@ const LOGGERS = [NgxsLoggerPluginModule.forRoot({ disabled: false })]; imports: [ CoreModule.forRoot({ environment, - requirements: { - layouts: LAYOUTS, - }, }), ThemeSharedModule.forRoot(), AccountConfigModule.forRoot({ redirectUrl: '/' }), diff --git a/npm/ng-packs/packages/core/src/lib/models/common.ts b/npm/ng-packs/packages/core/src/lib/models/common.ts index 8b4fb76cb0..79792a1b61 100644 --- a/npm/ng-packs/packages/core/src/lib/models/common.ts +++ b/npm/ng-packs/packages/core/src/lib/models/common.ts @@ -6,7 +6,11 @@ import { Subject } from 'rxjs'; export namespace ABP { export interface Root { environment: Partial; - requirements: Config.Requirements; + /** + * + * @deprecated To be deleted in v3.0 + */ + requirements?: Config.Requirements; } export type PagedResponse = { diff --git a/templates/app/angular/src/app/app.module.ts b/templates/app/angular/src/app/app.module.ts index 5df354fb38..928dff5172 100644 --- a/templates/app/angular/src/app/app.module.ts +++ b/templates/app/angular/src/app/app.module.ts @@ -3,7 +3,6 @@ import { CoreModule } from '@abp/ng.core'; import { IdentityConfigModule } from '@abp/ng.identity.config'; import { SettingManagementConfigModule } from '@abp/ng.setting-management.config'; import { TenantManagementConfigModule } from '@abp/ng.tenant-management.config'; -import { LAYOUTS } from '@abp/ng.theme.basic'; import { ThemeSharedModule } from '@abp/ng.theme.shared'; import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; @@ -20,10 +19,7 @@ const LOGGERS = [NgxsLoggerPluginModule.forRoot({ disabled: false })]; @NgModule({ imports: [ CoreModule.forRoot({ - environment, - requirements: { - layouts: LAYOUTS - } + environment }), ThemeSharedModule.forRoot(), AccountConfigModule.forRoot({ redirectUrl: '/' }), diff --git a/templates/module/angular/src/app/app.module.ts b/templates/module/angular/src/app/app.module.ts index c0fef36c9a..2705a3318b 100644 --- a/templates/module/angular/src/app/app.module.ts +++ b/templates/module/angular/src/app/app.module.ts @@ -1,21 +1,20 @@ -import { AccountConfigModule } from '@abp/ng.account.config'; -import { CoreModule } from '@abp/ng.core'; -import { IdentityConfigModule } from '@abp/ng.identity.config'; -import { SettingManagementConfigModule } from '@abp/ng.setting-management.config'; -import { TenantManagementConfigModule } from '@abp/ng.tenant-management.config'; -import { LAYOUTS } from '@abp/ng.theme.basic'; -import { ThemeSharedModule } from '@abp/ng.theme.shared'; -import { NgModule } from '@angular/core'; -import { BrowserModule } from '@angular/platform-browser'; -import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; -import { NgxsLoggerPluginModule } from '@ngxs/logger-plugin'; -import { NgxsModule } from '@ngxs/store'; -import { OAuthModule } from 'angular-oauth2-oidc'; -import { environment } from '../environments/environment'; -import { AppRoutingModule } from './app-routing.module'; -import { AppComponent } from './app.component'; -import { SharedModule } from './shared/shared.module'; -import { MyProjectNameConfigModule } from '../../projects/my-project-name-config/src/public-api'; +import { AccountConfigModule } from "@abp/ng.account.config"; +import { CoreModule } from "@abp/ng.core"; +import { IdentityConfigModule } from "@abp/ng.identity.config"; +import { SettingManagementConfigModule } from "@abp/ng.setting-management.config"; +import { TenantManagementConfigModule } from "@abp/ng.tenant-management.config"; +import { ThemeSharedModule } from "@abp/ng.theme.shared"; +import { NgModule } from "@angular/core"; +import { BrowserModule } from "@angular/platform-browser"; +import { BrowserAnimationsModule } from "@angular/platform-browser/animations"; +import { NgxsLoggerPluginModule } from "@ngxs/logger-plugin"; +import { NgxsModule } from "@ngxs/store"; +import { OAuthModule } from "angular-oauth2-oidc"; +import { environment } from "../environments/environment"; +import { AppRoutingModule } from "./app-routing.module"; +import { AppComponent } from "./app.component"; +import { SharedModule } from "./shared/shared.module"; +import { MyProjectNameConfigModule } from "../../projects/my-project-name-config/src/public-api"; const LOGGERS = [NgxsLoggerPluginModule.forRoot({ disabled: false })]; @@ -24,14 +23,11 @@ const LOGGERS = [NgxsLoggerPluginModule.forRoot({ disabled: false })]; imports: [ ThemeSharedModule.forRoot(), CoreModule.forRoot({ - environment, - requirements: { - layouts: LAYOUTS, - }, + environment }), OAuthModule.forRoot(), NgxsModule.forRoot([]), - AccountConfigModule.forRoot({ redirectUrl: '/' }), + AccountConfigModule.forRoot({ redirectUrl: "/" }), IdentityConfigModule, TenantManagementConfigModule, SettingManagementConfigModule, @@ -41,8 +37,8 @@ const LOGGERS = [NgxsLoggerPluginModule.forRoot({ disabled: false })]; AppRoutingModule, SharedModule, - ...(environment.production ? [] : LOGGERS), + ...(environment.production ? [] : LOGGERS) ], - bootstrap: [AppComponent], + bootstrap: [AppComponent] }) export class AppModule {} From 4ad19ebf84a7af0d68dcd9968bf13e510c6b77ee Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Fri, 27 Mar 2020 10:21:56 +0300 Subject: [PATCH 03/11] feat(theme-basic): add layouts to replaceable components state --- .../src/lib/services/initial.service.ts | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/npm/ng-packs/packages/theme-basic/src/lib/services/initial.service.ts b/npm/ng-packs/packages/theme-basic/src/lib/services/initial.service.ts index 33c7c18770..21fb1756bc 100644 --- a/npm/ng-packs/packages/theme-basic/src/lib/services/initial.service.ts +++ b/npm/ng-packs/packages/theme-basic/src/lib/services/initial.service.ts @@ -1,12 +1,29 @@ +import { LazyLoadService, AddReplaceableComponent } from '@abp/ng.core'; import { Injectable } from '@angular/core'; -import { Router } from '@angular/router'; -import { LazyLoadService } from '@abp/ng.core'; +import { Store } from '@ngxs/store'; import styles from '../constants/styles'; +import { ApplicationLayoutComponent } from '../components/application-layout/application-layout.component'; +import { AccountLayoutComponent } from '../components/account-layout/account-layout.component'; +import { EmptyLayoutComponent } from '../components/empty-layout/empty-layout.component'; @Injectable({ providedIn: 'root' }) export class InitialService { - constructor(private lazyLoadService: LazyLoadService) { + constructor(private lazyLoadService: LazyLoadService, private store: Store) { this.appendStyle().subscribe(); + this.store.dispatch([ + new AddReplaceableComponent({ + key: 'Theme.ApplicationLayoutComponent', + component: ApplicationLayoutComponent, + }), + new AddReplaceableComponent({ + key: 'Theme.AccountLayoutComponent', + component: AccountLayoutComponent, + }), + new AddReplaceableComponent({ + key: 'Theme.EmptyLayoutComponent', + component: EmptyLayoutComponent, + }), + ]); } appendStyle() { From 857ee6b9ef82376c42229c613764feaee7896a95 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Fri, 27 Mar 2020 10:22:45 +0300 Subject: [PATCH 04/11] feat(core): get layouts from store in dynamic-layout.component --- .../components/dynamic-layout.component.ts | 49 +++++---- .../tests/dynamic-layout.component.spec.ts | 102 +++++++++++------- 2 files changed, 93 insertions(+), 58 deletions(-) diff --git a/npm/ng-packs/packages/core/src/lib/components/dynamic-layout.component.ts b/npm/ng-packs/packages/core/src/lib/components/dynamic-layout.component.ts index 7fc1826efe..fc3926a1ea 100644 --- a/npm/ng-packs/packages/core/src/lib/components/dynamic-layout.component.ts +++ b/npm/ng-packs/packages/core/src/lib/components/dynamic-layout.component.ts @@ -1,13 +1,15 @@ import { Component, Input, OnDestroy, Type, Injector } from '@angular/core'; import { ActivatedRoute, NavigationEnd, Router, UrlSegment } from '@angular/router'; import { Select, Store } from '@ngxs/store'; -import { Observable } from 'rxjs'; +import { Observable, combineLatest } from 'rxjs'; import snq from 'snq'; import { eLayoutType } from '../enums/common'; import { Config } from '../models/config'; import { ABP } from '../models/common'; import { ConfigState } from '../states/config.state'; import { takeUntilDestroy } from '../utils/rxjs-utils'; +import { ReplaceableComponentsState } from '../states/replaceable-components.state'; +import { ReplaceableComponents } from '../models/replaceable-components'; @Component({ selector: 'abp-dynamic-layout', @@ -20,24 +22,24 @@ import { takeUntilDestroy } from '../utils/rxjs-utils'; `, }) export class DynamicLayoutComponent implements OnDestroy { - @Select(ConfigState.getOne('requirements')) requirements$: Observable; + @Select(ReplaceableComponentsState.getComponent('Theme.ApplicationLayoutComponent')) + applicationLayout$: Observable; + + @Select(ReplaceableComponentsState.getComponent('Theme.AccountLayoutComponent')) + accountLayout$: Observable; + + @Select(ReplaceableComponentsState.getComponent('Theme.EmptyLayoutComponent')) + emptyLayout$: Observable; layout: Type; + layouts = {} as { [key in eLayoutType]: Type }; + + expectedLayout: eLayoutType = eLayoutType.empty; + constructor(private router: Router, private route: ActivatedRoute, private store: Store) { - const { - requirements: { layouts }, - routes, - } = this.store.selectSnapshot(ConfigState.getAll); - - if ((this.route.snapshot.data || {}).layout) { - this.layout = layouts - .filter(l => !!l) - .find( - (l: any) => - snq(() => l.type.toLowerCase().indexOf(this.route.snapshot.data.layout), -1) > -1, - ); - } + this.listenToLayouts(); + const { routes } = this.store.selectSnapshot(ConfigState.getAll); router.events.pipe(takeUntilDestroy(this)).subscribe(event => { if (event instanceof NavigationEnd) { @@ -45,16 +47,25 @@ export class DynamicLayoutComponent implements OnDestroy { { path: router.url.replace('/', '') }, ] as any); - const layout = (this.route.snapshot.data || {}).layout || findLayout(segments, routes); + this.expectedLayout = + (this.route.snapshot.data || {}).layout || findLayout(segments, routes); - this.layout = layouts - .filter(l => !!l) - .find((l: any) => snq(() => l.type.toLowerCase().indexOf(layout), -1) > -1); + this.layout = this.layouts[this.expectedLayout]; } }); } ngOnDestroy() {} + + listenToLayouts() { + combineLatest(this.applicationLayout$, this.accountLayout$, this.emptyLayout$) + .pipe(takeUntilDestroy(this)) + .subscribe(([application, account, empty]) => { + this.layouts.application = application.component; + this.layouts.account = account.component; + this.layouts.empty = empty.component; + }); + } } function findLayout(segments: UrlSegment[], routes: ABP.FullRoute[]): eLayoutType { diff --git a/npm/ng-packs/packages/core/src/lib/tests/dynamic-layout.component.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/dynamic-layout.component.spec.ts index 54a602b84a..0a123b6a4f 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/dynamic-layout.component.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/dynamic-layout.component.spec.ts @@ -1,36 +1,36 @@ import { Component, NgModule } from '@angular/core'; import { ActivatedRoute, RouterModule } from '@angular/router'; -import { createRoutingFactory, SpectatorRouting, SpyObject } from '@ngneat/spectator/jest'; -import { Store } from '@ngxs/store'; +import { createRoutingFactory, SpectatorRouting } from '@ngneat/spectator/jest'; +import { NgxsModule, Store } from '@ngxs/store'; +import { DynamicLayoutComponent, RouterOutletComponent } from '../components'; import { eLayoutType } from '../enums'; import { ABP } from '../models'; -import { DynamicLayoutComponent, RouterOutletComponent } from '../components'; +import { ConfigState, ReplaceableComponentsState } from '../states'; +import { ApplicationConfigurationService } from '../services'; @Component({ selector: 'abp-layout-application', template: '', }) -class DummyApplicationLayoutComponent { - static type = eLayoutType.application; -} +class DummyApplicationLayoutComponent {} @Component({ selector: 'abp-layout-account', template: '', }) -class DummyAccountLayoutComponent { - static type = eLayoutType.account; -} +class DummyAccountLayoutComponent {} @Component({ selector: 'abp-layout-empty', template: '', }) -class DummyEmptyLayoutComponent { - static type = eLayoutType.empty; -} +class DummyEmptyLayoutComponent {} -const LAYOUTS = [DummyApplicationLayoutComponent, DummyAccountLayoutComponent, DummyEmptyLayoutComponent]; +const LAYOUTS = [ + DummyApplicationLayoutComponent, + DummyAccountLayoutComponent, + DummyEmptyLayoutComponent, +]; @NgModule({ imports: [RouterModule], @@ -47,13 +47,57 @@ class DummyComponent { constructor(public route: ActivatedRoute) {} } +const storeData = { + ConfigState: { + routes: [ + { + path: '', + wrapper: true, + children: [ + { + path: 'parentWithLayout', + layout: eLayoutType.application, + children: [ + { path: 'childWithoutLayout' }, + { path: 'childWithLayout', layout: eLayoutType.account }, + ], + }, + ], + }, + { path: 'withData', layout: eLayoutType.application }, + , + ] as ABP.FullRoute[], + environment: { application: {} }, + }, + ReplaceableComponentsState: { + replaceableComponents: [ + { + key: 'Theme.ApplicationLayoutComponent', + component: DummyApplicationLayoutComponent, + }, + { + key: 'Theme.AccountLayoutComponent', + component: DummyAccountLayoutComponent, + }, + { + key: 'Theme.EmptyLayoutComponent', + component: DummyEmptyLayoutComponent, + }, + ], + }, +}; + describe('DynamicLayoutComponent', () => { const createComponent = createRoutingFactory({ component: RouterOutletComponent, stubsEnabled: false, - mocks: [Store], declarations: [DummyComponent, DynamicLayoutComponent], - imports: [RouterModule, DummyLayoutModule], + mocks: [ApplicationConfigurationService], + imports: [ + RouterModule, + DummyLayoutModule, + NgxsModule.forRoot([ConfigState, ReplaceableComponentsState]), + ], routes: [ { path: '', component: RouterOutletComponent }, { @@ -100,33 +144,13 @@ describe('DynamicLayoutComponent', () => { }); let spectator: SpectatorRouting; - let store: SpyObject; - const mockStoreData = { - requirements: { layouts: LAYOUTS }, - routes: [ - { - path: '', - wrapper: true, - children: [ - { - path: 'parentWithLayout', - layout: eLayoutType.application, - children: [{ path: 'childWithoutLayout' }, { path: 'childWithLayout', layout: eLayoutType.account }], - }, - ], - }, - { path: 'withData', layout: eLayoutType.application }, - , - ] as ABP.FullRoute[], - environment: { application: {} }, - }; - let storeSpy: jest.SpyInstance; + let store: Store; beforeEach(async () => { spectator = createComponent(); store = spectator.get(Store); - storeSpy = jest.spyOn(store, 'selectSnapshot'); - storeSpy.mockReturnValue(mockStoreData); + + store.reset(storeData); }); it('should handle application layout from parent abp route and display it', async () => { @@ -159,7 +183,7 @@ describe('DynamicLayoutComponent', () => { }); it('should not display any layout when layouts are empty', async () => { - storeSpy.mockReturnValue({ ...mockStoreData, requirements: { layouts: [] } }); + store.reset({ ...storeData, ReplaceableComponentsState: {} }); spectator.detectChanges(); From e08290b1c5ac4456c21c6cb6760427d50579a0a3 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Fri, 27 Mar 2020 13:52:01 +0300 Subject: [PATCH 05/11] docs: add how to replace a layout section to component-replacement.md --- docs/en/UI/Angular/Component-Replacement.md | 53 +++++++++++++++++++-- 1 file changed, 50 insertions(+), 3 deletions(-) diff --git a/docs/en/UI/Angular/Component-Replacement.md b/docs/en/UI/Angular/Component-Replacement.md index b17c61ae73..d718b46117 100644 --- a/docs/en/UI/Angular/Component-Replacement.md +++ b/docs/en/UI/Angular/Component-Replacement.md @@ -1,10 +1,10 @@ -# Component Replacement +## Component Replacement You can replace some ABP components with your custom components. The reason that you **can replace** but **cannot customize** default ABP components is disabling or changing a part of that component can cause problems. So we named those components as _Replaceable Components_. -## How to Replace a Component +### How to Replace a Component Create a new component that you want to use instead of an ABP component. Add that component to `declarations` and `entryComponents` in the `AppModule`. @@ -29,7 +29,54 @@ export class AppComponent { ![Example Usage](./images/component-replacement.gif) -## Available Replaceable Components + +### How to Replace a Layout + +Each ABP theme module has 3 layouts named `ApplicationLayoutComponent`, `AccountLayoutComponent`, `EmptyLayoutComponent`. These layouts can be replaced with the same way. + +> A layout component template should contain `` element. + +The below example describes how to replace the `ApplicationLayoutComponent`: + +Run the following command to generate a layout in `angular` folder: + +```bash +yarn ng generate component shared/my-application-layout --export --entryComponent + +# You don't need the --entryComponent option in Angular 9 +``` + +Add the following code in your layout template (`my-layout.component.html`) where you want the page to be loaded. + +```html + +``` + +Open the `app.component.ts` and add the below content: + +```js +import { ..., AddReplaceableComponent } from '@abp/ng.core'; // imported AddReplaceableComponent +import { MyApplicationLayoutComponent } from './shared/my-application-layout/my-application-layout.component'; // imported MyApplicationLayoutComponent +import { Store } from '@ngxs/store'; // imported Store +//... +export class AppComponent { + constructor(..., private store: Store) {} // injected Store + + ngOnInit() { + // added below content + this.store.dispatch( + new AddReplaceableComponent({ + component: MyApplicationLayoutComponent, + key: 'Theme.ApplicationLayoutComponent', + }), + ); + + //... + } +} +``` + +### Available Replaceable Components | Component key | Description | | -------------------------------------------------- | --------------------------------------------- | From 0ccce0bbf999b95ff224e8c8ca78046c937bf0c5 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Fri, 27 Mar 2020 13:52:17 +0300 Subject: [PATCH 06/11] docs: fix the links --- docs/en/UI/Angular/Service-Proxies.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/en/UI/Angular/Service-Proxies.md b/docs/en/UI/Angular/Service-Proxies.md index 97b43b7513..6209350349 100644 --- a/docs/en/UI/Angular/Service-Proxies.md +++ b/docs/en/UI/Angular/Service-Proxies.md @@ -25,9 +25,9 @@ The files generated with the `--module all` option like below: ### Services -Each generated service matches a back-end controller. The services methods call back-end APIs via [RestService](./Http-Requests.md#restservice). +Each generated service matches a back-end controller. The services methods call back-end APIs via [RestService](./Http-Requests#restservice). -A variable named `apiName` (available as of v2.4) is defined in each service. `apiName` matches the module's RemoteServiceName. This variable passes to the `RestService` as a parameter at each request. If there is no microservice API defined in the environment, `RestService` uses the default. See [getting a specific API endpoint from application config](./Http-Requests.md#how-to-get-a-specific-api-endpoint-from-application-config) +A variable named `apiName` (available as of v2.4) is defined in each service. `apiName` matches the module's RemoteServiceName. This variable passes to the `RestService` as a parameter at each request. If there is no microservice API defined in the environment, `RestService` uses the default. See [getting a specific API endpoint from application config](./Http-Requests#how-to-get-a-specific-api-endpoint-from-application-config) The `providedIn` property of the services is defined as `'root'`. Therefore no need to add a service as a provider to a module. You can use a service by injecting it into a constructor as shown below: @@ -64,4 +64,4 @@ Initial values ​​can optionally be passed to each class constructor. ## What's Next? -* [HTTP Requests](./Http-Requests.md) +* [HTTP Requests](./Http-Requests) From 8d71b74281dd6fac4279970d14c47806c86e50ba Mon Sep 17 00:00:00 2001 From: Arman Ozak Date: Fri, 27 Mar 2020 14:31:09 +0300 Subject: [PATCH 07/11] style: add prettierrc and rules matching other angular projects --- templates/module/angular/.prettierrc | 5 +++ .../module/angular/src/app/app.module.ts | 42 +++++++++---------- 2 files changed, 26 insertions(+), 21 deletions(-) create mode 100644 templates/module/angular/.prettierrc diff --git a/templates/module/angular/.prettierrc b/templates/module/angular/.prettierrc new file mode 100644 index 0000000000..5e2863a11f --- /dev/null +++ b/templates/module/angular/.prettierrc @@ -0,0 +1,5 @@ +{ + "printWidth": 100, + "singleQuote": true, + "trailingComma": "all" +} diff --git a/templates/module/angular/src/app/app.module.ts b/templates/module/angular/src/app/app.module.ts index 2705a3318b..93e09321ec 100644 --- a/templates/module/angular/src/app/app.module.ts +++ b/templates/module/angular/src/app/app.module.ts @@ -1,20 +1,20 @@ -import { AccountConfigModule } from "@abp/ng.account.config"; -import { CoreModule } from "@abp/ng.core"; -import { IdentityConfigModule } from "@abp/ng.identity.config"; -import { SettingManagementConfigModule } from "@abp/ng.setting-management.config"; -import { TenantManagementConfigModule } from "@abp/ng.tenant-management.config"; -import { ThemeSharedModule } from "@abp/ng.theme.shared"; -import { NgModule } from "@angular/core"; -import { BrowserModule } from "@angular/platform-browser"; -import { BrowserAnimationsModule } from "@angular/platform-browser/animations"; -import { NgxsLoggerPluginModule } from "@ngxs/logger-plugin"; -import { NgxsModule } from "@ngxs/store"; -import { OAuthModule } from "angular-oauth2-oidc"; -import { environment } from "../environments/environment"; -import { AppRoutingModule } from "./app-routing.module"; -import { AppComponent } from "./app.component"; -import { SharedModule } from "./shared/shared.module"; -import { MyProjectNameConfigModule } from "../../projects/my-project-name-config/src/public-api"; +import { AccountConfigModule } from '@abp/ng.account.config'; +import { CoreModule } from '@abp/ng.core'; +import { IdentityConfigModule } from '@abp/ng.identity.config'; +import { SettingManagementConfigModule } from '@abp/ng.setting-management.config'; +import { TenantManagementConfigModule } from '@abp/ng.tenant-management.config'; +import { ThemeSharedModule } from '@abp/ng.theme.shared'; +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { NgxsLoggerPluginModule } from '@ngxs/logger-plugin'; +import { NgxsModule } from '@ngxs/store'; +import { OAuthModule } from 'angular-oauth2-oidc'; +import { MyProjectNameConfigModule } from '../../projects/my-project-name-config/src/public-api'; +import { environment } from '../environments/environment'; +import { AppRoutingModule } from './app-routing.module'; +import { AppComponent } from './app.component'; +import { SharedModule } from './shared/shared.module'; const LOGGERS = [NgxsLoggerPluginModule.forRoot({ disabled: false })]; @@ -23,11 +23,11 @@ const LOGGERS = [NgxsLoggerPluginModule.forRoot({ disabled: false })]; imports: [ ThemeSharedModule.forRoot(), CoreModule.forRoot({ - environment + environment, }), OAuthModule.forRoot(), NgxsModule.forRoot([]), - AccountConfigModule.forRoot({ redirectUrl: "/" }), + AccountConfigModule.forRoot({ redirectUrl: '/' }), IdentityConfigModule, TenantManagementConfigModule, SettingManagementConfigModule, @@ -37,8 +37,8 @@ const LOGGERS = [NgxsLoggerPluginModule.forRoot({ disabled: false })]; AppRoutingModule, SharedModule, - ...(environment.production ? [] : LOGGERS) + ...(environment.production ? [] : LOGGERS), ], - bootstrap: [AppComponent] + bootstrap: [AppComponent], }) export class AppModule {} From 2f7e69e1a27f2dc1732e4a55ef98d752b6f86f20 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Fri, 27 Mar 2020 15:06:07 +0300 Subject: [PATCH 08/11] refactor: reduce codes and increase readability --- .../components/dynamic-layout.component.ts | 48 +++++++------------ 1 file changed, 16 insertions(+), 32 deletions(-) diff --git a/npm/ng-packs/packages/core/src/lib/components/dynamic-layout.component.ts b/npm/ng-packs/packages/core/src/lib/components/dynamic-layout.component.ts index fc3926a1ea..e835dd777d 100644 --- a/npm/ng-packs/packages/core/src/lib/components/dynamic-layout.component.ts +++ b/npm/ng-packs/packages/core/src/lib/components/dynamic-layout.component.ts @@ -1,15 +1,13 @@ -import { Component, Input, OnDestroy, Type, Injector } from '@angular/core'; +import { Component, OnDestroy, Type } from '@angular/core'; import { ActivatedRoute, NavigationEnd, Router, UrlSegment } from '@angular/router'; -import { Select, Store } from '@ngxs/store'; -import { Observable, combineLatest } from 'rxjs'; +import { Store } from '@ngxs/store'; import snq from 'snq'; import { eLayoutType } from '../enums/common'; -import { Config } from '../models/config'; import { ABP } from '../models/common'; +import { ReplaceableComponents } from '../models/replaceable-components'; import { ConfigState } from '../states/config.state'; -import { takeUntilDestroy } from '../utils/rxjs-utils'; import { ReplaceableComponentsState } from '../states/replaceable-components.state'; -import { ReplaceableComponents } from '../models/replaceable-components'; +import { takeUntilDestroy } from '../utils/rxjs-utils'; @Component({ selector: 'abp-dynamic-layout', @@ -22,23 +20,9 @@ import { ReplaceableComponents } from '../models/replaceable-components'; `, }) export class DynamicLayoutComponent implements OnDestroy { - @Select(ReplaceableComponentsState.getComponent('Theme.ApplicationLayoutComponent')) - applicationLayout$: Observable; - - @Select(ReplaceableComponentsState.getComponent('Theme.AccountLayoutComponent')) - accountLayout$: Observable; - - @Select(ReplaceableComponentsState.getComponent('Theme.EmptyLayoutComponent')) - emptyLayout$: Observable; - layout: Type; - layouts = {} as { [key in eLayoutType]: Type }; - - expectedLayout: eLayoutType = eLayoutType.empty; - constructor(private router: Router, private route: ActivatedRoute, private store: Store) { - this.listenToLayouts(); const { routes } = this.store.selectSnapshot(ConfigState.getAll); router.events.pipe(takeUntilDestroy(this)).subscribe(event => { @@ -47,25 +31,25 @@ export class DynamicLayoutComponent implements OnDestroy { { path: router.url.replace('/', '') }, ] as any); - this.expectedLayout = + const layouts = { + application: this.getComponent('Theme.ApplicationLayoutComponent'), + account: this.getComponent('Theme.AccountLayoutComponent'), + empty: this.getComponent('Theme.EmptyApplicationLayoutComponent'), + }; + + const expectedLayout = (this.route.snapshot.data || {}).layout || findLayout(segments, routes); - this.layout = this.layouts[this.expectedLayout]; + this.layout = layouts[expectedLayout].component; } }); } - ngOnDestroy() {} - - listenToLayouts() { - combineLatest(this.applicationLayout$, this.accountLayout$, this.emptyLayout$) - .pipe(takeUntilDestroy(this)) - .subscribe(([application, account, empty]) => { - this.layouts.application = application.component; - this.layouts.account = account.component; - this.layouts.empty = empty.component; - }); + getComponent(key: string): ReplaceableComponents.ReplaceableComponent { + return this.store.selectSnapshot(ReplaceableComponentsState.getComponent(key)); } + + ngOnDestroy() {} } function findLayout(segments: UrlSegment[], routes: ABP.FullRoute[]): eLayoutType { From 91668b35f423dcca63be06f972e23a8a9e6bfb22 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Fri, 27 Mar 2020 15:14:00 +0300 Subject: [PATCH 09/11] =?UTF-8?q?refactor(core):=20make=20getComponent=20m?= =?UTF-8?q?ethod=20in=20DynamicCompo=C4=B1nent=20private?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/src/lib/components/dynamic-layout.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/npm/ng-packs/packages/core/src/lib/components/dynamic-layout.component.ts b/npm/ng-packs/packages/core/src/lib/components/dynamic-layout.component.ts index e835dd777d..71dd0f3fdf 100644 --- a/npm/ng-packs/packages/core/src/lib/components/dynamic-layout.component.ts +++ b/npm/ng-packs/packages/core/src/lib/components/dynamic-layout.component.ts @@ -45,7 +45,7 @@ export class DynamicLayoutComponent implements OnDestroy { }); } - getComponent(key: string): ReplaceableComponents.ReplaceableComponent { + private getComponent(key: string): ReplaceableComponents.ReplaceableComponent { return this.store.selectSnapshot(ReplaceableComponentsState.getComponent(key)); } From 1f2418b8721e0d991f2289bc4c57ca666de14c60 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Fri, 27 Mar 2020 15:48:37 +0300 Subject: [PATCH 10/11] fix(core): fix component key in dynamic layout --- .../core/src/lib/components/dynamic-layout.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/npm/ng-packs/packages/core/src/lib/components/dynamic-layout.component.ts b/npm/ng-packs/packages/core/src/lib/components/dynamic-layout.component.ts index 71dd0f3fdf..c07f11580f 100644 --- a/npm/ng-packs/packages/core/src/lib/components/dynamic-layout.component.ts +++ b/npm/ng-packs/packages/core/src/lib/components/dynamic-layout.component.ts @@ -34,7 +34,7 @@ export class DynamicLayoutComponent implements OnDestroy { const layouts = { application: this.getComponent('Theme.ApplicationLayoutComponent'), account: this.getComponent('Theme.AccountLayoutComponent'), - empty: this.getComponent('Theme.EmptyApplicationLayoutComponent'), + empty: this.getComponent('Theme.EmptyLayoutComponent'), }; const expectedLayout = From 6239fcd585958de01da89725d3d3cbc9b244ef5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arma=C4=9Fan=20=C3=9Cnl=C3=BC?= <36102404+armgnunlu@users.noreply.github.com> Date: Fri, 27 Mar 2020 17:40:04 +0300 Subject: [PATCH 11/11] Resolved #3238 --- .../Pages/Documents/Project/Index.cshtml | 31 +- .../Pages/Documents/Search.cshtml | 88 +++-- .../Pages/Documents/Shared/Styles/vs.css | 240 ++++++------ .../Pages/Documents/Shared/Styles/vs.min.css | 2 +- .../Pages/Documents/Shared/Styles/vs.scss | 349 ++++++++++-------- 5 files changed, 384 insertions(+), 326 deletions(-) diff --git a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml index 67e5352e22..6fcf402d70 100644 --- a/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml +++ b/modules/docs/src/Volo.Docs.Web/Pages/Documents/Project/Index.cshtml @@ -68,7 +68,7 @@ }
-