From 8bb00151c9d875a1408b7319ecbd717042c0bad4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20D=C3=ADaz=20Roussel?= Date: Thu, 22 Sep 2022 17:31:40 +0200 Subject: [PATCH 1/2] Separate reports endpoints and add sections ones --- .../document-detail.component.ts | 15 +- src/app/model/report.ts | 2 +- src/app/reports/reports.component.ts | 10 +- src/app/services/document.service.ts | 101 ----------- src/app/services/report.service.ts | 157 ++++++++++++++++++ 5 files changed, 171 insertions(+), 114 deletions(-) create mode 100644 src/app/services/report.service.ts diff --git a/src/app/document-detail/document-detail.component.ts b/src/app/document-detail/document-detail.component.ts index 051405c..777d8bc 100644 --- a/src/app/document-detail/document-detail.component.ts +++ b/src/app/document-detail/document-detail.component.ts @@ -3,6 +3,7 @@ import { Document } from '../model/document'; import { ActivatedRoute } from '@angular/router'; import { Location } from '@angular/common'; import { DocumentService } from '../services/document.service'; +import { ReportService } from '../services/report.service'; import { EventService } from '../services/event.service'; import { DomSanitizer, SafeHtml } from '@angular/platform-browser'; import { Finding } from '../model/finding'; @@ -80,7 +81,7 @@ export class DocumentDetailComponent implements OnInit { static FINISHED = 'FINISHED'; // tslint:disable-next-line: max-line-length - constructor(private router: Router, private route: ActivatedRoute, private documentService: DocumentService, private cdiscSendCTService: CdisSendCtService, private location: Location, private sanitizer: DomSanitizer, private eventService: EventService) { + constructor(private router: Router, private route: ActivatedRoute, private documentService: DocumentService, private reportService: ReportService, private cdiscSendCTService: CdisSendCtService, private location: Location, private sanitizer: DomSanitizer, private eventService: EventService) { const bratLocation = environment.bratUrl; this.loadBratVisualizer(); @@ -207,7 +208,7 @@ export class DocumentDetailComponent implements OnInit { getDocument(): void { const id = this.route.snapshot.paramMap.get('id'); - this.documentService.getReport(id) + this.reportService.getReport(id) .subscribe(report => { this.report = report; this.setNextStatus(this.report.status); @@ -301,7 +302,7 @@ export class DocumentDetailComponent implements OnInit { } findingSelected(documentId, finding): void { - this.documentService.findingSelected(documentId, finding) + this.reportService.findingSelected(documentId, finding) .subscribe(text => { var loading = document.getElementById('loadingDiv'); loading.addEventListener("load", this.loaded); @@ -322,7 +323,7 @@ export class DocumentDetailComponent implements OnInit { } pretoxSentenceSelected(documentId, pretoxSentence): void { - this.documentService.pretoxSentenceSelected(documentId, pretoxSentence) + this.reportService.pretoxSentenceSelected(documentId, pretoxSentence) .subscribe(text => { this.docData = text; document.getElementById('data2').className = 'collapse show'; @@ -345,7 +346,7 @@ export class DocumentDetailComponent implements OnInit { } findDocumentText(): void { - this.documentService.findDocumentText(this.report.id) + this.reportService.findDocumentText(this.report.id) .subscribe(text => { this.docData = text; document.getElementById('data2').className = 'collapse show'; @@ -367,7 +368,7 @@ export class DocumentDetailComponent implements OnInit { getAllEvidence() { //const id = +this.route.snapshot.paramMap.get('id'); const id = this.report.id; - this.documentService.getAllEvidence(id) + this.reportService.getAllEvidence(id) .subscribe(text => { this.docData = text; document.getElementById('data2').className = 'collapse show'; @@ -388,7 +389,7 @@ export class DocumentDetailComponent implements OnInit { getSentencesEvidence() { //const id = +this.route.snapshot.paramMap.get('id'); const id = this.report.id; - this.documentService.getSentencesEvidence(id) + this.reportService.getSentencesEvidence(id) .subscribe(text => { this.docData = text; document.getElementById('data2').className = 'collapse show'; diff --git a/src/app/model/report.ts b/src/app/model/report.ts index bf18dd0..ebcec39 100644 --- a/src/app/model/report.ts +++ b/src/app/model/report.ts @@ -1,7 +1,7 @@ import { Section } from "./section"; export class Report { - id:number; + id:string; uploadDate:string; fileName:string; fileType:string; diff --git a/src/app/reports/reports.component.ts b/src/app/reports/reports.component.ts index d4e028e..6e74597 100644 --- a/src/app/reports/reports.component.ts +++ b/src/app/reports/reports.component.ts @@ -1,5 +1,5 @@ import { Component, Input, OnInit, SimpleChanges } from '@angular/core'; -import { DocumentService } from '../services/document.service'; +import { ReportService } from '../services/report.service'; import { Report } from '../model/report'; import { Router } from '@angular/router'; import { TabulatorFull as Tabulator } from 'tabulator-tables'; @@ -29,7 +29,7 @@ export class ReportsComponent implements OnInit { tab = document.createElement('div'); - constructor(private documentService: DocumentService, private workflowService: WorkflowService, + constructor(private reportService: ReportService, private workflowService: WorkflowService, private router: Router, public dialog: MatDialog) { } ngOnInit() { @@ -45,7 +45,7 @@ export class ReportsComponent implements OnInit { } getReports(): void { - this.documentService.getReports() + this.reportService.getReports() .subscribe(reports => { this.reports = reports; var data = []; @@ -94,7 +94,7 @@ export class ReportsComponent implements OnInit { } delete(reportId): void { - this.documentService.deleteReport(reportId).subscribe(event => { + this.reportService.deleteReport(reportId).subscribe(event => { this.messages = []; this.validation_errors = []; this.getReports(); @@ -116,7 +116,7 @@ export class ReportsComponent implements OnInit { } openLegacyReport(gridFSId) { - this.documentService.openLegacyReport(gridFSId); + this.reportService.openLegacyReport(gridFSId); } openDialog(reportId) { diff --git a/src/app/services/document.service.ts b/src/app/services/document.service.ts index ee7ede3..6f91a5b 100644 --- a/src/app/services/document.service.ts +++ b/src/app/services/document.service.ts @@ -5,11 +5,8 @@ import { MessageService } from './message.service'; import { HttpClient, HttpHeaders } from '@angular/common/http'; import { catchError, map, tap } from 'rxjs/operators'; import { Finding } from '../model/finding'; -import { Annotation } from '../model/annotation'; -import { Report } from '../model/report'; import { environment } from '../../environments/environment'; import { DocumentTracking } from '../model/document-tracking'; -import { FindingSR } from '../model/findingsr'; import { SRDomainFinding } from '../model/srdomainfinding'; import { SRDomainDocument } from '../model/srdomaindocument'; const httpOptions = { @@ -20,11 +17,8 @@ const httpOptions = { providedIn: 'root' }) export class DocumentService { - private pretoxUrl = environment.apiUrl; private documentsUrl = environment.apiUrl + "/documents/"; - private reportsUrl = environment.apiUrl + "/reports/"; private apiSRDomainURL = environment.apiSRDomainUrl + "/reports/"; - private apiSRDomainComboURL = environment.apiSRDomainUrl + "/list/"; constructor(private http: HttpClient, private messageService: MessageService) { } getDocuments(): Observable { @@ -34,19 +28,6 @@ export class DocumentService { ); } - getReports(): Observable { - return this.http.get(this.reportsUrl).pipe( - tap(_ => this.log('fetched reports')), - catchError(this.handleError('getReports', [])) - ); - } - - /** GET report by id. Will 404 if id not found */ - getReport(id: string): Observable { - const url = `${this.reportsUrl}${id}`; - return this.http.get(url); - } - /** GET document by id. Will 404 if id not found */ getDocument(id: number): Observable { const url = `${this.documentsUrl}${id}`; @@ -80,35 +61,6 @@ export class DocumentService { }); } - /** GET the legacy pdf report */ - openLegacyReport(gridFSId: number): any { - const url = `${this.reportsUrl}download/${gridFSId}`; - return this.http.get(url, { - responseType: 'blob', - observe: 'response' - }) - .pipe(map(res => { - console.log(res.headers.get('content-disposition')); - return { - filename: name + '.pdf', - data: res.body - }; - })) - .subscribe(res => { - let url = window.URL.createObjectURL(res.data); - let a = document.createElement('a'); - document.body.appendChild(a); - a.setAttribute('style', 'display: none'); - a.href = url; - a.download = res.filename; - a.click(); - window.URL.revokeObjectURL(url); - a.remove(); - }); - } - - - /** DEPRECATED, no more levels of findings set validation of finding */ setFindingValidation(id: number, findingId: number, finding_validation: string): Observable { const url = `${this.documentsUrl}${id}/findingValidation/${findingId}/${finding_validation}`; @@ -183,24 +135,6 @@ export class DocumentService { ); } - /** GET Snipped of finding selected */ - findingSelected(id: number, finding: Finding): Observable { - const url = `${this.reportsUrl}${id}/evidence/finding/${finding.findingId}`; - return this.http.get(url, { responseType: 'text' }).pipe( - tap(_ => this.log(`fetched finding id=${finding.findingId}`)), - catchError(this.handleError(`getFinding id=${finding.findingId}`)) - ); - } - - /** GET Snipped of the full text with no annotations */ - findDocumentText(id: number): Observable { - const url = `${this.reportsUrl}${id}/text/`; - return this.http.get(url, { responseType: 'text' }).pipe( - tap(_ => this.log(`fetched text id=${id}`)), - catchError(this.handleError(`getText id=${id}`)) - ); - } - /** Get SRDomain format and send to srdomain api */ sendToSRDomain(id: number): any { //call to get srdomain @@ -241,15 +175,6 @@ export class DocumentService { ); } - /** GET Snipped of all finding evidence */ - getAllEvidence(id: number): Observable { - const url = `${this.reportsUrl}${id}/evidence/findings`; - return this.http.get(url, { responseType: 'text' }).pipe( - tap(_ => this.log(`fetched all evidence id=${id}`)), - catchError(this.handleError(`getFindings id=${id}`)) - ); - } - /** GET Snipped of all finding evidence */ getEvidence(id: number): Observable { const url = `${this.documentsUrl}${id}/evidence/all`; @@ -259,23 +184,6 @@ export class DocumentService { ); } - /** GET Snipped of sentences evidence */ - getSentencesEvidence(id: number): Observable { - const url = `${this.reportsUrl}${id}/evidence/sentences`; - return this.http.get(url, { responseType: 'text' }).pipe( - tap(_ => this.log(`fetched all sentences evidence id=${id}`)), - catchError(this.handleError(`getSentencesEvidence id=${id}`)) - ); - } - - pretoxSentenceSelected(id: number, pretoxSentence: Annotation): Observable { - const url = `${this.reportsUrl}${id}/evidence/sentence/${pretoxSentence.id}`; - return this.http.get(url, { responseType: 'text' }).pipe( - tap(_ => this.log(`fetched pretox sentence id=${pretoxSentence.id}`)), - catchError(this.handleError(`getPretoxSentence id=${pretoxSentence.id}`)) - ); - } - /** PUT: update the document on the server */ updateDocument(document: Document): Observable { return this.http.put(this.documentsUrl, document, httpOptions).pipe( @@ -302,15 +210,6 @@ export class DocumentService { ); } - /** Delete report */ - deleteReport(id: string): Observable { - const url = `${this.reportsUrl}remove/${id}`; - return this.http.delete(url, { responseType: 'text' }).pipe( - tap(_ => this.log(`deleteReport id=${id}`)), - catchError(this.handleError(`deleteReport id=${id}`)) - ); - } - /** Log a DocumentService message with the MessageService */ private log(message: string) { this.messageService.add(`DocumentService: ${message}`); diff --git a/src/app/services/report.service.ts b/src/app/services/report.service.ts new file mode 100644 index 0000000..7ff548e --- /dev/null +++ b/src/app/services/report.service.ts @@ -0,0 +1,157 @@ +import { Injectable } from '@angular/core'; +import { Observable, of } from 'rxjs'; +import { MessageService } from './message.service'; +import { HttpClient, HttpHeaders } from '@angular/common/http'; +import { catchError, map, tap } from 'rxjs/operators'; +import { Finding } from '../model/finding'; +import { Annotation } from '../model/annotation'; +import { Report } from '../model/report'; +import { environment } from '../../environments/environment'; +const httpOptions = { + headers: new HttpHeaders({ 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' }) +}; + +@Injectable({ + providedIn: 'root' +}) +export class ReportService { + private reportsUrl = environment.apiUrl + "/reports/"; + constructor(private http: HttpClient, private messageService: MessageService) { } + + getReports(): Observable { + return this.http.get(this.reportsUrl).pipe( + tap(_ => this.log('fetched reports')), + catchError(this.handleError('getReports', [])) + ); + } + + /** GET report by id. Will 404 if id not found */ + getReport(id: string): Observable { + const url = `${this.reportsUrl}${id}`; + return this.http.get(url); + } + + findReportSection(reportId:string, sectionId: string): Observable { + const url = `${this.reportsUrl}${reportId}/section/${sectionId}`; + return this.http.get(url); + } + + /** GET the legacy pdf report */ + openLegacyReport(gridFSId: number): any { + const url = `${this.reportsUrl}download/${gridFSId}`; + return this.http.get(url, { + responseType: 'blob', + observe: 'response' + }) + .pipe(map(res => { + console.log(res.headers.get('content-disposition')); + return { + filename: name + '.pdf', + data: res.body + }; + })) + .subscribe(res => { + let url = window.URL.createObjectURL(res.data); + let a = document.createElement('a'); + document.body.appendChild(a); + a.setAttribute('style', 'display: none'); + a.href = url; + a.download = res.filename; + a.click(); + window.URL.revokeObjectURL(url); + a.remove(); + }); + } + + /** GET Snipped of finding selected */ + findingSelected(id: number, finding: Finding): Observable { + const url = `${this.reportsUrl}${id}/evidence/finding/${finding.findingId}`; + return this.http.get(url, { responseType: 'text' }).pipe( + tap(_ => this.log(`fetched finding id=${finding.findingId}`)), + catchError(this.handleError(`getFinding id=${finding.findingId}`)) + ); + } + + /** GET Snipped of the full text with no annotations */ + findDocumentText(id: number): Observable { + const url = `${this.reportsUrl}${id}/text/`; + return this.http.get(url, { responseType: 'text' }).pipe( + tap(_ => this.log(`fetched text id=${id}`)), + catchError(this.handleError(`getText id=${id}`)) + ); + } + + /** GET Snipped of all finding evidence */ + getAllEvidence(id: number): Observable { + const url = `${this.reportsUrl}${id}/evidence/findings`; + return this.http.get(url, { responseType: 'text' }).pipe( + tap(_ => this.log(`fetched all evidence id=${id}`)), + catchError(this.handleError(`getFindings id=${id}`)) + ); + } + + getSectionEvidence(reportId: string, sectionId: string): Observable { + const url = `${this.reportsUrl}${reportId}/section/${sectionId}/evidence/findings`; + return this.http.get(url, { responseType: 'text' }).pipe( + tap(_ => this.log(`fetched all evidence reportId=${reportId}; sectionId=${sectionId}`)), + catchError(this.handleError(`getFindings reportId=${reportId}; sectionId=${sectionId}`)) + ); + } + + /** GET Snipped of sentences evidence */ + getSentencesEvidence(id: string): Observable { + const url = `${this.reportsUrl}${id}/evidence/sentences`; + return this.http.get(url, { responseType: 'text' }).pipe( + tap(_ => this.log(`fetched all sentences evidence id=${id}`)), + catchError(this.handleError(`getSentencesEvidence id=${id}`)) + ); + } + + getSectionSentencesEvidence(reportId: string, sectionId: string): Observable { + const url = `${this.reportsUrl}${reportId}/section/${sectionId}/evidence/sentences`; + return this.http.get(url, { responseType: 'text' }).pipe( + tap(_ => this.log(`fetched all sentences evidence reportId=${reportId}; sectionId=${sectionId}`)), + catchError(this.handleError(`getSentencesEvidence reportId=${reportId}; sectionId=${sectionId}`)) + ); + } + + pretoxSentenceSelected(id: number, pretoxSentence: Annotation): Observable { + const url = `${this.reportsUrl}${id}/evidence/sentence/${pretoxSentence.id}`; + return this.http.get(url, { responseType: 'text' }).pipe( + tap(_ => this.log(`fetched pretox sentence id=${pretoxSentence.id}`)), + catchError(this.handleError(`getPretoxSentence id=${pretoxSentence.id}`)) + ); + } + + /** Delete report */ + deleteReport(id: string): Observable { + const url = `${this.reportsUrl}remove/${id}`; + return this.http.delete(url, { responseType: 'text' }).pipe( + tap(_ => this.log(`deleteReport id=${id}`)), + catchError(this.handleError(`deleteReport id=${id}`)) + ); + } + + /** Log a DocumentService message with the MessageService */ + private log(message: string) { + this.messageService.add(`DocumentService: ${message}`); + } + + /** + * Handle Http operation that failed. + * Let the app continue. + * @param operation - name of the operation that failed + * @param result - optional value to return as the observable result + */ + private handleError(operation = 'operation', result?: T) { + return (error: any): Observable => { + // TODO: send the error to remote logging infrastructure + console.error(error); // log to console instead + // TODO: better job of transforming error for user consumption + this.log(`${operation} failed: ${error.message}`); + // Let the app keep running by returning an empty result. + return of(result as T); + }; + } + +} -- GitLab From 32820373f1a973bcdfa979faa2dc43411dca8eed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20D=C3=ADaz=20Roussel?= Date: Fri, 23 Sep 2022 08:57:38 +0200 Subject: [PATCH 2/2] Add section column to findings table --- .../pretoxsentences-tabulator.component.ts | 3 +++ src/app/services/report.service.ts | 4 ++-- .../srdomaintemplate-tabulator.component.ts | 3 +++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/app/pretoxsentences-tabulator/pretoxsentences-tabulator.component.ts b/src/app/pretoxsentences-tabulator/pretoxsentences-tabulator.component.ts index 9670b67..2186e5c 100644 --- a/src/app/pretoxsentences-tabulator/pretoxsentences-tabulator.component.ts +++ b/src/app/pretoxsentences-tabulator/pretoxsentences-tabulator.component.ts @@ -195,6 +195,9 @@ export class PretoxsentencesTabulatorComponent implements OnInit { return ''; } }, + { + title: 'Section', field: 'section', cssClass: "tabulator-cell non-editable-cell", + }, { title: 'Finding', field: 'srfndg', headerSort: true, headerFilter: true },//SRFNDG //{title: 'Finding (Free Text)', field: 'srores', headerSort: true , headerFilter: false},//SRORES { title: 'Test Name', field: 'srtstcd', headerSort: true, headerFilter: true },//SRTSTCD diff --git a/src/app/services/report.service.ts b/src/app/services/report.service.ts index 7ff548e..24a1de9 100644 --- a/src/app/services/report.service.ts +++ b/src/app/services/report.service.ts @@ -73,7 +73,7 @@ export class ReportService { } /** GET Snipped of the full text with no annotations */ - findDocumentText(id: number): Observable { + findDocumentText(id: string): Observable { const url = `${this.reportsUrl}${id}/text/`; return this.http.get(url, { responseType: 'text' }).pipe( tap(_ => this.log(`fetched text id=${id}`)), @@ -82,7 +82,7 @@ export class ReportService { } /** GET Snipped of all finding evidence */ - getAllEvidence(id: number): Observable { + getAllEvidence(id: string): Observable { const url = `${this.reportsUrl}${id}/evidence/findings`; return this.http.get(url, { responseType: 'text' }).pipe( tap(_ => this.log(`fetched all evidence id=${id}`)), diff --git a/src/app/srdomaintemplate-tabulator/srdomaintemplate-tabulator.component.ts b/src/app/srdomaintemplate-tabulator/srdomaintemplate-tabulator.component.ts index fbea754..f92d891 100644 --- a/src/app/srdomaintemplate-tabulator/srdomaintemplate-tabulator.component.ts +++ b/src/app/srdomaintemplate-tabulator/srdomaintemplate-tabulator.component.ts @@ -343,6 +343,9 @@ export class SrdomaintemplateTabulatorComponent implements OnInit { { title: '', width: 5, field: 'srDomainId', cssClass: "tabulator-cell non-editable-cell", }, + { + title: 'Section', field: 'section', cssClass: "tabulator-cell non-editable-cell", + }, { title: 'Finding', field: 'srfndg', cssClass: "tabulator-cell non-editable-cell", headerSort: true, editor: 'autocomplete', editable: this.editCheck.bind(this), editorParams: this.paramLookupFinding.bind(this), sorter: "string", formatter: this.ellipsisFormatter -- GitLab