RED-9747 add initial ws entity log refresh
This commit is contained in:
parent
2b00876e6b
commit
613a7429b8
@ -135,20 +135,20 @@ export const appModuleFactory = (config: AppConfig) => {
|
||||
features: {
|
||||
ANNOTATIONS: {
|
||||
color: 'aqua',
|
||||
enabled: true,
|
||||
enabled: false,
|
||||
level: NgxLoggerLevel.DEBUG,
|
||||
},
|
||||
FILTERS: {
|
||||
enabled: false,
|
||||
},
|
||||
TENANTS: {
|
||||
enabled: true,
|
||||
enabled: false,
|
||||
},
|
||||
ROUTES: {
|
||||
enabled: true,
|
||||
enabled: false,
|
||||
},
|
||||
PDF: {
|
||||
enabled: true,
|
||||
enabled: false,
|
||||
},
|
||||
FILE: {
|
||||
enabled: false,
|
||||
@ -171,6 +171,9 @@ export const appModuleFactory = (config: AppConfig) => {
|
||||
DOSSIERS_CHANGES: {
|
||||
enabled: false,
|
||||
},
|
||||
GUARDS: {
|
||||
enabled: false,
|
||||
},
|
||||
},
|
||||
} as ILoggerConfig,
|
||||
},
|
||||
|
||||
@ -51,6 +51,7 @@ export function ifLoggedIn(): AsyncGuard {
|
||||
const jwtToken = jwtDecode(token) as JwtToken;
|
||||
const authTime = (jwtToken.auth_time || jwtToken.iat).toString();
|
||||
localStorage.setItem('authTime', authTime);
|
||||
localStorage.setItem('token', token);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
import { ActivatedRouteSnapshot, NavigationExtras, Router, RouterLink } from '@angular/router';
|
||||
import { NgIf } from '@angular/common';
|
||||
import { ChangeDetectorRef, Component, effect, NgZone, OnDestroy, OnInit, TemplateRef, ViewChild } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot, NavigationExtras, Router, RouterLink } from '@angular/router';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { InitialsAvatarComponent } from '@common-ui/users';
|
||||
import { ComponentCanDeactivate } from '@guards/can-deactivate.guard';
|
||||
import {
|
||||
CircleButtonComponent,
|
||||
@ -18,10 +20,11 @@ import {
|
||||
Toaster,
|
||||
} from '@iqser/common-ui';
|
||||
import { copyLocalStorageFiltersValues, FilterService, NestedFilter, processFilters } from '@iqser/common-ui/lib/filtering';
|
||||
import { AutoUnsubscribe, Bind, bool, List, OnAttach, OnDetach } from '@iqser/common-ui/lib/utils';
|
||||
import { AutoUnsubscribe, Bind, bool, List, log, OnAttach, OnDetach } from '@iqser/common-ui/lib/utils';
|
||||
import { AnnotationWrapper } from '@models/file/annotation.wrapper';
|
||||
import { ManualRedactionEntryTypes, ManualRedactionEntryWrapper } from '@models/file/manual-redaction-entry.wrapper';
|
||||
import { Dictionary, File, ViewModes } from '@red/domain';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { AnalyseStatuses, AnalysisEvent, Dictionary, File, ViewModes, WsTopics } from '@red/domain';
|
||||
import { ConfigService } from '@services/config.service';
|
||||
import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service';
|
||||
import { DossiersService } from '@services/dossiers/dossiers.service';
|
||||
@ -29,10 +32,13 @@ import { FilesMapService } from '@services/files/files-map.service';
|
||||
import { FilesService } from '@services/files/files.service';
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
import { ReanalysisService } from '@services/reanalysis.service';
|
||||
import { WebSocketService } from '@services/web-socket.service';
|
||||
import { ProcessingIndicatorComponent } from '@shared/components/processing-indicator/processing-indicator.component';
|
||||
import { TypeFilterComponent } from '@shared/components/type-filter/type-filter.component';
|
||||
import { Roles } from '@users/roles';
|
||||
import { PreferencesKeys, UserPreferenceService } from '@users/user-preference.service';
|
||||
import { NGXLogger } from 'ngx-logger';
|
||||
import { combineLatest, first, firstValueFrom, Observable, of, pairwise } from 'rxjs';
|
||||
import { combineLatest, first, firstValueFrom, Observable, of, pairwise, Subscription } from 'rxjs';
|
||||
import { catchError, filter, map, startWith, switchMap, tap } from 'rxjs/operators';
|
||||
import { byId, byPage, handleFilterDelta, hasChanges } from '../../utils';
|
||||
import { AnnotationDrawService } from '../pdf-viewer/services/annotation-draw.service';
|
||||
@ -43,34 +49,29 @@ import { PdfViewer } from '../pdf-viewer/services/pdf-viewer.service';
|
||||
import { ReadableRedactionsService } from '../pdf-viewer/services/readable-redactions.service';
|
||||
import { ViewerHeaderService } from '../pdf-viewer/services/viewer-header.service';
|
||||
import { ROTATION_ACTION_BUTTONS, ViewerEvents } from '../pdf-viewer/utils/constants';
|
||||
import { FileActionsComponent } from '../shared-dossiers/components/file-actions/file-actions.component';
|
||||
import { FileHeaderComponent } from './components/file-header/file-header.component';
|
||||
import { FilePreviewRightContainerComponent } from './components/right-container/file-preview-right-container.component';
|
||||
import { StructuredComponentManagementComponent } from './components/structured-component-management/structured-component-management.component';
|
||||
import { UserManagementComponent } from './components/user-management/user-management.component';
|
||||
import { ViewSwitchComponent } from './components/view-switch/view-switch.component';
|
||||
import { AddHintDialogComponent } from './dialogs/add-hint-dialog/add-hint-dialog.component';
|
||||
import { AddAnnotationDialogComponent } from './dialogs/docu-mine/add-annotation-dialog/add-annotation-dialog.component';
|
||||
import { RedactTextDialogComponent } from './dialogs/redact-text-dialog/redact-text-dialog.component';
|
||||
import { filePreviewScreenProviders } from './file-preview-providers';
|
||||
import { AnnotationProcessingService } from './services/annotation-processing.service';
|
||||
import { AnnotationsListingService } from './services/annotations-listing.service';
|
||||
import { DocumentInfoService } from './services/document-info.service';
|
||||
import { FileDataService } from './services/file-data.service';
|
||||
import { FilePreviewDialogService } from './services/file-preview-dialog.service';
|
||||
import { FilePreviewStateService } from './services/file-preview-state.service';
|
||||
import { ManualRedactionService } from './services/manual-redaction.service';
|
||||
import { MultiSelectService } from './services/multi-select.service';
|
||||
import { PdfProxyService } from './services/pdf-proxy.service';
|
||||
import { SkippedService } from './services/skipped.service';
|
||||
import { StampService } from './services/stamp.service';
|
||||
import { ViewModeService } from './services/view-mode.service';
|
||||
import { RedactTextData } from './utils/dialog-types';
|
||||
import { MultiSelectService } from './services/multi-select.service';
|
||||
import { NgIf } from '@angular/common';
|
||||
import { ViewSwitchComponent } from './components/view-switch/view-switch.component';
|
||||
import { ProcessingIndicatorComponent } from '@shared/components/processing-indicator/processing-indicator.component';
|
||||
import { UserManagementComponent } from './components/user-management/user-management.component';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { InitialsAvatarComponent } from '@common-ui/users';
|
||||
import { FileActionsComponent } from '../shared-dossiers/components/file-actions/file-actions.component';
|
||||
import { FilePreviewRightContainerComponent } from './components/right-container/file-preview-right-container.component';
|
||||
import { TypeFilterComponent } from '@shared/components/type-filter/type-filter.component';
|
||||
import { FileHeaderComponent } from './components/file-header/file-header.component';
|
||||
import { StructuredComponentManagementComponent } from './components/structured-component-management/structured-component-management.component';
|
||||
import { DocumentInfoService } from './services/document-info.service';
|
||||
|
||||
@Component({
|
||||
templateUrl: './file-preview-screen.component.html',
|
||||
@ -96,17 +97,19 @@ import { DocumentInfoService } from './services/document-info.service';
|
||||
],
|
||||
})
|
||||
export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnInit, OnDestroy, OnAttach, OnDetach, ComponentCanDeactivate {
|
||||
readonly circleButtonTypes = CircleButtonTypes;
|
||||
readonly roles = Roles;
|
||||
readonly fileId = this.state.fileId;
|
||||
readonly dossierId = this.state.dossierId;
|
||||
@ViewChild('annotationFilterTemplate', {
|
||||
read: TemplateRef,
|
||||
static: false,
|
||||
})
|
||||
private readonly _filterTemplate: TemplateRef<unknown>;
|
||||
#loadAllAnnotationsEnabled = false;
|
||||
readonly #wsConnection$: Observable<unknown>;
|
||||
#wsConnectionSub: Subscription;
|
||||
protected readonly isDocumine = getConfig().IS_DOCUMINE;
|
||||
readonly circleButtonTypes = CircleButtonTypes;
|
||||
readonly roles = Roles;
|
||||
readonly fileId = this.state.fileId;
|
||||
readonly dossierId = this.state.dossierId;
|
||||
|
||||
constructor(
|
||||
readonly pdf: PdfViewer,
|
||||
@ -145,13 +148,31 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
|
||||
private readonly _dossierTemplatesService: DossierTemplatesService,
|
||||
private readonly _multiSelectService: MultiSelectService,
|
||||
private readonly _documentInfoService: DocumentInfoService,
|
||||
private readonly _webSocketService: WebSocketService,
|
||||
) {
|
||||
super();
|
||||
effect(() => {
|
||||
const file = this.state.file();
|
||||
this._fileDataService.loadAnnotations(file).then();
|
||||
console.log('FILE CHANGED');
|
||||
// this._fileDataService.loadAnnotations(file).then();
|
||||
});
|
||||
|
||||
this.#wsConnection$ = this._webSocketService.listen<AnalysisEvent>(WsTopics.ANALYSIS).pipe(
|
||||
log('[WS] Analysis events'),
|
||||
filter(event => event.analyseStatus === AnalyseStatuses.FINISHED),
|
||||
switchMap(event => this._fileDataService.updateAnnotations(this.state.file(), event.analysisNumber)),
|
||||
log('[CONNNEECCCCCTIIONSSS] Annotations updated'),
|
||||
);
|
||||
|
||||
const file = this.state.file();
|
||||
console.log(file);
|
||||
console.log(this._fileDataService.annotations());
|
||||
if (this._fileDataService.annotations().length) {
|
||||
firstValueFrom(this._fileDataService.updateAnnotations(file, file.numberOfAnalyses)).then();
|
||||
} else {
|
||||
this._fileDataService.loadAnnotations(file).then();
|
||||
}
|
||||
|
||||
effect(
|
||||
() => {
|
||||
if (this._documentViewer.loaded()) {
|
||||
@ -296,11 +317,13 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
|
||||
super.ngOnDetach();
|
||||
this.pdf.instance.UI.hotkeys.off('esc');
|
||||
this._changeRef.markForCheck();
|
||||
this.#wsConnectionSub.unsubscribe();
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.pdf.instance.UI.hotkeys.off('esc');
|
||||
super.ngOnDestroy();
|
||||
this.#wsConnectionSub.unsubscribe();
|
||||
}
|
||||
|
||||
@Bind()
|
||||
@ -339,6 +362,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
|
||||
}
|
||||
|
||||
async ngOnInit(): Promise<void> {
|
||||
this.#wsConnectionSub = this.#wsConnection$.subscribe();
|
||||
this.#updateViewerPosition();
|
||||
const file = this.state.file();
|
||||
|
||||
|
||||
@ -244,7 +244,6 @@ export class AnnotationActionsService {
|
||||
const text = annotation.AREA ? annotation.value : isImageText;
|
||||
const isApprover = this._permissionsService.isApprover(dossier);
|
||||
const dossierTemplate = this._dossierTemplatesService.find(this._state.dossierTemplateId);
|
||||
const isUnprocessed = annotation.pending;
|
||||
|
||||
const data: ResizeRedactionData = {
|
||||
redaction: annotation,
|
||||
@ -275,7 +274,7 @@ export class AnnotationActionsService {
|
||||
|
||||
await this.cancelResize(annotation);
|
||||
|
||||
const { fileId, dossierId, file } = this._state;
|
||||
const { fileId, dossierId } = this._state;
|
||||
const request = this._manualRedactionService.resize([resizeRequest], dossierId, fileId, includeUnprocessed);
|
||||
return this.#processObsAndEmit(request);
|
||||
}
|
||||
@ -321,7 +320,7 @@ export class AnnotationActionsService {
|
||||
}
|
||||
|
||||
async #processObsAndEmit(obs: Observable<unknown>) {
|
||||
await firstValueFrom(obs).finally(() => this._fileDataService.annotationsChanged());
|
||||
await firstValueFrom(obs.pipe(log('==>>[[[CHANGES]]]'))).finally(() => this._fileDataService.annotationsChanged());
|
||||
}
|
||||
|
||||
#getFalsePositiveText(annotation: AnnotationWrapper) {
|
||||
@ -443,9 +442,15 @@ export class AnnotationActionsService {
|
||||
// todo: might not be correct, probably shouldn't get to this point if they are not all the same
|
||||
const isHint = redactions.every(r => r.isHint);
|
||||
const { dossierId, fileId } = this._state;
|
||||
this.#processObsAndEmit(
|
||||
this._manualRedactionService.removeRedaction(body, dossierId, fileId, removeFromDictionary, isHint, includeUnprocessed),
|
||||
).then();
|
||||
const req$ = this._manualRedactionService.removeRedaction(
|
||||
body,
|
||||
dossierId,
|
||||
fileId,
|
||||
removeFromDictionary,
|
||||
isHint,
|
||||
includeUnprocessed,
|
||||
);
|
||||
this.#processObsAndEmit(req$).then(() => this._fileDataService.removeAnnotations(redactions.map(r => r.id)));
|
||||
}
|
||||
|
||||
#getRemoveRedactionDialog(data: RemoveRedactionData) {
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
import { effect, inject, Injectable, Signal, signal } from '@angular/core';
|
||||
import { effect, inject, Injectable, Signal, signal, WritableSignal } from '@angular/core';
|
||||
import { toObservable } from '@angular/core/rxjs-interop';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { TenantsService } from '@common-ui/tenants';
|
||||
import { log } from '@common-ui/utils';
|
||||
import { EntitiesService, getConfig, Toaster } from '@iqser/common-ui';
|
||||
import { AnnotationWrapper } from '@models/file/annotation.wrapper';
|
||||
import {
|
||||
@ -27,6 +29,7 @@ import { UserPreferenceService } from '@users/user-preference.service';
|
||||
import dayjs from 'dayjs';
|
||||
import { NGXLogger } from 'ngx-logger';
|
||||
import { firstValueFrom, Observable } from 'rxjs';
|
||||
import { switchMap, tap } from 'rxjs/operators';
|
||||
import { FilePreviewStateService } from './file-preview-state.service';
|
||||
import { MultiSelectService } from './multi-select.service';
|
||||
import { ViewModeService } from './view-mode.service';
|
||||
@ -43,13 +46,14 @@ export function chronologicallyBy<T>(property: (x: T) => string) {
|
||||
|
||||
@Injectable()
|
||||
export class FileDataService extends EntitiesService<AnnotationWrapper, AnnotationWrapper> {
|
||||
readonly #annotations = signal<AnnotationWrapper[]>([]);
|
||||
readonly #annotations: WritableSignal<AnnotationWrapper[]>;
|
||||
readonly #earmarks = signal<Map<number, AnnotationWrapper[]>>(new Map());
|
||||
#originalViewedPages: ViewedPage[] = [];
|
||||
readonly #isDocumine = getConfig().IS_DOCUMINE;
|
||||
readonly #logger = inject(NGXLogger);
|
||||
readonly #toaster = inject(Toaster);
|
||||
readonly #isIqserDevMode = inject(UserPreferenceService).isIqserDevMode;
|
||||
readonly #tenantsService = inject(TenantsService);
|
||||
protected readonly _entityClass = AnnotationWrapper;
|
||||
missingTypes = new Set<string>();
|
||||
readonly earmarks: Signal<Map<number, AnnotationWrapper[]>>;
|
||||
@ -70,9 +74,17 @@ export class FileDataService extends EntitiesService<AnnotationWrapper, Annotati
|
||||
private readonly _defaultColorsService: DefaultColorsService,
|
||||
) {
|
||||
super();
|
||||
const localStorageKey = this.#tenantsService.activeTenantId + '-annotations-' + this._state.fileId;
|
||||
this.#annotations = signal<AnnotationWrapper[]>(JSON.parse(localStorage.getItem(localStorageKey) || '[]'));
|
||||
this.annotations$ = toObservable(this.#annotations);
|
||||
this.annotations = this.#annotations.asReadonly();
|
||||
this.earmarks = this.#earmarks.asReadonly();
|
||||
|
||||
effect(() => {
|
||||
localStorage.setItem(localStorageKey, JSON.stringify(this.#annotations()));
|
||||
console.log('FileDataService#annotations', this.#annotations());
|
||||
});
|
||||
|
||||
effect(() => {
|
||||
const viewMode = this._viewModeService.viewMode();
|
||||
const earmarks = ([] as AnnotationWrapper[]).concat(...this.#earmarks().values());
|
||||
@ -81,6 +93,10 @@ export class FileDataService extends EntitiesService<AnnotationWrapper, Annotati
|
||||
});
|
||||
}
|
||||
|
||||
removeAnnotations(id: string[]) {
|
||||
this.#annotations.update(old => old.filter(annotation => !id.includes(annotation.id)));
|
||||
}
|
||||
|
||||
setEntities(entities: AnnotationWrapper[]): void {
|
||||
// this is a light version of setEntities to skip looping too much
|
||||
// used mostly for earmarks (which are usually a lot)
|
||||
@ -119,7 +135,8 @@ export class FileDataService extends EntitiesService<AnnotationWrapper, Annotati
|
||||
const file = this._state.file();
|
||||
const fileReloaded = await this._filesService.reload(file.dossierId, file);
|
||||
if (!fileReloaded) {
|
||||
await this.loadAnnotations(file);
|
||||
await this.#loadViewedPages(file);
|
||||
// await this.loadAnnotations(file);
|
||||
}
|
||||
}
|
||||
|
||||
@ -136,10 +153,37 @@ export class FileDataService extends EntitiesService<AnnotationWrapper, Annotati
|
||||
const redactionLog = await this._entityLogService.getEntityLog(this._state.dossierId, this._state.fileId);
|
||||
|
||||
this.#logger.info('[REDACTION_LOG] Redaction log loaded', redactionLog);
|
||||
let annotations = await this.#convertData(redactionLog);
|
||||
const annotations = await this.processEntityLog(redactionLog);
|
||||
this.#annotations.update(old => {
|
||||
const notUpdated = old.filter(oldAnnotation => {
|
||||
return !annotations.some(newAnnotation => newAnnotation.id === oldAnnotation.id);
|
||||
});
|
||||
return [...notUpdated, ...annotations].sort((a, b) => a.positions[0].page - b.positions[0].page);
|
||||
});
|
||||
}
|
||||
|
||||
async processEntityLog(entityLog: IEntityLog) {
|
||||
let annotations = await this.#convertData(entityLog);
|
||||
this.#checkMissingTypes();
|
||||
annotations = this.#isIqserDevMode ? annotations : annotations.filter(a => !a.isFalsePositive);
|
||||
this.#annotations.set(annotations);
|
||||
|
||||
return this.#isIqserDevMode ? annotations : annotations.filter(a => !a.isFalsePositive);
|
||||
}
|
||||
|
||||
updateAnnotations(file: File, analysisNumber: number) {
|
||||
const delta$ = this._entityLogService.getDelta(file.dossierId, file.fileId, analysisNumber);
|
||||
return delta$.pipe(
|
||||
log('[REDACTION_LOG] Delta loaded'),
|
||||
switchMap(delta => this.processEntityLog(delta)),
|
||||
tap(annotations => {
|
||||
this.#annotations.update(old => {
|
||||
const notUpdated = old.filter(oldAnnotation => {
|
||||
return !oldAnnotation.pending && !annotations.some(newAnnotation => newAnnotation.id === oldAnnotation.id);
|
||||
});
|
||||
return [...notUpdated, ...annotations].sort((a, b) => a.positions[0].page - b.positions[0].page);
|
||||
});
|
||||
}),
|
||||
tap(() => this.#logger.info('[REDACTION_LOG] Annotations updated', this.#annotations())),
|
||||
);
|
||||
}
|
||||
|
||||
#checkMissingTypes() {
|
||||
|
||||
@ -1,15 +1,15 @@
|
||||
import { inject, Injectable } from '@angular/core';
|
||||
import { GenericService, isIqserDevMode, Toaster } from '@iqser/common-ui';
|
||||
import { GenericService, Toaster } from '@iqser/common-ui';
|
||||
import { EntryStates, IEntityLog, IEntityLogEntry, ISectionGrid } from '@red/domain';
|
||||
import { firstValueFrom, of } from 'rxjs';
|
||||
import { catchError } from 'rxjs/operators';
|
||||
import { catchError, map } from 'rxjs/operators';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class EntityLogService extends GenericService<unknown> {
|
||||
protected readonly _defaultModelPath = '';
|
||||
readonly #toaster = inject(Toaster);
|
||||
protected readonly _defaultModelPath = '';
|
||||
|
||||
async getEntityLog(dossierId: string, fileId: string) {
|
||||
const queryParams = [{ key: 'includeUnprocessed', value: true }];
|
||||
@ -20,6 +20,17 @@ export class EntityLogService extends GenericService<unknown> {
|
||||
return entityLog;
|
||||
}
|
||||
|
||||
getDelta(dossierId: string, fileId: string, analysisNumber: number) {
|
||||
const req$ = this._getOne<IEntityLog>([dossierId, fileId, analysisNumber.toString()], 'entityLog');
|
||||
return req$.pipe(
|
||||
map(entityLog => {
|
||||
entityLog.entityLogEntry = this.#filterInvalidEntries(entityLog.entityLogEntry);
|
||||
return entityLog;
|
||||
}),
|
||||
catchError(() => of({} as IEntityLog)),
|
||||
);
|
||||
}
|
||||
|
||||
getSectionGrid(dossierId: string, fileId: string) {
|
||||
return this._getOne<ISectionGrid>([dossierId, fileId], 'sectionGrid');
|
||||
}
|
||||
|
||||
60
apps/red-ui/src/app/services/web-socket.service.ts
Normal file
60
apps/red-ui/src/app/services/web-socket.service.ts
Normal file
@ -0,0 +1,60 @@
|
||||
import { inject, Injectable } from '@angular/core';
|
||||
import { TenantsService } from '@common-ui/tenants';
|
||||
import { log } from '@common-ui/utils';
|
||||
import { getConfig } from '@iqser/common-ui';
|
||||
import { IMessage, IWatchParams, RxStomp } from '@stomp/rx-stomp';
|
||||
import { StompHeaders } from '@stomp/stompjs';
|
||||
|
||||
import { NGXLogger } from 'ngx-logger';
|
||||
import { Observable } from 'rxjs';
|
||||
import { map, tap } from 'rxjs/operators';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class WebSocketService extends RxStomp {
|
||||
readonly #logger = inject(NGXLogger);
|
||||
readonly #config = getConfig();
|
||||
readonly #tenantService = inject(TenantsService);
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
setTimeout(() => this.connect(), 1000);
|
||||
}
|
||||
|
||||
watch(opts: IWatchParams): Observable<IMessage>;
|
||||
watch(destination: string, headers?: StompHeaders): Observable<IMessage>;
|
||||
watch(opts: string | IWatchParams, headers?: StompHeaders): Observable<IMessage> {
|
||||
if (typeof opts === 'string') {
|
||||
return super.watch('/topic/' + this.#tenantService.activeTenantId + '/' + opts, headers);
|
||||
}
|
||||
|
||||
return super.watch(opts);
|
||||
}
|
||||
|
||||
listen<T>(topic: string): Observable<T> {
|
||||
return this.watch(topic).pipe(map(msg => JSON.parse(msg.body)));
|
||||
}
|
||||
|
||||
private connect() {
|
||||
const headers = { Authorization: 'Bearer ' + localStorage.getItem('token') };
|
||||
this.configure({
|
||||
debug: (msg: string) => this.#logger.debug(msg),
|
||||
brokerURL: this.#config.API_URL + '/redaction-gateway-v1/websocket',
|
||||
connectHeaders: headers,
|
||||
});
|
||||
this.connectionState$.pipe(log('[WS] Connection state')).subscribe();
|
||||
this.webSocketErrors$.pipe(log('[WS] Errors')).subscribe();
|
||||
this.stompErrors$
|
||||
.pipe(
|
||||
tap(frame => {
|
||||
console.error(frame);
|
||||
console.error('Broker reported error: ' + frame.headers['message']);
|
||||
console.error('Additional details: ' + frame.body);
|
||||
}),
|
||||
)
|
||||
.subscribe();
|
||||
|
||||
this.activate();
|
||||
}
|
||||
}
|
||||
@ -31,3 +31,4 @@ export * from './lib/colors';
|
||||
export * from './lib/component-log';
|
||||
export * from './lib/component-mappings';
|
||||
export * from './lib/component-definitions';
|
||||
export * from './lib/web-socket';
|
||||
|
||||
16
libs/red-domain/src/lib/web-socket/analysis-event.ts
Normal file
16
libs/red-domain/src/lib/web-socket/analysis-event.ts
Normal file
@ -0,0 +1,16 @@
|
||||
export const AnalyseStatuses = {
|
||||
PROCESSING: 'PROCESSING',
|
||||
FINISHED: 'FINISHED',
|
||||
} as const;
|
||||
|
||||
export type AnalyseStatus = keyof typeof AnalyseStatuses;
|
||||
|
||||
export interface AnalysisEvent {
|
||||
analyseStatus: AnalyseStatus;
|
||||
analysisNumber: number;
|
||||
dossierId: string;
|
||||
fileId: string;
|
||||
numberOfOCRedPages: number;
|
||||
numberOfPagesToOCR: number;
|
||||
timestamp: string;
|
||||
}
|
||||
2
libs/red-domain/src/lib/web-socket/index.ts
Normal file
2
libs/red-domain/src/lib/web-socket/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export * from './analysis-event';
|
||||
export * from './topics';
|
||||
3
libs/red-domain/src/lib/web-socket/topics.ts
Normal file
3
libs/red-domain/src/lib/web-socket/topics.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export const WsTopics = {
|
||||
ANALYSIS: 'analysis-events',
|
||||
} as const;
|
||||
@ -35,12 +35,14 @@
|
||||
"@ngx-translate/core": "15.0.0",
|
||||
"@ngx-translate/http-loader": "8.0.0",
|
||||
"@pdftron/webviewer": "10.10.1",
|
||||
"@stomp/rx-stomp": "^2.0.0",
|
||||
"@stomp/stompjs": "^7.0.0",
|
||||
"chart.js": "4.4.3",
|
||||
"dayjs": "1.11.11",
|
||||
"file-saver": "^2.0.5",
|
||||
"jszip": "^3.10.1",
|
||||
"jwt-decode": "^4.0.0",
|
||||
"keycloak-angular": "15.1.0",
|
||||
"keycloak-angular": "16.0.1",
|
||||
"keycloak-js": "23.0.1",
|
||||
"lodash-es": "^4.17.21",
|
||||
"monaco-editor": "0.49.0",
|
||||
@ -100,5 +102,6 @@
|
||||
"webpack": "5.92.0",
|
||||
"webpack-bundle-analyzer": "4.10.2",
|
||||
"xliff": "^6.2.1"
|
||||
}
|
||||
},
|
||||
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
|
||||
}
|
||||
|
||||
18
yarn.lock
18
yarn.lock
@ -3396,6 +3396,16 @@
|
||||
dependencies:
|
||||
"@sinonjs/commons" "^3.0.0"
|
||||
|
||||
"@stomp/rx-stomp@^2.0.0":
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@stomp/rx-stomp/-/rx-stomp-2.0.0.tgz#5d75c87db280d2af9da7fccd3478c682df312065"
|
||||
integrity sha512-3UxTxAA3NWGnwFfIvN8AigJ7BxGXG0u5IK8K12mQ9cCMuaT/MM7xlyZnuV8sDbHiqqLlbwA1wk1fDfUyOTIeug==
|
||||
|
||||
"@stomp/stompjs@^7.0.0":
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@stomp/stompjs/-/stompjs-7.0.0.tgz#46b5c454a9dc8262e0b20f3b3dbacaa113993077"
|
||||
integrity sha512-fGdq4wPDnSV/KyOsjq4P+zLc8MFWC3lMmP5FBgLWKPJTYcuCbAIrnRGjB7q2jHZdYCOD5vxLuFoKIYLy5/u8Pw==
|
||||
|
||||
"@tootallnate/once@2":
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf"
|
||||
@ -7442,10 +7452,10 @@ karma-source-map-support@1.4.0:
|
||||
dependencies:
|
||||
source-map-support "^0.5.5"
|
||||
|
||||
keycloak-angular@15.1.0:
|
||||
version "15.1.0"
|
||||
resolved "https://registry.yarnpkg.com/keycloak-angular/-/keycloak-angular-15.1.0.tgz#56d25025ace2596ea8265e7158b66b2fb20054d1"
|
||||
integrity sha512-9Wz1jEalUXeq3v88MMYEcFnF2GwUht1slMbDau8lpNEe0Wp9xcv5/NpMUP0RjsHKmNg8cX47BUsxL27Ypy7pmA==
|
||||
keycloak-angular@16.0.1:
|
||||
version "16.0.1"
|
||||
resolved "https://registry.yarnpkg.com/keycloak-angular/-/keycloak-angular-16.0.1.tgz#9dd30e36d5320db35cf1bdb681be5552ba1104ce"
|
||||
integrity sha512-ytkL32R/tfHEyZ3txQtgH1y0WofW/D36zTbo2agDCYUtZETq0wAQ3E/4bVDUAr6ZKwotgAnIyOORfErnvDkXng==
|
||||
dependencies:
|
||||
tslib "^2.3.1"
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user