Fix URL encoding issue for links (#446)

* Use [routerLink] with array instead of routerLink with interpolated string

* switch navigateByUrl to navigate with array format

* add some quick tests
This commit is contained in:
Jean Fernandez 2024-03-07 18:17:40 -05:00 committed by GitHub
parent c487c9fe25
commit 43579df659
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
26 changed files with 67 additions and 43 deletions

View File

@ -23,7 +23,7 @@
<fhir-coding *ngFor="let coding of rowItem.data" [coding]="coding"></fhir-coding>
</ng-template>
<ng-template #dataTypeReference>
<a routerLink="/explore/{{displayModel.source_id}}/resource/{{rowItem.data.reference}}">{{rowItem.data.display}}</a>
<a [routerLink]="['/explore', displayModel.source_id, 'resource', rowItem.data.reference]">{{rowItem.data.display}}</a>
</ng-template>
<ng-template #dataTypeString>{{rowItem.data}}</ng-template>
</td>

View File

@ -1,6 +1,9 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { TableComponent } from './table.component';
import { TableRowItemDataType } from './table-row-item';
import { RouterTestingModule } from '@angular/router/testing';
import { FastenDisplayModel } from 'src/lib/models/fasten/fasten-display-model';
describe('TableComponent', () => {
let component: TableComponent;
@ -8,16 +11,39 @@ describe('TableComponent', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [ TableComponent ]
imports: [ TableComponent, RouterTestingModule ]
})
.compileComponents();
fixture = TestBed.createComponent(TableComponent);
component = fixture.componentInstance;
component.displayModel = {
source_id: '123-456-789=',
} as FastenDisplayModel,
component.tableData = [
{
enabled: true,
label: 'hello',
data_type: TableRowItemDataType.Reference,
data: {
reference: 'aHR0cHM6Ly93d3cubWVyY3kubmV0L3NpdGVzL2RlZmF1bHQvZmlsZXMvZG9jdG9yX2ltYWdlcy9kZXNrdG9wLzE2NTk4ODYwNTktbS5qcGc=',
display: 'binary'
}
}
]
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('encodes urls properly', () => {
spyOn(console, 'log').and.callThrough();
const link = fixture.debugElement.nativeElement.querySelector('a');
console.log(link);
expect(link.href).toContain(
'/explore/123-456-789%3D/resource/aHR0cHM6Ly93d3cubWVyY3kubmV0L3NpdGVzL2RlZmF1bHQvZmlsZXMvZG9jdG9yX2ltYWdlcy9kZXNrdG9wLzE2NTk4ODYwNTktbS5qcGc%3D'
);
});
});

View File

