diff --git a/apps/red-ui/proxy.conf.json b/apps/red-ui/proxy.conf.json index fb4e0b5f5..b4abf4ba7 100644 --- a/apps/red-ui/proxy.conf.json +++ b/apps/red-ui/proxy.conf.json @@ -34,5 +34,17 @@ "secure": false, "changeOrigin": true, "logLevel": "debug" + }, + "/dictionary": { + "target": "https://timo-redaction-dev.iqser.cloud/", + "secure": false, + "changeOrigin": true, + "logLevel": "debug" + }, + "/manualRedaction": { + "target": "https://timo-redaction-dev.iqser.cloud/", + "secure": false, + "changeOrigin": true, + "logLevel": "debug" } } diff --git a/apps/red-ui/src/app/app.module.ts b/apps/red-ui/src/app/app.module.ts index 3e5463bb8..bbd5e4bce 100644 --- a/apps/red-ui/src/app/app.module.ts +++ b/apps/red-ui/src/app/app.module.ts @@ -51,6 +51,8 @@ import {CompositeRouteGuard} from "./utils/composite-route.guard"; import {AppStateGuard} from "./state/app-state.guard"; import {ChartsModule} from "ng2-charts"; import { SimpleDoughnutChartComponent } from './simple-doughnut-chart/simple-doughnut-chart.component'; +import { ManualRedactionDialogComponent } from './screens/file/manual-redaction-dialog/manual-redaction-dialog.component'; +import {MatCheckboxModule} from "@angular/material/checkbox"; export function HttpLoaderFactory(httpClient: HttpClient) { return new TranslateHttpLoader(httpClient, '/assets/i18n/', '.json'); @@ -72,80 +74,82 @@ export function HttpLoaderFactory(httpClient: HttpClient) { InitialsAvatarComponent, StatusBarComponent, LogoComponent, - SimpleDoughnutChartComponent + SimpleDoughnutChartComponent, + ManualRedactionDialogComponent ], - imports: [ - BrowserModule, - BrowserAnimationsModule, - ChartsModule, - ReactiveFormsModule, - HttpClientModule, - AuthModule, - IconsModule, - ApiModule, - MatDialogModule, - TranslateModule.forRoot({ - loader: { - provide: TranslateLoader, - useFactory: HttpLoaderFactory, - deps: [HttpClient] - } - }), - RouterModule.forRoot([ - { - path: '', - redirectTo: 'ui/projects', - pathMatch: 'full' - }, - { - path: 'ui', - component: BaseScreenComponent, - children: [ - { - path: 'projects', - component: ProjectListingScreenComponent, - canActivate: [CompositeRouteGuard], - data: { - routeGuards: [AuthGuard, AppStateGuard], + imports: [ + BrowserModule, + BrowserAnimationsModule, + ChartsModule, + ReactiveFormsModule, + HttpClientModule, + AuthModule, + IconsModule, + ApiModule, + MatDialogModule, + TranslateModule.forRoot({ + loader: { + provide: TranslateLoader, + useFactory: HttpLoaderFactory, + deps: [HttpClient] } - }, - { - path: 'projects/:projectId', - component: ProjectOverviewScreenComponent, - canActivate: [CompositeRouteGuard], - data: { - routeGuards: [AuthGuard, AppStateGuard], + }), + RouterModule.forRoot([ + { + path: '', + redirectTo: 'ui/projects', + pathMatch: 'full' + }, + { + path: 'ui', + component: BaseScreenComponent, + children: [ + { + path: 'projects', + component: ProjectListingScreenComponent, + canActivate: [CompositeRouteGuard], + data: { + routeGuards: [AuthGuard, AppStateGuard], + } + }, + { + path: 'projects/:projectId', + component: ProjectOverviewScreenComponent, + canActivate: [CompositeRouteGuard], + data: { + routeGuards: [AuthGuard, AppStateGuard], + } + }, + { + path: 'projects/:projectId/file/:fileId', + component: FilePreviewScreenComponent, + canActivate: [CompositeRouteGuard], + data: { + routeGuards: [AuthGuard, AppStateGuard], + } + } + ] } - }, - { - path: 'projects/:projectId/file/:fileId', - component: FilePreviewScreenComponent, - canActivate: [CompositeRouteGuard], - data: { - routeGuards: [AuthGuard, AppStateGuard], - } - } - ] - } - ]), - NgpSortModule, - MatToolbarModule, - MatButtonModule, - MatMenuModule, - MatIconModule, - MatTooltipModule, - MatSnackBarModule, - MatTabsModule, - MatButtonToggleModule, - MatFormFieldModule, - ToastrModule.forRoot(), - MatSelectModule, - MatSidenavModule, - FileUploadModule, - ServiceWorkerModule.register('ngsw-worker.js', {enabled: environment.production}), - MatProgressSpinnerModule - ], + ]), + NgpSortModule, + MatToolbarModule, + MatButtonModule, + MatMenuModule, + MatIconModule, + MatTooltipModule, + MatSnackBarModule, + MatTabsModule, + MatButtonToggleModule, + MatFormFieldModule, + ToastrModule.forRoot(), + MatSelectModule, + MatSidenavModule, + FileUploadModule, + ServiceWorkerModule.register('ngsw-worker.js', {enabled: environment.production}), + MatProgressSpinnerModule, + MatCheckboxModule + ], providers: [{ provide: HTTP_INTERCEPTORS, multi: true, diff --git a/apps/red-ui/src/app/screens/file/file-preview-screen/file-preview-screen.component.html b/apps/red-ui/src/app/screens/file/file-preview-screen/file-preview-screen.component.html index f9bf6c2bc..f36c63db8 100644 --- a/apps/red-ui/src/app/screens/file/file-preview-screen/file-preview-screen.component.html +++ b/apps/red-ui/src/app/screens/file/file-preview-screen/file-preview-screen.component.html @@ -12,7 +12,6 @@ - @@ -22,9 +21,11 @@ @@ -126,4 +127,6 @@ + + diff --git a/apps/red-ui/src/app/screens/file/file-preview-screen/file-preview-screen.component.ts b/apps/red-ui/src/app/screens/file/file-preview-screen/file-preview-screen.component.ts index 42797a7bc..6ca4de11a 100644 --- a/apps/red-ui/src/app/screens/file/file-preview-screen/file-preview-screen.component.ts +++ b/apps/red-ui/src/app/screens/file/file-preview-screen/file-preview-screen.component.ts @@ -1,16 +1,21 @@ -import { ChangeDetectorRef, Component, ElementRef, OnInit, ViewChild } from '@angular/core'; -import { ActivatedRoute, Router } from '@angular/router'; -import { FileUploadControllerService, ProjectControllerService, StatusControllerService } from '@redaction/red-ui-http'; -import { TranslateService } from '@ngx-translate/core'; -import { NotificationService } from '../../../notification/notification.service'; -import { MatDialog } from '@angular/material/dialog'; -import { AppStateService } from '../../../state/app-state.service'; -import { FileDetailsDialogComponent } from './file-details-dialog/file-details-dialog.component'; -import { ViewerSyncService } from '../service/viewer-sync.service'; -import { Annotations } from '@pdftron/webviewer'; -import { PdfViewerComponent } from '../pdf-viewer/pdf-viewer.component'; -import { AnnotationUtils } from '../../../utils/annotation-utils'; - +import {ChangeDetectorRef, Component, ElementRef, OnInit, ViewChild} from '@angular/core'; +import {ActivatedRoute, Router} from '@angular/router'; +import { + FileUploadControllerService, + ManualRedactionEntry, + ProjectControllerService, + StatusControllerService +} from '@redaction/red-ui-http'; +import {TranslateService} from '@ngx-translate/core'; +import {NotificationService} from '../../../notification/notification.service'; +import {MatDialog} from '@angular/material/dialog'; +import {AppStateService} from '../../../state/app-state.service'; +import {FileDetailsDialogComponent} from './file-details-dialog/file-details-dialog.component'; +import {ViewerSyncService} from '../service/viewer-sync.service'; +import {Annotations} from '@pdftron/webviewer'; +import {PdfViewerComponent} from '../pdf-viewer/pdf-viewer.component'; +import {AnnotationUtils} from '../../../utils/annotation-utils'; +import {ManualRedactionDialogComponent} from "../manual-redaction-dialog/manual-redaction-dialog.component"; @Component({ @@ -36,6 +41,8 @@ export class FilePreviewScreenComponent implements OnInit { public selectedPageNumber: number; public quickNavigation: { pageNumber: number, redactions: number, hints: number }[] = []; + private _manualRedactionEntry: ManualRedactionEntry; + constructor( public readonly appStateService: AppStateService, private readonly _changeDetectorRef: ChangeDetectorRef, @@ -97,11 +104,15 @@ export class FilePreviewScreenComponent implements OnInit { const pageNumber = annotation.getPageNumber(); let el = this.quickNavigation.find((page) => page.pageNumber === pageNumber); if (!el) { - el = { pageNumber, redactions: 0, hints: 0 } + el = {pageNumber, redactions: 0, hints: 0} this.quickNavigation.push(el); } - if (annotation.Id.startsWith('hint:')) { el.hints++; } - if (annotation.Id.startsWith('redaction:')) { el.redactions++; } + if (annotation.Id.startsWith('hint:')) { + el.hints++; + } + if (annotation.Id.startsWith('redaction:')) { + el.redactions++; + } } } this.annotations = AnnotationUtils.sortAnnotations(this.annotations); @@ -131,12 +142,12 @@ export class FilePreviewScreenComponent implements OnInit { return; } - const { top, height } = el.getBoundingClientRect(); + const {top, height} = el.getBoundingClientRect(); const headerHeight = window.innerHeight - this._annotationsContainer.nativeElement.getBoundingClientRect().height; if (top < headerHeight || top > window.innerHeight - height - 30) { const scrollTop = this._annotationsContainer.nativeElement.scrollTop - 30; - this._annotationsContainer.nativeElement.scroll({ top: scrollTop + top - headerHeight, behavior: 'smooth' }); + this._annotationsContainer.nativeElement.scroll({top: scrollTop + top - headerHeight, behavior: 'smooth'}); } } @@ -156,4 +167,21 @@ export class FilePreviewScreenComponent implements OnInit { this.selectedPageNumber = pageNumber; this._viewerComponent.navigateToPage(pageNumber); } + + handleManualAnnotationRequest($event: ManualRedactionEntry) { + this._manualRedactionEntry = $event; + document.getElementById('open-manual-redaction-dialog-btn').click(); + } + + openManualRedactionDialog() { + const ref = this._dialog.open(ManualRedactionDialogComponent, { + width: '600px', + maxWidth: '90vw', + data: this._manualRedactionEntry + }); + + ref.afterClosed().subscribe(() => { + this._manualRedactionEntry = null; + }) + } } diff --git a/apps/red-ui/src/app/screens/file/manual-redaction-dialog/manual-redaction-dialog.component.html b/apps/red-ui/src/app/screens/file/manual-redaction-dialog/manual-redaction-dialog.component.html new file mode 100644 index 000000000..851c77843 --- /dev/null +++ b/apps/red-ui/src/app/screens/file/manual-redaction-dialog/manual-redaction-dialog.component.html @@ -0,0 +1,45 @@ +
+
+
+ +
+ +
+ +
+
+
+
+ +
+ + +
+
+ {{'manual-redaction.dialog.content.dictionary.add.label' | translate}} +
+ + {{'manual-redaction.dialog.content.dictionary.label' | translate}} + + + {{dictionary.type}} + + + + +
+ +
+ +
+ +
+ + +
diff --git a/apps/red-ui/src/app/screens/file/manual-redaction-dialog/manual-redaction-dialog.component.scss b/apps/red-ui/src/app/screens/file/manual-redaction-dialog/manual-redaction-dialog.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/apps/red-ui/src/app/screens/file/manual-redaction-dialog/manual-redaction-dialog.component.ts b/apps/red-ui/src/app/screens/file/manual-redaction-dialog/manual-redaction-dialog.component.ts new file mode 100644 index 000000000..1fb7598b8 --- /dev/null +++ b/apps/red-ui/src/app/screens/file/manual-redaction-dialog/manual-redaction-dialog.component.ts @@ -0,0 +1,70 @@ +import {Component, Inject, OnInit} from '@angular/core'; +import {FormBuilder, FormGroup, Validators} from "@angular/forms"; +import {AppStateService} from "../../../state/app-state.service"; +import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog"; +import { + DictionaryControllerService, + ManualRedactionControllerService, + ManualRedactionEntry, + TypeValue +} from "@redaction/red-ui-http"; +import {NotificationService, NotificationType} from "../../../notification/notification.service"; +import {TranslateService} from "@ngx-translate/core"; +import {map} from "rxjs/operators"; +import {Observable} from "rxjs"; + + +@Component({ + selector: 'redaction-manual-redaction-dialog', + templateUrl: './manual-redaction-dialog.component.html', + styleUrls: ['./manual-redaction-dialog.component.scss'] +}) +export class ManualRedactionDialogComponent implements OnInit { + + redactionForm: FormGroup; + dictionaries: Observable>; + + constructor( + private readonly _appStateService: AppStateService, + private readonly _formBuilder: FormBuilder, + private readonly _notificationService: NotificationService, + private readonly _translateService: TranslateService, + private readonly _manualRedactionControllerService: ManualRedactionControllerService, + private readonly _dictionaryControllerService: DictionaryControllerService, + public dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public manualRedactionInput: ManualRedactionEntry) { + } + + async ngOnInit() { + this.redactionForm = this._formBuilder.group({ + addToDictionary: [false], + reason: [null, Validators.required], + dictionary: null, + }); + this.dictionaries = this._dictionaryControllerService.getAllTypes().pipe(map(r => r.types)); + } + + + saveManualRedaction() { + const mre = Object.assign({}, this.manualRedactionInput); + this._enhanceManualRedaction(mre); + this._manualRedactionControllerService.updateManualRedaction({entriesToAdd: [mre]}, this._appStateService.activeProject.project.projectId, this._appStateService.activeFile.fileId).subscribe(ok=>{ + this._notificationService.showToastNotification(this._translateService.instant('manual-redaction.dialog.add-redaction.success.label'), null, NotificationType.SUCCESS); + this.dialogRef.close(); + },(err)=>{ + this._notificationService.showToastNotification(this._translateService.instant('manual-redaction.dialog.add-redaction.failed.label',err), null, NotificationType.SUCCESS); + }); + + } + + private _enhanceManualRedaction(mre: ManualRedactionEntry) { + mre.type = this.redactionForm.get('dictionary').value; + mre.addToDictionary = this.redactionForm.get('addToDictionary').value; + mre.reason = this.redactionForm.get('reason').value; + } + + get showDictionary(){ + return !this.redactionForm.get('addToDictionary').value + } + +} diff --git a/apps/red-ui/src/app/screens/file/pdf-viewer/pdf-viewer.component.ts b/apps/red-ui/src/app/screens/file/pdf-viewer/pdf-viewer.component.ts index f481245e8..008f4a7d5 100644 --- a/apps/red-ui/src/app/screens/file/pdf-viewer/pdf-viewer.component.ts +++ b/apps/red-ui/src/app/screens/file/pdf-viewer/pdf-viewer.component.ts @@ -9,13 +9,15 @@ import { Output, ViewChild } from '@angular/core'; -import { AppConfigKey, AppConfigService } from '../../../app-config/app-config.service'; -import { FileStatus, FileUploadControllerService } from '@redaction/red-ui-http'; -import { Observable, of } from 'rxjs'; -import { tap } from 'rxjs/operators'; -import WebViewer, { Annotations, WebViewerInstance } from '@pdftron/webviewer'; -import { TranslateService } from '@ngx-translate/core'; -import { ViewerSyncService } from '../service/viewer-sync.service'; +import {AppConfigKey, AppConfigService} from '../../../app-config/app-config.service'; +import {FileStatus, FileUploadControllerService, ManualRedactionEntry, Rectangle} from '@redaction/red-ui-http'; +import {Observable, of} from 'rxjs'; +import {tap} from 'rxjs/operators'; +import WebViewer, {Annotations, WebViewerInstance} from '@pdftron/webviewer'; +import {TranslateService} from '@ngx-translate/core'; +import {ViewerSyncService} from '../service/viewer-sync.service'; +import {MatDialog} from "@angular/material/dialog"; +import {ManualRedactionDialogComponent} from "../manual-redaction-dialog/manual-redaction-dialog.component"; export enum FileType { ORIGINAL = 'ORIGINAL', @@ -36,8 +38,9 @@ export class PdfViewerComponent implements OnInit, AfterViewInit, OnDestroy { @Output() fileReady = new EventEmitter(); @Output() annotationsAdded = new EventEmitter(); @Output() annotationSelected = new EventEmitter(); + @Output() manualAnnotationRequested = new EventEmitter(); - @ViewChild('viewer', { static: true }) viewer: ElementRef; + @ViewChild('viewer', {static: true}) viewer: ElementRef; wvInstance: WebViewerInstance; _fileData: Blob; @@ -46,6 +49,7 @@ export class PdfViewerComponent implements OnInit, AfterViewInit, OnDestroy { private readonly _viewerSyncService: ViewerSyncService, private readonly _translateService: TranslateService, private readonly _fileUploadControllerService: FileUploadControllerService, + private readonly _dialog: MatDialog, private readonly _appConfigService: AppConfigService) { } @@ -95,7 +99,7 @@ export class PdfViewerComponent implements OnInit, AfterViewInit, OnDestroy { })); instance.docViewer.on('documentLoaded', this.wvDocumentLoadedHandler); - instance.loadDocument(pdfBlob, { filename: this.fileStatus ? this.fileStatus.filename : 'file.pdf' }); + instance.loadDocument(pdfBlob, {filename: this.fileStatus ? this.fileStatus.filename : 'file.pdf'}); }); } @@ -145,11 +149,31 @@ export class PdfViewerComponent implements OnInit, AfterViewInit, OnDestroy { title: this._translateService.instant('pdf-viewer.text-popup.actions.suggestion-redaction.label'), onClick: () => { const selectedQuads = this.wvInstance.docViewer.getSelectedTextQuads(); - console.log(selectedQuads); + const text = this.wvInstance.docViewer.getSelectedText(); + const entry: ManualRedactionEntry = {positions: []}; + for (let key of Object.keys(selectedQuads)) { + for (let quad of selectedQuads[key]) { + entry.positions.push(this.toPosition(parseInt(key), quad)); + } + } + entry.value = text; + this.manualAnnotationRequested.emit(entry); } }); } + private toPosition(page: number, selectedQuad: any): Rectangle { + return { + page: page, + topLeft: { + x: selectedQuad.x4, + y: selectedQuad.y4 + }, + height: selectedQuad.y2 - selectedQuad.y4, + width: selectedQuad.x3 - selectedQuad.x4 + } + } + private _configureHeader() { this.wvInstance.setToolbarGroup('toolbarGroup-View'); } diff --git a/apps/red-ui/src/assets/i18n/en.json b/apps/red-ui/src/assets/i18n/en.json index 19a36062d..b7979b977 100644 --- a/apps/red-ui/src/assets/i18n/en.json +++ b/apps/red-ui/src/assets/i18n/en.json @@ -1,4 +1,38 @@ { + "manual-redaction": { + "dialog": { + "header": { + "label": "Add Manual Redaction" + }, + "add-redaction": { + "success": { + "label": "Redaction suggestion added!" + }, + "failed": { + "label": "Failed to add manual redaction: {{message}}" + } + }, + "actions": { + "save": { + "label": "Save Manual Redaction" + } + }, + "content": { + "text": { + "label": "Selected Text: {{value}}" + }, + "dictionary": { + "add": { + "label": "Add to dictionary" + }, + "label": "Dictionary" + }, + "reason": { + "label": "Reason" + } + } + } + }, "app-name": { "label": "Redacto" }, @@ -195,15 +229,12 @@ "name": { "label": "Name" }, - "added-on": { "label": "Added on" }, - "added-by": { "label": "Added by" }, - "assigned-to": { "label": "Assigned to" }, diff --git a/apps/red-ui/src/assets/styles/red-page-layout.scss b/apps/red-ui/src/assets/styles/red-page-layout.scss index fe7918429..1b617f45f 100644 --- a/apps/red-ui/src/assets/styles/red-page-layout.scss +++ b/apps/red-ui/src/assets/styles/red-page-layout.scss @@ -185,5 +185,5 @@ html, body { } .hidden { - display: none; + display: none !important; } diff --git a/docker/common/nginx/nginx.conf.template b/docker/common/nginx/nginx.conf.template index 255e7372a..47823c96d 100644 --- a/docker/common/nginx/nginx.conf.template +++ b/docker/common/nginx/nginx.conf.template @@ -17,6 +17,12 @@ server { location /project { proxy_pass $API_URL; } + location /dictionary { + proxy_pass $API_URL; + } + location /manualRedaction { + proxy_pass $API_URL; + } location /reanalyse { proxy_pass $API_URL; } diff --git a/libs/red-ui-http/src/lib/model/comment.ts b/libs/red-ui-http/src/lib/model/comment.ts new file mode 100644 index 000000000..4979a7f32 --- /dev/null +++ b/libs/red-ui-http/src/lib/model/comment.ts @@ -0,0 +1,17 @@ +/** + * API Documentation for Redaction Gateway + * Description for redaction + * + * OpenAPI spec version: 1.0 + * + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + +export interface Comment { + date?: string; + text?: string; + user?: string; +} \ No newline at end of file diff --git a/libs/red-ui-http/src/lib/model/idRemoval.ts b/libs/red-ui-http/src/lib/model/idRemoval.ts new file mode 100644 index 000000000..ca159e4e9 --- /dev/null +++ b/libs/red-ui-http/src/lib/model/idRemoval.ts @@ -0,0 +1,19 @@ +/** + * API Documentation for Redaction Gateway + * Description for redaction + * + * OpenAPI spec version: 1.0 + * + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ +import { Comment } from './comment'; + +export interface IdRemoval { + approved?: boolean; + comments?: Array; + id?: string; + removeFromDictionary?: boolean; +} \ No newline at end of file diff --git a/libs/red-ui-http/src/lib/model/manualRedactionEntry.ts b/libs/red-ui-http/src/lib/model/manualRedactionEntry.ts index 0fea08361..96425faa6 100644 --- a/libs/red-ui-http/src/lib/model/manualRedactionEntry.ts +++ b/libs/red-ui-http/src/lib/model/manualRedactionEntry.ts @@ -1,19 +1,23 @@ /** - * Api Documentation - * Api Documentation + * API Documentation for Redaction Gateway + * Description for redaction * * OpenAPI spec version: 1.0 - * + * * * NOTE: This class is auto generated by the swagger code generator program. * https://github.com/swagger-api/swagger-codegen.git * Do not edit the class manually. */ -import {Rectangle} from './rectangle'; +import { Comment } from './comment'; +import { Rectangle } from './rectangle'; -export interface ManualRedactionEntry { - positions?: Array; - reason?: string; - type?: string; - value?: string; -} +export interface ManualRedactionEntry { + addToDictionary?: boolean; + approved?: boolean; + comments?: Array; + positions?: Array; + reason?: string; + type?: string; + value?: string; +} \ No newline at end of file diff --git a/libs/red-ui-http/src/lib/model/manualRedactions.ts b/libs/red-ui-http/src/lib/model/manualRedactions.ts index 83eb29750..0fd9e31d0 100644 --- a/libs/red-ui-http/src/lib/model/manualRedactions.ts +++ b/libs/red-ui-http/src/lib/model/manualRedactions.ts @@ -1,17 +1,18 @@ /** - * Api Documentation - * Api Documentation + * API Documentation for Redaction Gateway + * Description for redaction * * OpenAPI spec version: 1.0 - * + * * * NOTE: This class is auto generated by the swagger code generator program. * https://github.com/swagger-api/swagger-codegen.git * Do not edit the class manually. */ -import {ManualRedactionEntry} from './manualRedactionEntry'; +import { IdRemoval } from './idRemoval'; +import { ManualRedactionEntry } from './manualRedactionEntry'; -export interface ManualRedactions { - entriesToAdd?: Array; - idsToRemove?: Array; -} +export interface ManualRedactions { + entriesToAdd?: Array; + idsToRemove?: Array; +} \ No newline at end of file diff --git a/libs/red-ui-http/src/lib/model/models.ts b/libs/red-ui-http/src/lib/model/models.ts index 993f7ea7f..b39dc5ce8 100644 --- a/libs/red-ui-http/src/lib/model/models.ts +++ b/libs/red-ui-http/src/lib/model/models.ts @@ -20,3 +20,5 @@ export * from './typeResponse'; export * from './typeValue'; export * from './fileUploadResult'; export * from './authInfo'; +export * from './comment'; +export * from './idRemoval';