diff --git a/docs/en/UI/Angular/HTTP-Requests.md b/docs/en/UI/Angular/HTTP-Requests.md index 57a058ef36..a0e53df9c9 100644 --- a/docs/en/UI/Angular/HTTP-Requests.md +++ b/docs/en/UI/Angular/HTTP-Requests.md @@ -298,3 +298,15 @@ export function handleHttpErrors(injector: Injector, httpError: HttpErrorRespons return throwError(httpError) } ``` + + +### How to Skip HTTP interceptors and ABP headers + +The ABP Framework adds several HTTP headers to the HttpClient, such as the "Auth token" or "tenant Id". +The ABP Server must possess the information but the ABP user may not want to send this informations to an external server. +ExternalHttpClient and IS EXTERNAL REQUEST HttpContext Token were added in V6.0.4. +The ABP Http interceptors check the value of the `IS_EXTERNAL_REQUEST` token. If the token is True then ABP-specific headers won't be added to Http Request. +The `ExternalHttpClient` extends from `HTTPClient` and sets the `IS_EXTERNAL_REQUEST` context token to true. +When you are using `ExternalHttpClient` as HttpClient in your components, it does not add ABP-specific headers. + +Note: With `IS_EXTERNAL_REQUEST` or without it, ABP loading service works. diff --git a/docs/en/UI/Angular/Modal.md b/docs/en/UI/Angular/Modal.md index 144f38e842..903e98f1fd 100644 --- a/docs/en/UI/Angular/Modal.md +++ b/docs/en/UI/Angular/Modal.md @@ -57,7 +57,7 @@ You can add the `abp-modal` to your component very quickly. See an example: @Component(/* component metadata */) export class SampleComponent { - isModelOpen = false + isModalOpen = false } ``` diff --git a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/AngularSourceCodeAdder.cs b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/AngularSourceCodeAdder.cs index c8d3aeb75b..74a45ba7e1 100644 --- a/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/AngularSourceCodeAdder.cs +++ b/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/AngularSourceCodeAdder.cs @@ -267,11 +267,11 @@ public class AngularSourceCodeAdder : ITransientDependency var fileContent = File.ReadAllText(filePath); - fileContent = "import { "+moduleName.Split(".").Last()+"Module } from '@"+moduleName.Split(".").Last().ToKebabCase()+"/config';" + Environment.NewLine + fileContent; + fileContent = "import { "+moduleName.Split(".").Last()+"ConfigModule } from '@"+moduleName.Split(".").Last().ToKebabCase()+"/config';" + Environment.NewLine + fileContent; fileContent = Regex.Replace(fileContent, "imports\\s*:\\s*\\[", "imports: ["+ Environment.NewLine + - " " + moduleName.Split(".").Last() + "Module.forRoot(),"); + " " + moduleName.Split(".").Last() + "ConfigModule.forRoot(),"); File.WriteAllText(filePath, fileContent); } diff --git a/npm/ng-packs/packages/core/src/lib/clients/http.client.ts b/npm/ng-packs/packages/core/src/lib/clients/http.client.ts new file mode 100644 index 0000000000..c6e9017be7 --- /dev/null +++ b/npm/ng-packs/packages/core/src/lib/clients/http.client.ts @@ -0,0 +1,30 @@ +import { HttpClient, HttpContext, HttpRequest } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; +import { IS_EXTERNAL_REQUEST } from '../tokens/http-context.token'; + +// source : https://github.com/armanozak/demo-angular-server-specific-interceptors +@Injectable({ + providedIn: 'root', +}) +export class ExternalHttpClient extends HttpClient { + override request( + first: string | HttpRequest, + url?: string, + options: RequestOptions = {}, + ): Observable { + if (typeof first === 'string') { + this.#setPlaceholderContext(options); + return super.request(first, url, options); + } + + this.#setPlaceholderContext(first); + return super.request(first); + } + #setPlaceholderContext(optionsOrRequest: { context?: HttpContext }) { + optionsOrRequest.context ??= new HttpContext(); + optionsOrRequest.context.set(IS_EXTERNAL_REQUEST, true); + } +} + +type RequestOptions = Parameters[2]; diff --git a/npm/ng-packs/packages/core/src/lib/clients/index.ts b/npm/ng-packs/packages/core/src/lib/clients/index.ts new file mode 100644 index 0000000000..c9aba4d030 --- /dev/null +++ b/npm/ng-packs/packages/core/src/lib/clients/index.ts @@ -0,0 +1 @@ +export * from './http.client'; diff --git a/npm/ng-packs/packages/core/src/lib/providers/include-localization-resources.provider.ts b/npm/ng-packs/packages/core/src/lib/providers/include-localization-resources.provider.ts index f530f72cb1..344dced803 100644 --- a/npm/ng-packs/packages/core/src/lib/providers/include-localization-resources.provider.ts +++ b/npm/ng-packs/packages/core/src/lib/providers/include-localization-resources.provider.ts @@ -1,8 +1,7 @@ - import { Provider } from "@angular/core"; - import { INCUDE_LOCALIZATION_RESOURCES_TOKEN } from "../tokens/include-localization-resources.token"; +import { Provider } from '@angular/core'; +import { INCUDE_LOCALIZATION_RESOURCES_TOKEN } from '../tokens/include-localization-resources.token'; export const IncludeLocalizationResourcesProvider: Provider = { - provide: INCUDE_LOCALIZATION_RESOURCES_TOKEN, - useValue: false, - }; - \ No newline at end of file + provide: INCUDE_LOCALIZATION_RESOURCES_TOKEN, + useValue: false, +}; diff --git a/npm/ng-packs/packages/core/src/lib/providers/index.ts b/npm/ng-packs/packages/core/src/lib/providers/index.ts index 8a9f61bda5..4ae2d22a1a 100644 --- a/npm/ng-packs/packages/core/src/lib/providers/index.ts +++ b/npm/ng-packs/packages/core/src/lib/providers/index.ts @@ -1,3 +1,3 @@ export * from './cookie-language.provider'; export * from './locale.provider'; -export * from './include-localization-resources.provider'; \ No newline at end of file +export * from './include-localization-resources.provider'; diff --git a/npm/ng-packs/packages/core/src/lib/tokens/http-context.token.ts b/npm/ng-packs/packages/core/src/lib/tokens/http-context.token.ts new file mode 100644 index 0000000000..e935232b08 --- /dev/null +++ b/npm/ng-packs/packages/core/src/lib/tokens/http-context.token.ts @@ -0,0 +1,3 @@ +import { HttpContextToken } from '@angular/common/http'; + +export const IS_EXTERNAL_REQUEST = new HttpContextToken(() => false); diff --git a/npm/ng-packs/packages/core/src/lib/tokens/include-localization-resources.token.ts b/npm/ng-packs/packages/core/src/lib/tokens/include-localization-resources.token.ts index ac805a8ee8..4c5495ad12 100644 --- a/npm/ng-packs/packages/core/src/lib/tokens/include-localization-resources.token.ts +++ b/npm/ng-packs/packages/core/src/lib/tokens/include-localization-resources.token.ts @@ -1,3 +1,5 @@ -import { InjectionToken } from "@angular/core"; +import { InjectionToken } from '@angular/core'; -export const INCUDE_LOCALIZATION_RESOURCES_TOKEN = new InjectionToken('INCUDE_LOCALIZATION_RESOURCES_TOKEN'); +export const INCUDE_LOCALIZATION_RESOURCES_TOKEN = new InjectionToken( + 'INCUDE_LOCALIZATION_RESOURCES_TOKEN', +); diff --git a/npm/ng-packs/packages/core/src/lib/tokens/index.ts b/npm/ng-packs/packages/core/src/lib/tokens/index.ts index b9d724f9f6..f0e724259a 100644 --- a/npm/ng-packs/packages/core/src/lib/tokens/index.ts +++ b/npm/ng-packs/packages/core/src/lib/tokens/index.ts @@ -11,3 +11,4 @@ export * from './include-localization-resources.token'; export * from './pipe-to-login.token'; export * from './set-token-response-to-storage.token'; export * from './check-authentication-state'; +export * from './http-context.token'; diff --git a/npm/ng-packs/packages/core/src/public-api.ts b/npm/ng-packs/packages/core/src/public-api.ts index da5fccd8c0..c7b56ac41c 100644 --- a/npm/ng-packs/packages/core/src/public-api.ts +++ b/npm/ng-packs/packages/core/src/public-api.ts @@ -23,3 +23,4 @@ export * from './lib/tokens'; export * from './lib/utils'; export * from './lib/validators'; export * from './lib/interceptors'; +export * from './lib/clients'; diff --git a/npm/ng-packs/packages/feature-management/proxy/src/lib/proxy/feature-management/features.service.ts b/npm/ng-packs/packages/feature-management/proxy/src/lib/proxy/feature-management/features.service.ts index 490089fbbd..189076428d 100644 --- a/npm/ng-packs/packages/feature-management/proxy/src/lib/proxy/feature-management/features.service.ts +++ b/npm/ng-packs/packages/feature-management/proxy/src/lib/proxy/feature-management/features.service.ts @@ -7,34 +7,37 @@ import { Injectable } from '@angular/core'; }) export class FeaturesService { apiName = 'AbpFeatureManagement'; - delete = (providerName: string, providerKey: string) => - this.restService.request({ - method: 'DELETE', - url: '/api/feature-management/features', - params: { providerName, providerKey }, - }, - { apiName: this.apiName }); - + this.restService.request( + { + method: 'DELETE', + url: '/api/feature-management/features', + params: { providerName, providerKey }, + }, + { apiName: this.apiName }, + ); get = (providerName: string, providerKey: string) => - this.restService.request({ - method: 'GET', - url: '/api/feature-management/features', - params: { providerName, providerKey }, - }, - { apiName: this.apiName }); - + this.restService.request( + { + method: 'GET', + url: '/api/feature-management/features', + params: { providerName, providerKey }, + }, + { apiName: this.apiName }, + ); update = (providerName: string, providerKey: string, input: UpdateFeaturesDto) => - this.restService.request({ - method: 'PUT', - url: '/api/feature-management/features', - params: { providerName, providerKey }, - body: input, - }, - { apiName: this.apiName }); + this.restService.request( + { + method: 'PUT', + url: '/api/feature-management/features', + params: { providerName, providerKey }, + body: input, + }, + { apiName: this.apiName }, + ); constructor(private restService: RestService) {} } diff --git a/npm/ng-packs/packages/oauth/src/lib/interceptors/api.interceptor.ts b/npm/ng-packs/packages/oauth/src/lib/interceptors/api.interceptor.ts index e807133c0d..f36f966559 100644 --- a/npm/ng-packs/packages/oauth/src/lib/interceptors/api.interceptor.ts +++ b/npm/ng-packs/packages/oauth/src/lib/interceptors/api.interceptor.ts @@ -2,7 +2,13 @@ import { HttpHandler, HttpHeaders, HttpRequest } from '@angular/common/http'; import { Inject, Injectable } from '@angular/core'; import { OAuthService } from 'angular-oauth2-oidc'; import { finalize } from 'rxjs/operators'; -import { SessionStateService, HttpWaitService, TENANT_KEY, IApiInterceptor } from '@abp/ng.core'; +import { + SessionStateService, + HttpWaitService, + TENANT_KEY, + IApiInterceptor, + IS_EXTERNAL_REQUEST, +} from '@abp/ng.core'; @Injectable({ providedIn: 'root', @@ -17,12 +23,15 @@ export class OAuthApiInterceptor implements IApiInterceptor { intercept(request: HttpRequest, next: HttpHandler) { this.httpWaitService.addRequest(request); - return next - .handle( - request.clone({ + const isExternalRequest = request.context?.get(IS_EXTERNAL_REQUEST); + const newRequest = isExternalRequest + ? request + : request.clone({ setHeaders: this.getAdditionalHeaders(request.headers), - }), - ) + }); + + return next + .handle(newRequest) .pipe(finalize(() => this.httpWaitService.deleteRequest(request))); } diff --git a/npm/ng-packs/packages/permission-management/src/lib/components/permission-management.component.ts b/npm/ng-packs/packages/permission-management/src/lib/components/permission-management.component.ts index 35380fe47c..44cc372f32 100644 --- a/npm/ng-packs/packages/permission-management/src/lib/components/permission-management.component.ts +++ b/npm/ng-packs/packages/permission-management/src/lib/components/permission-management.component.ts @@ -1,13 +1,13 @@ -import { ConfigStateService, CurrentUserDto } from "@abp/ng.core"; +import { ConfigStateService, CurrentUserDto } from '@abp/ng.core'; import { GetPermissionListResultDto, PermissionGrantInfoDto, PermissionGroupDto, PermissionsService, ProviderInfoDto, - UpdatePermissionDto -} from "@abp/ng.permission-management/proxy"; -import { LocaleDirection } from "@abp/ng.theme.shared"; + UpdatePermissionDto, +} from '@abp/ng.permission-management/proxy'; +import { LocaleDirection } from '@abp/ng.theme.shared'; import { Component, ElementRef, @@ -16,11 +16,11 @@ import { Output, QueryList, TrackByFunction, - ViewChildren -} from "@angular/core"; -import { concat, of } from "rxjs"; -import { finalize, switchMap, take, tap } from "rxjs/operators"; -import { PermissionManagement } from "../models/permission-management"; + ViewChildren, +} from '@angular/core'; +import { concat, of } from 'rxjs'; +import { finalize, switchMap, take, tap } from 'rxjs/operators'; +import { PermissionManagement } from '../models/permission-management'; type PermissionWithStyle = PermissionGrantInfoDto & { style: string; diff --git a/npm/ng-packs/packages/schematics/src/commands/create-lib/index.ts b/npm/ng-packs/packages/schematics/src/commands/create-lib/index.ts index 2b92336c0e..4b5408311b 100644 --- a/npm/ng-packs/packages/schematics/src/commands/create-lib/index.ts +++ b/npm/ng-packs/packages/schematics/src/commands/create-lib/index.ts @@ -246,4 +246,3 @@ export function addRoutingToAppRoutingModule(workspace: WorkspaceDefinition, pac return; }; } - diff --git a/npm/ng-packs/packages/schematics/src/models/model.ts b/npm/ng-packs/packages/schematics/src/models/model.ts index 048c08a1b0..142d4da75c 100644 --- a/npm/ng-packs/packages/schematics/src/models/model.ts +++ b/npm/ng-packs/packages/schematics/src/models/model.ts @@ -45,9 +45,13 @@ abstract class TypeRef { get default() { return this._default; } - set default(value: string) { + set default(value: any) { if (!value) return; - this._default = ` = ${value}`; + if (typeof value === 'string') { + this._default = ` = "${value}"`; + } else { + this._default = ` = ${value}`; + } } constructor(options: TypeRefOptions) { diff --git a/npm/ng-packs/packages/schematics/src/utils/angular/generate-from-files.ts b/npm/ng-packs/packages/schematics/src/utils/angular/generate-from-files.ts index eaf8febb54..169c6c389a 100644 --- a/npm/ng-packs/packages/schematics/src/utils/angular/generate-from-files.ts +++ b/npm/ng-packs/packages/schematics/src/utils/angular/generate-from-files.ts @@ -48,7 +48,7 @@ export function generateFromFiles( validateClassName(strings.classify(options.name)); const templateSource = apply(url('./files'), [ - options.skipTests ? filter((path) => !path.endsWith('.spec.ts.template')) : noop(), + options.skipTests ? filter(path => !path.endsWith('.spec.ts.template')) : noop(), applyTemplates({ ...strings, ...options,