@ -1,19 +1,17 @@
import type { Meta, StoryObj } from '@storybook/angular';
import { moduleMetadata, type Meta, type StoryObj } from '@storybook/angular';
import {TableComponent} from "./table.component";
import {TableRowItem} from "./table-row-item";
import {FastenDisplayModel} from "../../../../../lib/models/fasten/fasten-display-model";
import { RouterTestingModule } from '@angular/router/testing';
// More on how to set up stories at: https://storybook.js.org/docs/angular/writing-stories/introduction
const meta: Meta<TableComponent> = {
title: 'Fhir Card/Common/Table',
component: TableComponent,
decorators: [
// moduleMetadata({
// imports: [AppModule]
// })
// applicationConfig({
// providers: [importProvidersFrom(AppModule)],
// }),
moduleMetadata({
imports: [RouterTestingModule]
})
],
tags: ['autodocs'],
render: (args: TableComponent) => ({
@ -73,7 +71,7 @@ export const Ref: Story = {
label: 'hello',
data_type: 'reference',
data: {
reference: 'Patient/123',
reference: 'Patient/123=',
display: 'John Doe'
}
},
@ -82,8 +80,8 @@ export const Ref: Story = {
label: 'hello',
data_type: 'reference',
data: {
reference: 'Patient/123',
display: 'John Doe'
reference: 'aHR0cHM6Ly93d3cubWVyY3kubmV0L3NpdGVzL2RlZmF1bHQvZmlsZXMvZG9jdG9yX2ltYWdlcy9kZXNrdG9wLzE2NTk4ODYwNTktbS5qcGc=',
display: 'binary'
}
}
] as TableRowItem[]

View File

@ -11,6 +11,6 @@
<fhir-ui-table [displayModel]="displayModel" [tableData]="tableData"></fhir-ui-table>
</div>
<div *ngIf="showDetails" class="card-footer">
<a class="float-right" routerLink="/explore/{{displayModel?.source_id}}/resource/{{displayModel?.source_resource_id}}">details</a>
<a class="float-right" [routerLink]="['/explore', displayModel?.source_id, 'resource', displayModel?.source_resource_id]">details</a>
</div>
</div>

View File

@ -34,7 +34,7 @@
</div>
</div>
<div *ngIf="showDetails" class="card-footer">
<a class="float-right" routerLink="/explore/{{displayModel?.source_id}}/resource/{{displayModel?.source_resource_id}}">details</a>
<a class="float-right" [routerLink]="['/explore', displayModel?.source_id, 'resource', displayModel?.source_resource_id]">details</a>
</div>
</div>

View File

@ -34,6 +34,6 @@
</div>
</div>
<div *ngIf="showDetails" class="card-footer">
<a class="float-right" routerLink="/explore/{{displayModel?.source_id}}/resource/{{displayModel?.source_resource_id}}">details</a>
<a class="float-right" [routerLink]="['/explore', displayModel?.source_id, 'resource', displayModel?.source_resource_id]">details</a>
</div>
</div>

View File

@ -14,6 +14,6 @@
<fhir-ui-table [displayModel]="displayModel" [tableData]="tableData"></fhir-ui-table>
</div>
<div *ngIf="showDetails" class="card-footer">
<a class="float-right" routerLink="/explore/{{displayModel?.source_id}}/resource/{{displayModel?.source_resource_id}}">details</a>
<a class="float-right" [routerLink]="['/explore', displayModel?.source_id, 'resource', displayModel?.source_resource_id]">details</a>
</div>
</div>

View File

@ -16,6 +16,6 @@
<fhir-ui-table [displayModel]="displayModel" [tableData]="tableData"></fhir-ui-table>
</div>
<div *ngIf="showDetails" class="card-footer">
<a class="float-right" routerLink="/explore/{{displayModel?.source_id}}/resource/{{displayModel?.source_resource_id}}">details</a>
<a class="float-right" [routerLink]="['/explore', displayModel?.source_id, 'resource', displayModel?.source_resource_id]">details</a>
</div>
</div>

View File

@ -15,6 +15,6 @@
<fhir-ui-table [displayModel]="displayModel" [tableData]="tableData"></fhir-ui-table>
</div>
<div *ngIf="showDetails" class="card-footer">
<a class="float-right" routerLink="/explore/{{displayModel?.source_id}}/resource/{{displayModel?.source_resource_id}}">details</a>
<a class="float-right" [routerLink]="['/explore', displayModel?.source_id, 'resource', displayModel?.source_resource_id]">details</a>
</div>
</div>

View File

@ -20,6 +20,6 @@
</div>
</div>
<div *ngIf="showDetails" class="card-footer">
<a class="float-right" routerLink="/explore/{{displayModel?.source_id}}/resource/{{displayModel?.source_resource_id}}">details</a>
<a class="float-right" [routerLink]="['/explore', displayModel?.source_id, 'resource', displayModel?.source_resource_id]">details</a>
</div>
</div>

View File

@ -16,7 +16,7 @@
<fhir-ui-table [displayModel]="displayModel" [tableData]="tableData"></fhir-ui-table>
</div>
<div *ngIf="showDetails" class="card-footer">
<a class="float-right" routerLink="/explore/{{displayModel?.source_id}}/resource/{{displayModel?.source_resource_id}}">details</a>
<a class="float-right" [routerLink]="['/explore', displayModel?.source_id, 'resource', displayModel?.source_resource_id]">details</a>
</div>
</div>

View File

@ -16,7 +16,7 @@
<fhir-ui-table [displayModel]="displayModel" [tableData]="tableData"></fhir-ui-table>
</div>
<div *ngIf="showDetails" class="card-footer">
<a class="float-right" routerLink="/explore/{{displayModel?.source_id}}/resource/{{displayModel?.source_resource_id}}">details</a>
<a class="float-right" [routerLink]="['/explore', displayModel?.source_id, 'resource', displayModel?.source_resource_id]">details</a>
</div>
</div>

View File

@ -23,6 +23,6 @@
></canvas>
</div>
<div *ngIf="showDetails" class="card-footer">
<a class="float-right" routerLink="/explore/{{displayModel?.source_id}}/resource/{{displayModel?.source_resource_id}}">details</a>
<a class="float-right" [routerLink]="['/explore', displayModel?.source_id, 'resource', displayModel?.source_resource_id]">details</a>
</div>
</div>

View File

@ -10,6 +10,6 @@
<fhir-ui-table [displayModel]="displayModel" [tableData]="tableData"></fhir-ui-table>
</div>
<div *ngIf="showDetails" class="card-footer">
<a class="float-right" routerLink="/explore/{{displayModel?.source_id}}/resource/{{displayModel?.source_resource_id}}">details</a>
<a class="float-right" [routerLink]="['/explore', displayModel?.source_id, 'resource', displayModel?.source_resource_id]">details</a>
</div>
</div>

View File

@ -14,6 +14,6 @@
<fhir-ui-table [displayModel]="displayModel" [tableData]="tableData"></fhir-ui-table>
</div>
<div *ngIf="showDetails" class="card-footer">
<a class="float-right" routerLink="/explore/{{displayModel?.source_id}}/resource/{{displayModel?.source_resource_id}}">details</a>
<a class="float-right" [routerLink]="['/explore', displayModel?.source_id, 'resource', displayModel?.source_resource_id]">details</a>
</div>
</div>

View File

@ -16,7 +16,7 @@
<fhir-ui-table [displayModel]="displayModel" [tableData]="tableData"></fhir-ui-table>
</div>
<div *ngIf="showDetails" class="card-footer">
<a class="float-right" routerLink="/explore/{{displayModel?.source_id}}/resource/{{displayModel?.source_resource_id}}">details</a>
<a class="float-right" [routerLink]="['/explore', displayModel?.source_id, 'resource', displayModel?.source_resource_id]">details</a>
</div>
</div>

View File

@ -79,7 +79,7 @@ export class FhirDatatableComponent implements OnInit, OnChanges {
}
componentRef.instance.selectionChanged.subscribe((selected: FastenDisplayModel) => {
this.router.navigateByUrl(`/explore/${selected?.source_id}/resource/${selected?.source_resource_id}`);
this.router.navigate(['/explore', selected?.source_id, 'resource', selected?.source_resource_id]);
})
this.knownResourceType = (componentType != DatatableFallbackComponent)
}

View File

@ -40,7 +40,7 @@
<div class="modal-footer">
<a routerLink="/explore/{{modalSelectedSourceListItem?.source?.id}}" (click)="modal.close()" class="btn btn-indigo mr-auto">Explore</a>
<a [routerLink]="['/explore', modalSelectedSourceListItem?.source?.id]" (click)="modal.close()" class="btn btn-indigo mr-auto">Explore</a>
<div *ngIf="modalSelectedSourceListItem?.source?.platform_type != 'fasten'" class="d-inline-block" ngbDropdown>

View File

@ -3,7 +3,7 @@
<div class="row" >
<!-- Condition Header -->
<div class="col-6">
<span routerLink="/explore/{{firstObservation?.source_id}}/resource/{{firstObservation?.source_resource_id}}">{{observationTitle}}</span>
<span [routerLink]="['/explore', firstObservation?.source_id, 'resource', firstObservation?.source_resource_id]">{{observationTitle}}</span>
</div>
<div class="col-6">
{{firstObservation | fhirPath: "Observation.effectiveDateTime": "Observation.issued" | date}}
@ -36,7 +36,7 @@
<div #collapse="ngbCollapse" [ngbCollapse]="true">
<ul>
<li class="cursor-pointer tx-indigo" *ngFor="let observation of observations" routerLink="/explore/{{observation?.source_id}}/resource/{{observation?.source_resource_id}}">Observation: {{observation | fhirPath: "Observation.effectiveDateTime": "Observation.issued" | date}}</li>
<li class="cursor-pointer tx-indigo" *ngFor="let observation of observations" [routerLink]="['/explore', observation?.source_id, 'resource', observation?.source_resource_id]">Observation: {{observation | fhirPath: "Observation.effectiveDateTime": "Observation.issued" | date}}</li>
</ul>
</div>

View File

@ -1,6 +1,6 @@
<div class="card card-dashboard-seven mb-3">
<div class="card-header tx-medium">
<div class="row cursor-pointer" routerLink="/explore/{{conditionDisplayModel?.source_id}}/resource/{{conditionDisplayModel?.source_resource_id}}" role="link">
<div class="row cursor-pointer" [routerLink]="['/explore', conditionDisplayModel?.source_id, 'resource', conditionDisplayModel?.source_resource_id]" role="link">
<!-- Condition Header -->
<div class="col-6">
{{conditionDisplayModel?.sort_title ? conditionDisplayModel?.sort_title : (conditionGroup | fhirPath: "Condition.code.text.first()":"Condition.code.coding.display.first()")}}
@ -66,10 +66,10 @@
<div class="row">
<ng-container *ngFor="let encounter of encounters">
<div routerLink="/explore/{{encounter?.source_id}}/resource/{{encounter?.source_resource_id}}" class="col-6 mt-3 mb-2 tx-indigo" role="link">
<div [routerLink]="['/explore', encounter?.source_id, 'resource', encounter?.source_resource_id]" class="col-6 mt-3 mb-2 tx-indigo" role="link">
<strong>{{encounter.period_start | date}}</strong>
</div>
<div routerLink="/explore/{{encounter?.source_id}}/resource/{{encounter?.source_resource_id}}" class="col-6 mt-3 mb-2 tx-indigo" role="link">
<div [routerLink]="['/explore', encounter?.source_id, 'resource', encounter?.source_resource_id]" class="col-6 mt-3 mb-2 tx-indigo" role="link">
<small>{{encounter.location_display }}</small>
</div>
@ -137,7 +137,7 @@
<div *ngIf="encounter?.related_resources?.Device as devices" class="col-12 mt-2 mb-2">
<strong>Device:</strong>
<ul>
<li routerLink="/explore/{{device?.source_id}}/resource/{{device?.source_resource_id}}" *ngFor="let device of devices" role="link">
<li [routerLink]="['/explore', device?.source_id, 'resource', device?.source_resource_id]" *ngFor="let device of devices" role="link">
{{device.model}}
</li>
</ul>

View File

@ -1,6 +1,6 @@
<div class="card card-dashboard-seven mb-3">
<div class="card-header tx-medium">
<div class="row cursor-pointer" routerLink="/explore/{{eobDisplayModel?.source_id}}/resource/{{eobDisplayModel?.source_resource_id}}">
<div class="row cursor-pointer" [routerLink]="['/explore', eobDisplayModel?.source_id, 'resource', eobDisplayModel?.source_resource_id]">
<!-- Condition Header -->
<div class="col-6">
{{eobDisplayModel?.sort_title ? eobDisplayModel?.sort_title : condition?.display ? condition?.display : 'unknown'}}
@ -139,7 +139,7 @@
<div *ngIf="eobDisplayModel?.related_resources?.Device as devices" class="col-12 mt-2 mb-2">
<strong>Device:</strong>
<ul>
<li routerLink="/explore/{{device?.source_id}}/resource/{{device?.source_resource_id}}" *ngFor="let device of devices">
<li [routerLink]="['/explore', device?.source_id, 'resource', device?.source_resource_id]" *ngFor="let device of devices">
{{device.model}}
</li>
</ul>

View File

@ -13,7 +13,7 @@
<div class="timeline-body card">
<div class="timeline-header">
<span class="username">
<a style="color:black;font-size: 1.3125rem;font-weight: 500;" routerLink="/explore/{{displayModel?.source_id}}/resource/{{displayModel?.source_resource_id}}">
<a style="color:black;font-size: 1.3125rem;font-weight: 500;" [routerLink]="['/explore', displayModel?.source_id, 'resource', displayModel?.source_resource_id]">
{{displayModel?.sort_title}}
</a>
<small></small>
@ -96,7 +96,7 @@
<div *ngIf="displayModel?.related_resources?.Device as devices">
<strong>Device:</strong>
<ul>
<li routerLink="/explore/{{device?.source_id}}/resource/{{device?.source_resource_id}}" *ngFor="let device of devices" role="link">
<li [routerLink]="['/explore', device?.source_id, 'resource', device?.source_resource_id]" *ngFor="let device of devices" role="link">
{{device.model}}
</li>
</ul>
@ -110,7 +110,7 @@
<div ngbDropdownMenu aria-labelledby="dropdownReports">
<a class="dropdown-item"
*ngFor="let documentReference of displayModel?.related_resources['DocumentReference']" ngbDropdownItem
routerLink="/explore/{{documentReference?.source_id}}/resource/{{documentReference?.source_resource_id}}"
[routerLink]="['/explore', documentReference?.source_id, 'resource', documentReference?.source_resource_id]"
>{{documentReference?.sort_title}}</a>
<a class="dropdown-item"
*ngFor="let diagnosticReport of displayModel?.related_resources['DiagnosticReport']" ngbDropdownItem
@ -127,7 +127,7 @@
<ng-container *ngFor="let resourceEntry of displayModel?.related_resources | keyvalue">
<a class="dropdown-item"
*ngFor="let resourceListItem of resourceEntry.value" ngbDropdownItem
routerLink="/explore/{{resourceListItem?.source_id}}/resource/{{resourceListItem?.source_resource_id}}"
[routerLink]="['/explore', resourceListItem?.source_id, 'resource', resourceListItem?.source_resource_id]"
>{{resourceListItem.source_resource_type}} {{resourceListItem.sort_title ? '- '+resourceListItem.sort_title : '' }}</a>
</ng-container>

View File

@ -70,7 +70,7 @@ export class DashboardComponent implements OnInit {
}
selectSource(selectedSource: Source){
this.router.navigateByUrl(`/explore/${selectedSource.id}`, {
this.router.navigate(['/explore', selectedSource.id], {
state: selectedSource
});
}

View File

@ -52,7 +52,7 @@ export class ExploreComponent implements OnInit {
}
public exploreSource(sourceListItem: SourceListItem, ) {
this.router.navigateByUrl(`/explore/${sourceListItem.source.id}`, {
this.router.navigate(['/explore', sourceListItem.source.id], {
state: sourceListItem.source
});

View File

@ -2,7 +2,7 @@
<div class="container">
<div class="az-content-body">
<div class="az-content-breadcrumb">
<span class="cursor-pointer" routerLink="/explore/{{sourceId}}">{{sourceName}}</span>
<span class="cursor-pointer" [routerLink]="['/explore', sourceId]">{{sourceName}}</span>
<span>Resource</span>
<span>{{resource?.source_resource_type}}</span>
<span>{{resource?.source_resource_id}}</span>

View File

@ -18,7 +18,7 @@
<div class="patient-row row">
<div class="col-7 patient-name"><h3 class="pull-left text-primary">{{getPatientName()}}</h3></div>
<div class="col-5">
<a routerLink="/explore/{{selectedSource?.id}}/resource/{{selectedPatient?.source_resource_id}}" class="btn btn-indigo btn-icon float-right">
<a [routerLink]="['/explore', selectedSource?.id, 'resource', selectedPatient?.source_resource_id]" class="btn btn-indigo btn-icon float-right">
<i class="fas fa-info-circle"></i>
</a>
</div>