From 4aa3a8250fdb076b64c1f8cfdb962e6610681d74 Mon Sep 17 00:00:00 2001 From: Xiao Gui <xgui3783@gmail.com> Date: Thu, 18 Apr 2024 14:39:18 +0200 Subject: [PATCH] feat: added code snippet --- .helm/adhoc/certificate-sxplr-ebrains.yml | 2 +- .helm/adhoc/ingress-main.yml | 29 +++++- docs/releases/v2.14.5.md | 1 + .../sapi/codeSnippets/codeSnippet.dialog.ts | 31 +++++++ .../codeSnippets/codeSnippet.directive.ts | 88 +++++++++++++++++++ .../sapi/codeSnippets/codeSnippet.style.scss | 20 +++++ .../codeSnippets/codeSnippet.template.html | 31 +++++++ src/atlasComponents/sapi/sxplrTypes.ts | 1 + src/atlasComponents/sapi/translateV3.ts | 1 + .../sapiViews/core/region/module.ts | 2 + .../region/rich/region.rich.template.html | 26 ++++++ .../userAnnotations/tools/module.ts | 5 +- .../textareaCopyExport.component.ts | 17 +++- .../textareaCopyExport.style.css | 0 .../textareaCopyExport.template.html | 2 + .../feature-view/feature-view.component.html | 24 +++++ .../feature-view/feature-view.component.ts | 28 ++++-- src/features/guards.ts | 2 +- src/features/module.ts | 2 + src/sharedModules/angularMaterial.exports.ts | 3 +- src/util/priority.ts | 33 +++++-- 21 files changed, 324 insertions(+), 24 deletions(-) create mode 100644 src/atlasComponents/sapi/codeSnippets/codeSnippet.dialog.ts create mode 100644 src/atlasComponents/sapi/codeSnippets/codeSnippet.directive.ts create mode 100644 src/atlasComponents/sapi/codeSnippets/codeSnippet.style.scss create mode 100644 src/atlasComponents/sapi/codeSnippets/codeSnippet.template.html rename src/{atlasComponents/userAnnotations/tools => components}/textareaCopyExport/textareaCopyExport.component.ts (71%) rename src/{atlasComponents/userAnnotations/tools => components}/textareaCopyExport/textareaCopyExport.style.css (100%) rename src/{atlasComponents/userAnnotations/tools => components}/textareaCopyExport/textareaCopyExport.template.html (94%) diff --git a/.helm/adhoc/certificate-sxplr-ebrains.yml b/.helm/adhoc/certificate-sxplr-ebrains.yml index 19a96659e..6e73e4c5e 100644 --- a/.helm/adhoc/certificate-sxplr-ebrains.yml +++ b/.helm/adhoc/certificate-sxplr-ebrains.yml @@ -1,7 +1,7 @@ apiVersion: cert-manager.io/v1 kind: Certificate metadata: - name: siibra-explorer-certificate + name: siibra-explorer-ebrains-certificate spec: secretName: sxplr-ebrains-secret renewBefore: 120h diff --git a/.helm/adhoc/ingress-main.yml b/.helm/adhoc/ingress-main.yml index 3c69b3b6a..230fcf5aa 100644 --- a/.helm/adhoc/ingress-main.yml +++ b/.helm/adhoc/ingress-main.yml @@ -13,7 +13,31 @@ spec: path: "/viewer" backend: service: - name: master-siibra-explorer + name: prod-siibra-explorer + port: + number: 8080 + - pathType: Prefix + path: "/viewer-staging" + backend: + service: + name: rc-siibra-explorer + port: + number: 8080 + - pathType: Prefix + path: "/viewer-expmt" + backend: + service: + name: expmt-siibra-explorer + port: + number: 8080 + - host: siibra-explorer.apps.ebrains.eu + http: + paths: + - pathType: Prefix + path: "/viewer" + backend: + service: + name: prod-siibra-explorer port: number: 8080 - pathType: Prefix @@ -34,3 +58,6 @@ spec: - secretName: siibra-explorer-prod-secret hosts: - siibra-explorer.apps.tc.humanbrainproject.eu + - secretName: sxplr-ebrains-secret + hosts: + - siibra-explorer.apps.ebrains.eu diff --git a/docs/releases/v2.14.5.md b/docs/releases/v2.14.5.md index ec6e17c76..243ce4cf3 100644 --- a/docs/releases/v2.14.5.md +++ b/docs/releases/v2.14.5.md @@ -10,6 +10,7 @@ - Added legend to region hierarchy - Allow latest queried concept in feature view - Allow experimental flag to be set to be on at runtime (this also shows the button, allow toggling of experimental features) +- Added code snippet to limited panels - (experimental) allow addition of custom linear coordinate space - (experimental) show BigBrain slice number diff --git a/src/atlasComponents/sapi/codeSnippets/codeSnippet.dialog.ts b/src/atlasComponents/sapi/codeSnippets/codeSnippet.dialog.ts new file mode 100644 index 000000000..63c4e5c2f --- /dev/null +++ b/src/atlasComponents/sapi/codeSnippets/codeSnippet.dialog.ts @@ -0,0 +1,31 @@ +import { CommonModule } from "@angular/common"; +import { Component, Inject } from "@angular/core"; +import { TextareaCopyExportCmp } from "src/components/textareaCopyExport/textareaCopyExport.component"; +import { AngularMaterialModule, Clipboard, MAT_DIALOG_DATA } from "src/sharedModules"; + +@Component({ + templateUrl: './codeSnippet.template.html', + standalone: true, + styleUrls: [ + './codeSnippet.style.scss' + ], + imports: [ + TextareaCopyExportCmp, + AngularMaterialModule, + CommonModule, + ] +}) + +export class CodeSnippetCmp { + constructor( + @Inject(MAT_DIALOG_DATA) + public data: any, + public clipboard: Clipboard, + ){ + + } + + copy(){ + this.clipboard.copy(this.data.code) + } +} diff --git a/src/atlasComponents/sapi/codeSnippets/codeSnippet.directive.ts b/src/atlasComponents/sapi/codeSnippets/codeSnippet.directive.ts new file mode 100644 index 000000000..1967c3cdc --- /dev/null +++ b/src/atlasComponents/sapi/codeSnippets/codeSnippet.directive.ts @@ -0,0 +1,88 @@ +import { Directive, HostListener, Input } from "@angular/core"; +import { RouteParam, SapiRoute } from "../typeV3"; +import { SAPI } from "../sapi.service"; +import { BehaviorSubject, from, of } from "rxjs"; +import { switchMap, take } from "rxjs/operators"; +import { MatDialog } from "src/sharedModules" +import { CodeSnippetCmp } from "./codeSnippet.dialog"; + +type V<T extends SapiRoute> = {route: T, param: RouteParam<T>} + +@Directive({ + selector: '[code-snippet]', + standalone: true, + exportAs: "codeSnippet" +}) + +export class CodeSnippet<T extends SapiRoute>{ + + code$ = this.sapi.sapiEndpoint$.pipe( + switchMap(endpt => this.#path.pipe( + switchMap(path => { + if (!path) { + return of(null) + } + return from(this.#getCode(`${endpt}${path}`)) + }) + )), + ) + + #busy$ = new BehaviorSubject<boolean>(false) + busy$ = this.#busy$.asObservable() + + @HostListener("click") + async handleClick(){ + this.#busy$.next(true) + const code = await this.code$.pipe( + take(1) + ).toPromise() + this.#busy$.next(false) + this.matDialog.open(CodeSnippetCmp, { + data: { code } + }) + } + + @Input() + set routeParam(value: V<T>|null|undefined){ + if (!value) { + return + } + const { param, route } = value + const { params, path } = this.sapi.v3GetRoute(route, param) + + let url = encodeURI(path) + const queryParam = new URLSearchParams() + for (const key in params) { + queryParam.set(key, params[key].toString()) + } + const result = `${url}?${queryParam.toString()}` + this.#path.next(result) + } + + @Input() + set path(value: string) { + this.#path.next(value) + } + #path = new BehaviorSubject<string>(null) + + constructor(private sapi: SAPI, private matDialog: MatDialog){} + + async #getCode(url: string): Promise<string> { + try { + const resp = await fetch(url, { + headers: { + Accept: `text/x-sapi-python` + } + }) + if (!resp.ok){ + console.warn(`${url} returned not ok`) + return null + } + const result = await resp.text() + return result + } catch (e) { + console.warn(`Error: ${e}`) + return null + } + } +} diff --git a/src/atlasComponents/sapi/codeSnippets/codeSnippet.style.scss b/src/atlasComponents/sapi/codeSnippets/codeSnippet.style.scss new file mode 100644 index 000000000..2a159cdfc --- /dev/null +++ b/src/atlasComponents/sapi/codeSnippets/codeSnippet.style.scss @@ -0,0 +1,20 @@ +.textarea +{ + width: 75vw; + +} + +textarea-copy-export +{ + display: block; + width: 75vw; + + ::ng-deep mat-form-field { + width: 100%; + + textarea + { + resize: none; + } + } +} diff --git a/src/atlasComponents/sapi/codeSnippets/codeSnippet.template.html b/src/atlasComponents/sapi/codeSnippets/codeSnippet.template.html new file mode 100644 index 000000000..0dbf045b3 --- /dev/null +++ b/src/atlasComponents/sapi/codeSnippets/codeSnippet.template.html @@ -0,0 +1,31 @@ +<mat-card class="sxplr-custom-cmp text"> + <mat-card-header> + <mat-card-title> + Code snippet + </mat-card-title> + </mat-card-header> + <mat-card-content> + <textarea-copy-export + textarea-copy-export-label="python" + [textarea-copy-export-text]="data.code" + textarea-copy-export-download-filename="export.py" + [textarea-copy-export-disable]="true" + [textarea-copy-show-suffixes]="false" + [textarea-copy-export-rows]="10" + #textAreaCopyExport="textAreaCopyExport"> + + </textarea-copy-export> + </mat-card-content> + + <mat-card-actions> + <button mat-raised-button + color="primary" + (click)="textAreaCopyExport.copyToClipboard(data.code)"> + <mat-icon fontSet="fas" fontIcon="fa-copy"></mat-icon> + <span>copy</span> + </button> + <button mat-button mat-dialog-close> + <span>close</span> + </button> + </mat-card-actions> +</mat-card> diff --git a/src/atlasComponents/sapi/sxplrTypes.ts b/src/atlasComponents/sapi/sxplrTypes.ts index 11d685807..331767f01 100644 --- a/src/atlasComponents/sapi/sxplrTypes.ts +++ b/src/atlasComponents/sapi/sxplrTypes.ts @@ -103,6 +103,7 @@ export type SimpleCompoundFeature<T extends string|Point=string|Point> = { name: string category?: string indices: { + category?: string id: string index: T name: string diff --git a/src/atlasComponents/sapi/translateV3.ts b/src/atlasComponents/sapi/translateV3.ts index a2abb1375..03659664a 100644 --- a/src/atlasComponents/sapi/translateV3.ts +++ b/src/atlasComponents/sapi/translateV3.ts @@ -649,6 +649,7 @@ class TranslateV3 { id, index: await this.#transformIndex(index), name, + category: feat.category }) ) ), diff --git a/src/atlasComponents/sapiViews/core/region/module.ts b/src/atlasComponents/sapiViews/core/region/module.ts index e72f1b154..8bb8f8bf7 100644 --- a/src/atlasComponents/sapiViews/core/region/module.ts +++ b/src/atlasComponents/sapiViews/core/region/module.ts @@ -15,6 +15,7 @@ import { SapiViewsCoreParcellationModule } from "../parcellation"; import { TranslateQualificationPipe } from "./translateQualification.pipe"; import { DedupRelatedRegionPipe } from "./dedupRelatedRegion.pipe"; import { ExperimentalFlagDirective } from "src/experimental/experimental-flag.directive"; +import { CodeSnippet } from "src/atlasComponents/sapi/codeSnippets/codeSnippet.directive"; @NgModule({ imports: [ @@ -30,6 +31,7 @@ import { ExperimentalFlagDirective } from "src/experimental/experimental-flag.di SapiViewsCoreParcellationModule, ExperimentalFlagDirective, + CodeSnippet, ], declarations: [ SapiViewsCoreRegionRegionListItem, diff --git a/src/atlasComponents/sapiViews/core/region/region/rich/region.rich.template.html b/src/atlasComponents/sapiViews/core/region/region/rich/region.rich.template.html index 25a7643b6..33e467679 100644 --- a/src/atlasComponents/sapiViews/core/region/region/rich/region.rich.template.html +++ b/src/atlasComponents/sapiViews/core/region/region/rich/region.rich.template.html @@ -37,6 +37,32 @@ <mat-tab label="Overview"> <mat-action-list class="overview-container"> + + <button mat-list-item + code-snippet + [routeParam]="{ + route: '/regions/{region_id}', + param: { + path: { + region_id: region.name + }, + query: { + parcellation_id: parcellation.id + } + } + }" + #codeSnippet="codeSnippet" + [disabled]="codeSnippet.busy$ | async"> + <mat-icon matListItemIcon fontSet="fas" fontIcon="fa-code"></mat-icon> + <div matListItemTitle> + <ng-template [ngIf]="codeSnippet.busy$ | async"> + loading code ... + </ng-template> + <ng-template [ngIf]="!(codeSnippet.busy$ | async)"> + code + </ng-template> + </div> + </button> <!-- parcellation button --> <button diff --git a/src/atlasComponents/userAnnotations/tools/module.ts b/src/atlasComponents/userAnnotations/tools/module.ts index 31c675db2..8085478cc 100644 --- a/src/atlasComponents/userAnnotations/tools/module.ts +++ b/src/atlasComponents/userAnnotations/tools/module.ts @@ -15,7 +15,7 @@ import { ToolSelect } from "./select"; import { ToolDelete } from "./delete"; import { Polygon, ToolPolygon } from "./poly"; import { ZipFilesOutputModule } from "src/zipFilesOutput/module"; -import { TextareaCopyExportCmp } from "./textareaCopyExport/textareaCopyExport.component"; +import { TextareaCopyExportCmp } from "src/components/textareaCopyExport/textareaCopyExport.component"; @NgModule({ imports: [ @@ -23,13 +23,14 @@ import { TextareaCopyExportCmp } from "./textareaCopyExport/textareaCopyExport.c AngularMaterialModule, UtilModule, ZipFilesOutputModule, + + TextareaCopyExportCmp, ], declarations: [ LineUpdateCmp, PolyUpdateCmp, PointUpdateCmp, ToFormattedStringPipe, - TextareaCopyExportCmp, ], exports: [ LineUpdateCmp, diff --git a/src/atlasComponents/userAnnotations/tools/textareaCopyExport/textareaCopyExport.component.ts b/src/components/textareaCopyExport/textareaCopyExport.component.ts similarity index 71% rename from src/atlasComponents/userAnnotations/tools/textareaCopyExport/textareaCopyExport.component.ts rename to src/components/textareaCopyExport/textareaCopyExport.component.ts index f749e39b4..b9482ce1f 100644 --- a/src/atlasComponents/userAnnotations/tools/textareaCopyExport/textareaCopyExport.component.ts +++ b/src/components/textareaCopyExport/textareaCopyExport.component.ts @@ -2,13 +2,23 @@ import { Component, Input } from "@angular/core"; import { MatSnackBar } from 'src/sharedModules/angularMaterial.exports' import { ARIA_LABELS } from 'common/constants' import { Clipboard } from "@angular/cdk/clipboard"; +import { AngularMaterialModule } from "src/sharedModules"; +import { CommonModule } from "@angular/common"; +import { ZipFilesOutputModule } from "src/zipFilesOutput/module"; @Component({ selector: 'textarea-copy-export', templateUrl: './textareaCopyExport.template.html', styleUrls: [ './textareaCopyExport.style.css' - ] + ], + standalone: true, + imports: [ + AngularMaterialModule, + CommonModule, + ZipFilesOutputModule, + ], + exportAs: "textAreaCopyExport" }) export class TextareaCopyExportCmp { @@ -31,6 +41,9 @@ export class TextareaCopyExportCmp { @Input('textarea-copy-export-disable') disableFlag: boolean = false + + @Input('textarea-copy-show-suffixes') + showSuffix: boolean = true public ARIA_LABELS = ARIA_LABELS @@ -42,7 +55,7 @@ export class TextareaCopyExportCmp { } copyToClipboard(value: string){ - const success = this.clipboard.copy(`${value}`) + const success = this.clipboard.copy(value) this.snackbar.open( success ? `Copied to clipboard!` : `Failed to copy URL to clipboard!`, null, diff --git a/src/atlasComponents/userAnnotations/tools/textareaCopyExport/textareaCopyExport.style.css b/src/components/textareaCopyExport/textareaCopyExport.style.css similarity index 100% rename from src/atlasComponents/userAnnotations/tools/textareaCopyExport/textareaCopyExport.style.css rename to src/components/textareaCopyExport/textareaCopyExport.style.css diff --git a/src/atlasComponents/userAnnotations/tools/textareaCopyExport/textareaCopyExport.template.html b/src/components/textareaCopyExport/textareaCopyExport.template.html similarity index 94% rename from src/atlasComponents/userAnnotations/tools/textareaCopyExport/textareaCopyExport.template.html rename to src/components/textareaCopyExport/textareaCopyExport.template.html index 65fe0d112..7e023d9af 100644 --- a/src/atlasComponents/userAnnotations/tools/textareaCopyExport/textareaCopyExport.template.html +++ b/src/components/textareaCopyExport/textareaCopyExport.template.html @@ -10,6 +10,7 @@ #exportTarget>{{ input }}</textarea> <button mat-icon-button + *ngIf="showSuffix" matSuffix iav-stop="click" aria-label="Copy to clipboard" @@ -18,6 +19,7 @@ <i class="fas fa-copy"></i> </button> <button mat-icon-button + *ngIf="showSuffix" matSuffix iav-stop="click" [matTooltip]="ARIA_LABELS.USER_ANNOTATION_EXPORT_SINGLE" diff --git a/src/features/feature-view/feature-view.component.html b/src/features/feature-view/feature-view.component.html index 05bffb881..eea4f1017 100644 --- a/src/features/feature-view/feature-view.component.html +++ b/src/features/feature-view/feature-view.component.html @@ -63,6 +63,30 @@ </button> </ng-template> + <!-- code --> + <button mat-list-item + code-snippet + [routeParam]="{ + route: '/feature/{feature_id}', + param: { + path: { + feature_id: view.featureId + } + } + }" + #codeSnippet="codeSnippet" + [disabled]="codeSnippet.busy$ | async"> + <mat-icon matListItemIcon fontSet="fas" fontIcon="fa-code"></mat-icon> + <div matListItemTitle> + <ng-template [ngIf]="codeSnippet.busy$ | async"> + loading code ... + </ng-template> + <ng-template [ngIf]="!(codeSnippet.busy$ | async)"> + code + </ng-template> + </div> + </button> + <!-- anchor --> <ng-template [ngIf]="view.concept"> <button mat-list-item diff --git a/src/features/feature-view/feature-view.component.ts b/src/features/feature-view/feature-view.component.ts index f95b096cd..bbcbfb28b 100644 --- a/src/features/feature-view/feature-view.component.ts +++ b/src/features/feature-view/feature-view.component.ts @@ -51,17 +51,26 @@ export class FeatureViewComponent { map(f => f.id) ) - #featureDetail$ = this.#feature$.pipe( - switchMap(f => this.sapi.getV3FeatureDetailWithId(f.id)), - shareReplay(1), + #featureDetail$ = this.#featureId.pipe( + switchMap(fid => this.sapi.getV3FeatureDetailWithId(fid)), ) - #featureDesc$ = this.#feature$.pipe( switchMap(() => concat( of(null as string), this.#featureDetail$.pipe( - map(v => v.desc) + map(v => v?.desc), + catchError((err) => { + let errortext = 'Error fetching feature instance' + + if (err.error instanceof Error) { + errortext += `:\n\n${err.error.toString()}` + } else { + errortext += '!' + } + + return of(errortext) + }), ) )) ) @@ -70,6 +79,7 @@ export class FeatureViewComponent { switchMap(() => concat( of(null), this.#featureDetail$.pipe( + catchError(() => of(null)), map(val => { if (isVoiData(val)) { return val @@ -84,7 +94,8 @@ export class FeatureViewComponent { switchMap(() => concat( of([] as string[]), this.#featureDetail$.pipe( - map(notQuiteRight) + catchError(() => of(null)), + map(notQuiteRight), ) )) ) @@ -118,6 +129,7 @@ export class FeatureViewComponent { switchMap(() => concat( of(true), this.#featureDetail$.pipe( + catchError(() => of(null)), map(() => false) ) )) @@ -157,7 +169,8 @@ export class FeatureViewComponent { switchMap(() => concat( of([] as string[]), this.#featureDetail$.pipe( - map(val => (val.link || []).map(l => l.href)) + catchError(() => of(null as null)), + map(val => (val?.link || []).map(l => l.href)) ) )) ) @@ -292,6 +305,7 @@ export class FeatureViewComponent { ]).pipe( map(([ feature, busy, warnings, additionalLinks, downloadLink, desc ]) => { return { + featureId: feature.id, name: feature.name, links: feature.link, category: feature.category === 'Unknown category' diff --git a/src/features/guards.ts b/src/features/guards.ts index 426d94acf..6d13d4514 100644 --- a/src/features/guards.ts +++ b/src/features/guards.ts @@ -3,7 +3,7 @@ import { VoiFeature } from "src/atlasComponents/sapi/sxplrTypes" export { VoiFeature } export function isVoiData(feature: unknown): feature is VoiFeature { - return !!feature['bbox'] + return !!(feature?.['bbox']) } export function notQuiteRight(_feature: unknown): string[] { diff --git a/src/features/module.ts b/src/features/module.ts index e23945532..fc440770b 100644 --- a/src/features/module.ts +++ b/src/features/module.ts @@ -24,6 +24,7 @@ import { FEATURE_CONCEPT_TOKEN, FeatureConcept, TPRB } from "./util"; import { BehaviorSubject } from "rxjs"; import { TPBRViewCmp } from "./TPBRView/TPBRView.component"; import { DialogModule } from "src/ui/dialogInfo"; +import { CodeSnippet } from "src/atlasComponents/sapi/codeSnippets/codeSnippet.directive"; @NgModule({ imports: [ @@ -44,6 +45,7 @@ import { DialogModule } from "src/ui/dialogInfo"; PlotlyComponent, AtlasColorMapIntents, TPBRViewCmp, + CodeSnippet, ], declarations: [ EntryComponent, diff --git a/src/sharedModules/angularMaterial.exports.ts b/src/sharedModules/angularMaterial.exports.ts index 4c83edd64..3e3b99556 100644 --- a/src/sharedModules/angularMaterial.exports.ts +++ b/src/sharedModules/angularMaterial.exports.ts @@ -1,8 +1,7 @@ export { MatTab, MatTabGroup } from "@angular/material/tabs"; export { ErrorStateMatcher } from "@angular/material/core"; -export { MatDialogConfig, MatDialog, MatDialogRef } from "@angular/material/dialog"; +export { MAT_DIALOG_DATA, MatDialogConfig, MatDialog, MatDialogRef } from "@angular/material/dialog"; export { MatSnackBar, MatSnackBarRef, SimpleSnackBar, MatSnackBarConfig } from "@angular/material/snack-bar"; -export { MAT_DIALOG_DATA } from "@angular/material/dialog"; export { MatBottomSheet, MatBottomSheetRef, MatBottomSheetConfig } from "@angular/material/bottom-sheet"; export { MatSlideToggle, MatSlideToggleChange } from "@angular/material/slide-toggle" export { MatTableDataSource } from "@angular/material/table" diff --git a/src/util/priority.ts b/src/util/priority.ts index 2dcd8a28b..03e99d3b5 100644 --- a/src/util/priority.ts +++ b/src/util/priority.ts @@ -27,12 +27,26 @@ type Queue = { }) export class PriorityHttpInterceptor implements HttpInterceptor{ + static ErrorToString(err: HttpErrorResponse){ + if (err.status === 504) { + return "Gateway Timeout" + } + if (!!err.error.message) { + try { + const { detail } = JSON.parse(err.error.message) + return detail as string + } catch (e) { + return err.error.message as string + } + } + return err.statusText || err.status.toString() + } private retry = 0 private priorityQueue: Queue[] = [] private currentJob: Set<string> = new Set() - private archive: Map<string, (HttpErrorResponse|HttpResponse<unknown>|Error)> = new Map() + private archive: Map<string, (HttpResponse<unknown>|Error)> = new Map() private queue$: Subject<Queue> = new Subject() private result$: Subject<Result<unknown>> = new Subject() private error$: Subject<ErrorResult> = new Subject() @@ -95,11 +109,13 @@ export class PriorityHttpInterceptor implements HttpInterceptor{ }) } if (val instanceof HttpErrorResponse) { - - this.archive.set(urlWithParams, val) + const error = new Error( + PriorityHttpInterceptor.ErrorToString(val) + ) + this.archive.set(urlWithParams, error) this.error$.next({ urlWithParams, - error: new Error(val.toString()), + error, status: val.status }) } @@ -136,10 +152,11 @@ export class PriorityHttpInterceptor implements HttpInterceptor{ const archive = this.archive.get(urlWithParams) if (archive) { if (archive instanceof Error) { - return throwError(archive) - } - if (archive instanceof HttpErrorResponse) { - return throwError(archive) + return throwError({ + urlWithParams, + error: archive, + status: 400 + }) } if (archive instanceof HttpResponse) { return of( archive.clone() ) -- GitLab