Merge branch 'dan' into 'master'
RED-3800 ng update See merge request redactmanager/red-ui!213
This commit is contained in:
commit
0a32b8f5bd
@ -122,11 +122,11 @@
|
||||
"serve": {
|
||||
"builder": "@angular-devkit/build-angular:dev-server",
|
||||
"options": {
|
||||
"browserTarget": "red-ui:build"
|
||||
"buildTarget": "red-ui:build"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"browserTarget": "red-ui:build:production"
|
||||
"buildTarget": "red-ui:build:production"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
5
apps/red-ui/src/app/guards/guards-utils.ts
Normal file
5
apps/red-ui/src/app/guards/guards-utils.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export function getRouteTenant() {
|
||||
const pathParams = location.pathname.split('/').filter(Boolean);
|
||||
const uiPathIndex = pathParams.indexOf('ui');
|
||||
return pathParams[uiPathIndex + 1];
|
||||
}
|
||||
@ -1,12 +1,13 @@
|
||||
import { ActivatedRouteSnapshot, Router } from '@angular/router';
|
||||
import { inject } from '@angular/core';
|
||||
import { NGXLogger } from 'ngx-logger';
|
||||
import { keycloakInitializer, KeycloakStatusService, TenantsService } from '@iqser/common-ui/lib/tenants';
|
||||
import { KeycloakService } from 'keycloak-angular';
|
||||
import { UserService } from '@users/user.service';
|
||||
import { LicenseService } from '@services/license.service';
|
||||
import { ActivatedRouteSnapshot, Router } from '@angular/router';
|
||||
import { getRouteTenant } from '@guards/guards-utils';
|
||||
import { AsyncGuard } from '@iqser/common-ui';
|
||||
import jwt_decode from 'jwt-decode';
|
||||
import { keycloakInitializer, KeycloakStatusService, TenantsService } from '@iqser/common-ui/lib/tenants';
|
||||
import { LicenseService } from '@services/license.service';
|
||||
import { UserService } from '@users/user.service';
|
||||
import { jwtDecode } from 'jwt-decode';
|
||||
import { KeycloakService } from 'keycloak-angular';
|
||||
import { NGXLogger } from 'ngx-logger';
|
||||
|
||||
export interface JwtToken {
|
||||
auth_time: number;
|
||||
@ -25,9 +26,7 @@ export function ifLoggedIn(): AsyncGuard {
|
||||
const keycloakStatusService = inject(KeycloakStatusService);
|
||||
|
||||
const keycloakInstance = keycloakService.getKeycloakInstance();
|
||||
const pathParams = location.pathname.split('/').filter(Boolean);
|
||||
const uiPathIndex = pathParams.indexOf('ui');
|
||||
const tenant = pathParams[uiPathIndex + 1];
|
||||
const tenant = getRouteTenant();
|
||||
const queryParams = new URLSearchParams(window.location.search);
|
||||
const username = queryParams.get('username');
|
||||
const router = inject(Router);
|
||||
@ -48,15 +47,13 @@ export function ifLoggedIn(): AsyncGuard {
|
||||
|
||||
const token = await keycloakService.getToken();
|
||||
if (token) {
|
||||
const jwtToken = jwt_decode(token) as JwtToken;
|
||||
const jwtToken = jwtDecode(token) as JwtToken;
|
||||
const authTime = (jwtToken.auth_time || jwtToken.iat).toString();
|
||||
localStorage.setItem('authTime', authTime);
|
||||
}
|
||||
}
|
||||
|
||||
const isLoggedIn = await keycloakService.isLoggedIn();
|
||||
|
||||
if (isLoggedIn) {
|
||||
if (keycloakService.isLoggedIn()) {
|
||||
logger.info('[ROUTES] Is logged in, continuing');
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1,17 +1,24 @@
|
||||
import { CanActivateFn, Router } from '@angular/router';
|
||||
import { inject } from '@angular/core';
|
||||
import { NGXLogger } from 'ngx-logger';
|
||||
import { CanActivateFn, Router } from '@angular/router';
|
||||
import { getRouteTenant } from '@guards/guards-utils';
|
||||
import { KeycloakService } from 'keycloak-angular';
|
||||
import { NGXLogger } from 'ngx-logger';
|
||||
|
||||
export function ifNotLoggedIn(): CanActivateFn {
|
||||
return async () => {
|
||||
const logger = inject(NGXLogger);
|
||||
const router = inject(Router);
|
||||
const keycloakService = inject(KeycloakService);
|
||||
if (!keycloakService.getKeycloakInstance()) {
|
||||
const tenant = getRouteTenant();
|
||||
if (tenant) {
|
||||
logger.warn('[ROUTES] Tenant ' + tenant + ' found in route, redirecting to /main');
|
||||
await router.navigate(['main']);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const isLoggedIn = await keycloakService.isLoggedIn();
|
||||
|
||||
if (!isLoggedIn) {
|
||||
if (!keycloakService.isLoggedIn()) {
|
||||
logger.info('[ROUTES] Not logged in, continuing to selected route');
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -34,11 +34,15 @@ export const canChangeLegalBasis = (annotation: AnnotationWrapper, canAddRedacti
|
||||
export const canRecategorizeAnnotation = (annotation: AnnotationWrapper, canRecategorize: boolean) =>
|
||||
canRecategorize && (annotation.isImage || annotation.isDictBasedHint) && !annotation.pending;
|
||||
|
||||
export const canResizeAnnotation = (annotation: AnnotationWrapper, canAddRedaction: boolean) =>
|
||||
export const canResizeAnnotation = (annotation: AnnotationWrapper, canAddRedaction: boolean, hasDictionary = false) =>
|
||||
canAddRedaction &&
|
||||
!annotation.isSkipped &&
|
||||
!annotation.pending &&
|
||||
(annotation.isRedacted || annotation.isImage || annotation.isDictBasedHint || annotation.isRecommendation);
|
||||
(annotation.isRedacted ||
|
||||
annotation.isImage ||
|
||||
annotation.isDictBasedHint ||
|
||||
annotation.isRecommendation ||
|
||||
(hasDictionary && annotation.isRuleBased));
|
||||
|
||||
export const canEditAnnotation = (annotation: AnnotationWrapper) => (annotation.isRedacted || annotation.isSkipped) && !annotation.isImage;
|
||||
|
||||
|
||||
@ -62,7 +62,7 @@ export class AnnotationPermissions {
|
||||
permissions.canRemoveRedaction = canRemoveRedaction(annotation, permissions);
|
||||
permissions.canChangeLegalBasis = canChangeLegalBasis(annotation, canAddRedaction);
|
||||
permissions.canRecategorizeAnnotation = canRecategorizeAnnotation(annotation, canAddRedaction);
|
||||
permissions.canResizeAnnotation = canResizeAnnotation(annotation, canAddRedaction);
|
||||
permissions.canResizeAnnotation = canResizeAnnotation(annotation, canAddRedaction, annotationEntity.hasDictionary);
|
||||
permissions.canEditAnnotations = canEditAnnotation(annotation);
|
||||
permissions.canEditHints = canEditHint(annotation);
|
||||
permissions.canEditImages = canEditImage(annotation);
|
||||
|
||||
@ -61,6 +61,10 @@ export class AnnotationWrapper implements IListable {
|
||||
hasBeenRemovedByManualOverride: boolean;
|
||||
isRemoved = false;
|
||||
|
||||
get isRuleBased() {
|
||||
return this.engines.includes(LogEntryEngines.RULE);
|
||||
}
|
||||
|
||||
get searchKey(): string {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
import { ChangeDetectionStrategy, Component, HostListener, ViewChild } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { getConfig, IconButtonTypes } from '@iqser/common-ui';
|
||||
import { IqserEventTarget } from '@iqser/common-ui/lib/utils';
|
||||
import { Dictionary, DOSSIER_TEMPLATE_ID, ENTITY_TYPE } from '@red/domain';
|
||||
import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { getCurrentUser } from '@users/user.service';
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
import { AddEditEntityComponent } from '@shared/components/add-edit-entity/add-edit-entity.component';
|
||||
import { getConfig, IconButtonTypes } from '@iqser/common-ui';
|
||||
import { getCurrentUser } from '@users/user.service';
|
||||
import { Observable } from 'rxjs';
|
||||
import { IqserEventTarget } from '@iqser/common-ui/lib/utils';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-entity-info',
|
||||
@ -23,7 +23,11 @@ export class EntityInfoComponent {
|
||||
readonly config = getConfig();
|
||||
readonly iconButtonTypes = IconButtonTypes;
|
||||
|
||||
constructor(route: ActivatedRoute, dictionariesMapService: DictionariesMapService, readonly permissionsService: PermissionsService) {
|
||||
constructor(
|
||||
route: ActivatedRoute,
|
||||
dictionariesMapService: DictionariesMapService,
|
||||
readonly permissionsService: PermissionsService,
|
||||
) {
|
||||
this.dossierTemplateId = route.parent.snapshot.paramMap.get(DOSSIER_TEMPLATE_ID);
|
||||
const entityType = route.parent.snapshot.paramMap.get(ENTITY_TYPE);
|
||||
this.entity$ = dictionariesMapService.watch$(this.dossierTemplateId, entityType);
|
||||
|
||||
@ -43,6 +43,15 @@ import Quad = Core.Math.Quad;
|
||||
|
||||
@Injectable()
|
||||
export class PdfProxyService {
|
||||
readonly #convertPath = inject(UI_ROOT_PATH_FN);
|
||||
readonly #visibilityOffIcon = this.#convertPath('/assets/icons/general/visibility-off.svg');
|
||||
readonly #visibilityIcon = this.#convertPath('/assets/icons/general/visibility.svg');
|
||||
readonly #falsePositiveIcon = this.#convertPath('/assets/icons/general/pdftron-action-false-positive.svg');
|
||||
readonly #addRedactionIcon = this._iqserPermissionsService.has(Roles.getRss)
|
||||
? this.#convertPath('/assets/icons/general/pdftron-action-add-annotation.svg')
|
||||
: this.#convertPath('/assets/icons/general/pdftron-action-add-redaction.svg');
|
||||
readonly #isDocumine = getConfig().IS_DOCUMINE;
|
||||
readonly #addHintIcon = this.#convertPath('/assets/icons/general/pdftron-action-add-hint.svg');
|
||||
readonly annotationSelected$ = this.#annotationSelected$;
|
||||
readonly manualAnnotationRequested$ = new Subject<ManualRedactionEntryWrapper>();
|
||||
readonly redactTextRequested$ = new Subject<ManualRedactionEntryWrapper>();
|
||||
@ -61,15 +70,6 @@ export class PdfProxyService {
|
||||
const isAllowed = this._permissionsService.canPerformAnnotationActions(this._state.file(), this._state.dossier());
|
||||
return isAllowed && isStandard;
|
||||
});
|
||||
readonly #convertPath = inject(UI_ROOT_PATH_FN);
|
||||
readonly #visibilityOffIcon = this.#convertPath('/assets/icons/general/visibility-off.svg');
|
||||
readonly #visibilityIcon = this.#convertPath('/assets/icons/general/visibility.svg');
|
||||
readonly #falsePositiveIcon = this.#convertPath('/assets/icons/general/pdftron-action-false-positive.svg');
|
||||
readonly #addRedactionIcon = this._iqserPermissionsService.has(Roles.getRss)
|
||||
? this.#convertPath('/assets/icons/general/pdftron-action-add-annotation.svg')
|
||||
: this.#convertPath('/assets/icons/general/pdftron-action-add-redaction.svg');
|
||||
readonly #isDocumine = getConfig().IS_DOCUMINE;
|
||||
readonly #addHintIcon = this.#convertPath('/assets/icons/general/pdftron-action-add-hint.svg');
|
||||
|
||||
constructor(
|
||||
private readonly _translateService: TranslateService,
|
||||
@ -351,6 +351,7 @@ export class PdfProxyService {
|
||||
|
||||
#configureAnnotationSpecificActions(viewerAnnotations: Annotation[]) {
|
||||
if (!this.canPerformActions()) {
|
||||
this._pdf.instance.UI.annotationPopup.update([]);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@ import { Dictionary, IDictionary } from '@red/domain';
|
||||
import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service';
|
||||
import { DictionaryService } from '@services/entity-services/dictionary.service';
|
||||
import { toSnakeCase } from '@utils/functions';
|
||||
import { firstValueFrom, Observable } from 'rxjs';
|
||||
import { Observable } from 'rxjs';
|
||||
import { map, startWith } from 'rxjs/operators';
|
||||
|
||||
const REDACTION_FIELDS = ['defaultReason'];
|
||||
@ -20,7 +20,7 @@ interface Color {
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-add-edit-entity [entity] [dossierTemplateId]',
|
||||
selector: 'redaction-add-edit-entity',
|
||||
templateUrl: './add-edit-entity.component.html',
|
||||
styleUrls: ['./add-edit-entity.component.scss'],
|
||||
})
|
||||
@ -82,16 +82,13 @@ export class AddEditEntityComponent extends BaseFormComponent implements OnInit
|
||||
async save(): Promise<void> {
|
||||
this._loadingService.start();
|
||||
const dictionary = this.#formToObject();
|
||||
const isEditMode = !!this.entity;
|
||||
try {
|
||||
if (this.entity) {
|
||||
// edit mode
|
||||
await firstValueFrom(
|
||||
this._dictionaryService.updateDictionary(dictionary, this.dossierTemplateId, dictionary.type, this.dossierId),
|
||||
);
|
||||
if (isEditMode) {
|
||||
await this._dictionaryService.update(dictionary, this.dossierTemplateId, dictionary.type, this.dossierId);
|
||||
this._toaster.success(_('add-edit-entity.success.edit'));
|
||||
} else {
|
||||
// create mode
|
||||
await firstValueFrom(this._dictionaryService.addDictionary({ ...dictionary, dossierTemplateId: this.dossierTemplateId }));
|
||||
await this._dictionaryService.add({ ...dictionary, dossierTemplateId: this.dossierTemplateId });
|
||||
this._toaster.success(_('add-edit-entity.success.create'));
|
||||
}
|
||||
this.initialFormValue = this.form.getRawValue();
|
||||
@ -149,7 +146,7 @@ export class AddEditEntityComponent extends BaseFormComponent implements OnInit
|
||||
caseSensitive: [{ value: !this.entity?.caseInsensitive, disabled: this.#isSystemManaged }],
|
||||
manageEntriesInDictionaryEditorOnly: [
|
||||
{
|
||||
value: !this.entity?.addToDictionaryAction,
|
||||
value: this.entity?.addToDictionaryAction,
|
||||
disabled: this.#isSystemManaged && !this.#isDossierRedaction,
|
||||
},
|
||||
],
|
||||
@ -216,7 +213,7 @@ export class AddEditEntityComponent extends BaseFormComponent implements OnInit
|
||||
|
||||
#formToObject(): IDictionary {
|
||||
// Fields which aren't set for hints, need additional check
|
||||
const addToDictionaryAction = !this.form.get('manageEntriesInDictionaryEditorOnly')?.value;
|
||||
const addToDictionaryAction = !!this.form.get('manageEntriesInDictionaryEditorOnly')?.value;
|
||||
const hasDictionary = !!this.form.get('hasDictionary')?.value;
|
||||
const dossierDictionaryOnly = !!this.form.get('dossierDictionaryOnly')?.value;
|
||||
|
||||
|
||||
@ -39,10 +39,6 @@ export class DictionaryService extends EntitiesService<IDictionary, Dictionary>
|
||||
return firstValueFrom(this._getOne([type, dossierTemplateId], this._defaultModelPath, queryParams));
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes entry types
|
||||
*/
|
||||
|
||||
deleteDictionaries(dictionaryIds: List, dossierTemplateId: string, dossierId?: string): Observable<unknown> {
|
||||
const queryParams = dossierId ? [{ key: 'dossierId', value: dossierId }] : undefined;
|
||||
const url = `${this._defaultModelPath}/type/${dossierTemplateId}/delete`;
|
||||
@ -52,10 +48,6 @@ export class DictionaryService extends EntitiesService<IDictionary, Dictionary>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve all entry types
|
||||
*/
|
||||
|
||||
getAllDictionaries(dossierTemplateId: string, dossierId?: string) {
|
||||
const queryParams = dossierId ? [{ key: 'dossierId', value: dossierId }] : undefined;
|
||||
return this._getOne<{ types: IDictionary[] }>(['type', dossierTemplateId], this._defaultModelPath, queryParams);
|
||||
@ -65,27 +57,27 @@ export class DictionaryService extends EntitiesService<IDictionary, Dictionary>
|
||||
* Updates colors, hint and caseInsensitive of an entry type.
|
||||
*/
|
||||
|
||||
updateDictionary(body: IUpdateDictionary, dossierTemplateId: string, type: string, dossierId?: string): Observable<unknown> {
|
||||
async update(body: IUpdateDictionary, dossierTemplateId: string, type: string, dossierId?: string): Promise<unknown> {
|
||||
const url = `${this._defaultModelPath}/type/${type}/${dossierTemplateId}`;
|
||||
const queryParams = dossierId ? [{ key: 'dossierId', value: dossierId }] : undefined;
|
||||
return this._post(body, url, queryParams).pipe(
|
||||
const request = this._post(body, url, queryParams).pipe(
|
||||
catchError((error: unknown) => this.#addUpdateDictionaryErrorToast(error)),
|
||||
switchMap(() => this.loadDictionaryDataForDossierTemplate(dossierTemplateId)),
|
||||
switchMap(() => this._dossierTemplateStatsService.getFor([dossierTemplateId])),
|
||||
);
|
||||
|
||||
return await firstValueFrom(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates entry type with colors, hint and caseInsensitive
|
||||
*/
|
||||
|
||||
addDictionary(dictionary: IDictionary, dossierId?: string): Observable<unknown> {
|
||||
async add(dictionary: IDictionary, dossierId?: string): Promise<unknown> {
|
||||
const queryParams = dossierId ? [{ key: 'dossierId', value: dossierId }] : undefined;
|
||||
return this._post(dictionary, `${this._defaultModelPath}/type`, queryParams).pipe(
|
||||
const request = this._post(dictionary, `${this._defaultModelPath}/type`, queryParams).pipe(
|
||||
catchError((error: unknown) => this.#addUpdateDictionaryErrorToast(error)),
|
||||
switchMap(() => this.loadDictionaryDataForDossierTemplate(dictionary.dossierTemplateId)),
|
||||
switchMap(() => this._dossierTemplateStatsService.getFor([dictionary.dossierTemplateId])),
|
||||
);
|
||||
|
||||
return await firstValueFrom(request);
|
||||
}
|
||||
|
||||
async saveEntries(
|
||||
@ -118,10 +110,10 @@ export class DictionaryService extends EntitiesService<IDictionary, Dictionary>
|
||||
|
||||
try {
|
||||
if (deletedEntries.length) {
|
||||
await this._deleteEntries(deletedEntries, dossierTemplateId, type, dictionaryEntryType, dossierId);
|
||||
await this.#deleteEntries(deletedEntries, dossierTemplateId, type, dictionaryEntryType, dossierId);
|
||||
}
|
||||
if (entriesToAdd.length) {
|
||||
await this._addEntries(entriesToAdd, dossierTemplateId, type, dictionaryEntryType, dossierId);
|
||||
await this.#addEntries(entriesToAdd, dossierTemplateId, type, dictionaryEntryType, dossierId);
|
||||
}
|
||||
|
||||
if (showToast) {
|
||||
@ -284,13 +276,7 @@ export class DictionaryService extends EntitiesService<IDictionary, Dictionary>
|
||||
* Add dictionary entries with entry type.
|
||||
*/
|
||||
|
||||
private _addEntries(
|
||||
entries: List,
|
||||
dossierTemplateId: string,
|
||||
type: string,
|
||||
dictionaryEntryType: DictionaryEntryType,
|
||||
dossierId: string,
|
||||
) {
|
||||
#addEntries(entries: List, dossierTemplateId: string, type: string, dictionaryEntryType: DictionaryEntryType, dossierId: string) {
|
||||
const queryParams: List<QueryParam> = [
|
||||
{ key: 'dossierId', value: dossierId },
|
||||
{ key: 'dictionaryEntryType', value: dictionaryEntryType },
|
||||
@ -303,13 +289,7 @@ export class DictionaryService extends EntitiesService<IDictionary, Dictionary>
|
||||
* Delete dictionary entries with entry type.
|
||||
*/
|
||||
|
||||
private _deleteEntries(
|
||||
entries: List,
|
||||
dossierTemplateId: string,
|
||||
type: string,
|
||||
dictionaryEntryType: DictionaryEntryType,
|
||||
dossierId: string,
|
||||
) {
|
||||
#deleteEntries(entries: List, dossierTemplateId: string, type: string, dictionaryEntryType: DictionaryEntryType, dossierId: string) {
|
||||
const queryParams = [
|
||||
{ key: 'dossierId', value: dossierId },
|
||||
{ key: 'dictionaryEntryType', value: dictionaryEntryType },
|
||||
|
||||
@ -2,7 +2,7 @@ import { effect, Injectable } from '@angular/core';
|
||||
import { NavigationEnd, Router } from '@angular/router';
|
||||
import { JwtToken } from '@guards/if-logged-in.guard';
|
||||
import { TenantsService } from '@iqser/common-ui/lib/tenants';
|
||||
import jwt_decode from 'jwt-decode';
|
||||
import { jwtDecode } from 'jwt-decode';
|
||||
import { KeycloakService } from 'keycloak-angular';
|
||||
import { filter } from 'rxjs/operators';
|
||||
|
||||
@ -37,7 +37,7 @@ export class RouterHistoryService {
|
||||
return;
|
||||
}
|
||||
|
||||
const jwtToken = jwt_decode(token) as JwtToken;
|
||||
const jwtToken = jwtDecode(token) as JwtToken;
|
||||
const authTime = (jwtToken.auth_time || jwtToken.iat).toString();
|
||||
const localStorageAuthTime = localStorage.getItem('authTime');
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"ADMIN_CONTACT_NAME": null,
|
||||
"ADMIN_CONTACT_URL": null,
|
||||
"API_URL": "https://dan.iqser.cloud",
|
||||
"API_URL": "https://dan1.iqser.cloud",
|
||||
"APP_NAME": "RedactManager",
|
||||
"IS_DOCUMINE": false,
|
||||
"RULE_EDITOR_DEV_ONLY": false,
|
||||
@ -13,7 +13,7 @@
|
||||
"MAX_RETRIES_ON_SERVER_ERROR": 3,
|
||||
"OAUTH_CLIENT_ID": "redaction",
|
||||
"OAUTH_IDP_HINT": null,
|
||||
"OAUTH_URL": "https://dan.iqser.cloud/auth",
|
||||
"OAUTH_URL": "https://dan1.iqser.cloud/auth",
|
||||
"RECENT_PERIOD_IN_HOURS": 24,
|
||||
"SELECTION_MODE": "structural",
|
||||
"MANUAL_BASE_URL": "https://docs.redactmanager.com/preview",
|
||||
|
||||
94
package.json
94
package.json
@ -19,19 +19,19 @@
|
||||
"*.{ts,js,html}": "eslint --fix"
|
||||
},
|
||||
"dependencies": {
|
||||
"@angular/animations": "16.2.9",
|
||||
"@angular/cdk": "16.2.8",
|
||||
"@angular/common": "16.2.9",
|
||||
"@angular/compiler": "16.2.9",
|
||||
"@angular/core": "16.2.9",
|
||||
"@angular/forms": "16.2.9",
|
||||
"@angular/material": "16.2.8",
|
||||
"@angular/platform-browser": "16.2.9",
|
||||
"@angular/platform-browser-dynamic": "16.2.9",
|
||||
"@angular/router": "16.2.9",
|
||||
"@angular/service-worker": "16.2.9",
|
||||
"@angular/animations": "17.0.5",
|
||||
"@angular/cdk": "17.0.1",
|
||||
"@angular/common": "17.0.5",
|
||||
"@angular/compiler": "17.0.5",
|
||||
"@angular/core": "17.0.5",
|
||||
"@angular/forms": "17.0.5",
|
||||
"@angular/material": "17.0.1",
|
||||
"@angular/platform-browser": "17.0.5",
|
||||
"@angular/platform-browser-dynamic": "17.0.5",
|
||||
"@angular/router": "17.0.5",
|
||||
"@angular/service-worker": "17.0.5",
|
||||
"@materia-ui/ngx-monaco-editor": "^6.0.0",
|
||||
"@messageformat/core": "^3.1.0",
|
||||
"@messageformat/core": "^3.3.0",
|
||||
"@ngx-translate/core": "15.0.0",
|
||||
"@ngx-translate/http-loader": "8.0.0",
|
||||
"@pdftron/webviewer": "10.5.0",
|
||||
@ -39,64 +39,64 @@
|
||||
"dayjs": "1.11.10",
|
||||
"file-saver": "^2.0.5",
|
||||
"jszip": "^3.10.1",
|
||||
"jwt-decode": "^3.1.2",
|
||||
"keycloak-angular": "14.1.0",
|
||||
"keycloak-js": "22.0.4",
|
||||
"jwt-decode": "^4.0.0",
|
||||
"keycloak-angular": "15.0.0",
|
||||
"keycloak-js": "23.0.1",
|
||||
"lodash-es": "^4.17.21",
|
||||
"monaco-editor": "0.43.0",
|
||||
"monaco-editor": "0.44.0",
|
||||
"ng2-charts": "5.0.3",
|
||||
"ngx-color-picker": "15.0.0",
|
||||
"ngx-color-picker": "16.0.0",
|
||||
"ngx-logger": "^5.0.11",
|
||||
"ngx-toastr": "17.0.2",
|
||||
"ngx-toastr": "18.0.0",
|
||||
"ngx-translate-messageformat-compiler": "6.5.0",
|
||||
"object-hash": "^3.0.0",
|
||||
"papaparse": "^5.4.0",
|
||||
"rxjs": "7.8.1",
|
||||
"sass": "1.69.3",
|
||||
"sass": "1.69.5",
|
||||
"scroll-into-view-if-needed": "3.1.0",
|
||||
"streamsaver": "^2.0.5",
|
||||
"tslib": "2.6.2",
|
||||
"zone.js": "0.14.0"
|
||||
"zone.js": "0.14.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "16.2.6",
|
||||
"@angular-devkit/core": "16.2.6",
|
||||
"@angular-devkit/schematics": "16.2.6",
|
||||
"@angular-eslint/builder": "16.2.0",
|
||||
"@angular-eslint/eslint-plugin": "16.2.0",
|
||||
"@angular-eslint/eslint-plugin-template": "16.2.0",
|
||||
"@angular-eslint/schematics": "16.2.0",
|
||||
"@angular-eslint/template-parser": "16.2.0",
|
||||
"@angular/cli": "16.2.6",
|
||||
"@angular/compiler-cli": "16.2.9",
|
||||
"@angular/language-service": "16.2.9",
|
||||
"@angular-devkit/build-angular": "17.0.4",
|
||||
"@angular-devkit/core": "17.0.4",
|
||||
"@angular-devkit/schematics": "17.0.4",
|
||||
"@angular-eslint/builder": "17.1.0",
|
||||
"@angular-eslint/eslint-plugin": "17.1.0",
|
||||
"@angular-eslint/eslint-plugin-template": "17.1.0",
|
||||
"@angular-eslint/schematics": "17.1.0",
|
||||
"@angular-eslint/template-parser": "17.1.0",
|
||||
"@angular/cli": "17.0.4",
|
||||
"@angular/compiler-cli": "17.0.5",
|
||||
"@angular/language-service": "17.0.5",
|
||||
"@bartholomej/ngx-translate-extract": "^8.0.2",
|
||||
"@localazy/ts-api": "^1.0.0",
|
||||
"@schematics/angular": "16.2.6",
|
||||
"@types/file-saver": "^2.0.5",
|
||||
"@types/jest": "29.5.5",
|
||||
"@types/lodash-es": "4.17.9",
|
||||
"@types/node": "20.8.6",
|
||||
"@typescript-eslint/eslint-plugin": "6.8.0",
|
||||
"@typescript-eslint/parser": "6.8.0",
|
||||
"axios": "1.5.1",
|
||||
"eslint": "8.51.0",
|
||||
"@schematics/angular": "17.0.4",
|
||||
"@types/file-saver": "^2.0.7",
|
||||
"@types/jest": "29.5.10",
|
||||
"@types/lodash-es": "4.17.12",
|
||||
"@types/node": "20.10.0",
|
||||
"@typescript-eslint/eslint-plugin": "^6.10.0",
|
||||
"@typescript-eslint/parser": "^6.10.0",
|
||||
"axios": "1.6.2",
|
||||
"eslint": "^8.53.0",
|
||||
"eslint-config-prettier": "9.0.0",
|
||||
"eslint-plugin-prettier": "5.0.1",
|
||||
"eslint-plugin-rxjs": "^5.0.2",
|
||||
"google-translate-api-browser": "^4.0.6",
|
||||
"google-translate-api-browser": "^4.1.9",
|
||||
"husky": "^8.0.3",
|
||||
"jest": "29.7.0",
|
||||
"jest-environment-jsdom": "29.7.0",
|
||||
"jest-extended": "4.0.2",
|
||||
"jest-preset-angular": "13.1.2",
|
||||
"lint-staged": "15.0.1",
|
||||
"prettier": "3.0.3",
|
||||
"sonarqube-scanner": "3.1.0",
|
||||
"jest-preset-angular": "13.1.4",
|
||||
"lint-staged": "15.1.0",
|
||||
"prettier": "3.1.0",
|
||||
"sonarqube-scanner": "3.3.0",
|
||||
"ts-node": "10.9.1",
|
||||
"typescript": "5.1.6",
|
||||
"typescript": "5.2.2",
|
||||
"webpack": "5.89.0",
|
||||
"webpack-bundle-analyzer": "4.9.1",
|
||||
"webpack-bundle-analyzer": "4.10.1",
|
||||
"xliff": "^6.1.0"
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user