diff --git a/apps/red-ui/src/app/app.module.ts b/apps/red-ui/src/app/app.module.ts index aa140d8c4..e7c40a6f6 100644 --- a/apps/red-ui/src/app/app.module.ts +++ b/apps/red-ui/src/app/app.module.ts @@ -73,6 +73,7 @@ import { PageIndicatorComponent } from './screens/file/page-indicator/page-indic import { NeedsWorkBadgeComponent } from './screens/common/needs-work-badge/needs-work-badge.component'; import { ProjectOverviewEmptyComponent } from './screens/empty-states/project-overview-empty/project-overview-empty.component'; import { ProjectListingEmptyComponent } from './screens/empty-states/project-listing-empty/project-listing-empty.component'; +import { ProjectListingDetailsComponent } from './screens/project-listing-screen/project-listing-details/project-listing-details.component'; export function HttpLoaderFactory(httpClient: HttpClient) { return new TranslateHttpLoader(httpClient, '/assets/i18n/', '.json'); @@ -111,7 +112,8 @@ export function HttpLoaderFactory(httpClient: HttpClient) { PageIndicatorComponent, NeedsWorkBadgeComponent, ProjectOverviewEmptyComponent, - ProjectListingEmptyComponent + ProjectListingEmptyComponent, + ProjectListingDetailsComponent ], imports: [ BrowserModule, diff --git a/apps/red-ui/src/app/common/filter/utils/filter-utils.ts b/apps/red-ui/src/app/common/filter/utils/filter-utils.ts index ed10d5300..2f6add9ad 100644 --- a/apps/red-ui/src/app/common/filter/utils/filter-utils.ts +++ b/apps/red-ui/src/app/common/filter/utils/filter-utils.ts @@ -1,6 +1,5 @@ import { FilterModel } from '../model/filter.model'; import { FileStatusWrapper } from '../../../screens/file/model/file-status.wrapper'; -import * as moment from 'moment'; import { ProjectWrapper } from '../../../state/app-state.service'; export const RedactionFilterSorter = { @@ -57,9 +56,6 @@ export const annotationFilterChecker = (f: FileStatusWrapper, filter: FilterMode return f[getter]; }; -export const fileAddedFilterChecker = (f: FileStatusWrapper, filter: FilterModel) => - moment(f.added).format('DD/MM/YYYY') === filter.key; - export const projectStatusChecker = (pw: ProjectWrapper, filter: FilterModel) => pw.hasStatus(filter.key); diff --git a/apps/red-ui/src/app/common/initials-avatar/initials-avatar.component.html b/apps/red-ui/src/app/common/initials-avatar/initials-avatar.component.html index aeb90be97..3ee32e3b7 100644 --- a/apps/red-ui/src/app/common/initials-avatar/initials-avatar.component.html +++ b/apps/red-ui/src/app/common/initials-avatar/initials-avatar.component.html @@ -1,5 +1,11 @@ -
-
{{ initials }}
+
+
+ {{ initials }} +
{{ username || ('initials-avatar.unassigned' | translate) }}
diff --git a/apps/red-ui/src/app/components/simple-doughnut-chart/simple-doughnut-chart.component.html b/apps/red-ui/src/app/components/simple-doughnut-chart/simple-doughnut-chart.component.html index 5f4d6913e..1319c967b 100644 --- a/apps/red-ui/src/app/components/simple-doughnut-chart/simple-doughnut-chart.component.html +++ b/apps/red-ui/src/app/components/simple-doughnut-chart/simple-doughnut-chart.component.html @@ -30,7 +30,12 @@
-
+
+ +
+
+ +
+
{{ totalPages }}
+
+
+
+ +
+ +
+
{{ totalPeople }}
+
+
+
+
+
+
+ +
diff --git a/apps/red-ui/src/app/screens/project-listing-screen/project-listing-details/project-listing-details.component.scss b/apps/red-ui/src/app/screens/project-listing-screen/project-listing-details/project-listing-details.component.scss new file mode 100644 index 000000000..538a27659 --- /dev/null +++ b/apps/red-ui/src/app/screens/project-listing-screen/project-listing-details/project-listing-details.component.scss @@ -0,0 +1,32 @@ +:host { + flex: 1; + display: flex; + flex-direction: row; + justify-content: space-between; + + > div { + display: flex; + flex-direction: column; + align-items: center; + + .project-stats-container { + width: fit-content; + + .project-stats-item { + display: flex; + width: fit-content; + gap: 5px; + margin-top: 25px; + + &:first-of-type { + margin-top: 50px; + } + + mat-icon { + height: 16px; + margin-top: 2px; + } + } + } + } +} diff --git a/apps/red-ui/src/app/screens/project-listing-screen/project-listing-details/project-listing-details.component.ts b/apps/red-ui/src/app/screens/project-listing-screen/project-listing-details/project-listing-details.component.ts new file mode 100644 index 000000000..5ee602320 --- /dev/null +++ b/apps/red-ui/src/app/screens/project-listing-screen/project-listing-details/project-listing-details.component.ts @@ -0,0 +1,34 @@ +import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; +import { DoughnutChartConfig } from '../../../components/simple-doughnut-chart/simple-doughnut-chart.component'; +import { AppStateService } from '../../../state/app-state.service'; +import { FilterModel } from '../../../common/filter/model/filter.model'; + +@Component({ + selector: 'redaction-project-listing-details', + templateUrl: './project-listing-details.component.html', + styleUrls: ['./project-listing-details.component.scss'] +}) +export class ProjectListingDetailsComponent implements OnInit { + @Input() public projectsChartData: DoughnutChartConfig[]; + @Input() public documentsChartData: DoughnutChartConfig[]; + @Input() public filters: { statusFilters: FilterModel[] }; + @Output() public filtersChanged = new EventEmitter(); + + constructor(private readonly _appStateService: AppStateService) {} + + ngOnInit(): void {} + + public get totalPages() { + return this._appStateService.totalAnalysedPages; + } + + public get totalPeople() { + return this._appStateService.totalPeople; + } + + public toggleFilter(filterType: 'needsWorkFilters' | 'statusFilters', key: string): void { + const filter = this.filters[filterType].find((f) => f.key === key); + filter.checked = !filter.checked; + this.filtersChanged.emit(this.filters); + } +} diff --git a/apps/red-ui/src/app/screens/project-listing-screen/project-listing-screen.component.html b/apps/red-ui/src/app/screens/project-listing-screen/project-listing-screen.component.html index 882d6c9b8..a1faf643e 100644 --- a/apps/red-ui/src/app/screens/project-listing-screen/project-listing-screen.component.html +++ b/apps/red-ui/src/app/screens/project-listing-screen/project-listing-screen.component.html @@ -162,7 +162,7 @@ [config]="getProjectStatusConfig(pw)" > -
+
diff --git a/apps/red-ui/src/app/screens/project-listing-screen/project-listing-screen.component.scss b/apps/red-ui/src/app/screens/project-listing-screen/project-listing-screen.component.scss index c8d100a87..e3a8235e2 100644 --- a/apps/red-ui/src/app/screens/project-listing-screen/project-listing-screen.component.scss +++ b/apps/red-ui/src/app/screens/project-listing-screen/project-listing-screen.component.scss @@ -38,31 +38,4 @@ display: flex; width: 430px; padding-top: 50px; - - > div { - flex: 1; - display: flex; - flex-direction: column; - align-items: center; - } - - .project-stats-container { - width: fit-content; - - .project-stats-item { - display: flex; - width: fit-content; - gap: 5px; - margin-top: 25px; - - &:first-of-type { - margin-top: 50px; - } - - mat-icon { - height: 16px; - margin-top: 2px; - } - } - } } diff --git a/apps/red-ui/src/app/screens/project-listing-screen/project-listing-screen.component.ts b/apps/red-ui/src/app/screens/project-listing-screen/project-listing-screen.component.ts index 2dd30e430..02259e860 100644 --- a/apps/red-ui/src/app/screens/project-listing-screen/project-listing-screen.component.ts +++ b/apps/red-ui/src/app/screens/project-listing-screen/project-listing-screen.component.ts @@ -34,8 +34,12 @@ export class ProjectListingScreenComponent implements OnInit { public dueDateFilters: FilterModel[]; public peopleFilters: FilterModel[]; public needsWorkFilters: FilterModel[]; - public displayedProjects: ProjectWrapper[] = []; + public detailsContainerFilters: { + statusFilters: FilterModel[]; + }; + + public displayedProjects: ProjectWrapper[] = []; public sortingOption: SortingOption = { column: 'projectDate', order: 'desc' }; constructor( @@ -72,14 +76,6 @@ export class ProjectListingScreenComponent implements OnInit { return this.userService.user; } - public get totalPages() { - return this.appStateService.totalAnalysedPages; - } - - public get totalPeople() { - return this.appStateService.totalPeople; - } - public get activeProjects() { return this.appStateService.allProjects.reduce( (i, p) => i + (p.project.status === Project.StatusEnum.ACTIVE ? 1 : 0), @@ -216,7 +212,14 @@ export class ProjectListingScreenComponent implements OnInit { this.needsWorkFilters = needsWorkFilters; } - public filtersChanged() { + filtersChanged(filters?: { [key: string]: FilterModel[] }): void { + if (filters) { + for (const key of Object.keys(filters)) { + for (let idx = 0; idx < this[key].length; ++idx) { + this[key][idx] = filters[key][idx]; + } + } + } this._filterProjects(); } @@ -227,7 +230,9 @@ export class ProjectListingScreenComponent implements OnInit { { values: this.dueDateFilters, checker: dueDateChecker }, { values: this.needsWorkFilters, checker: annotationFilterChecker, matchAll: true } ]; - + this.detailsContainerFilters = { + statusFilters: this.statusFilters.map((f) => ({ ...f })) + }; this.displayedProjects = getFilteredEntities(this.appStateService.allProjects, filters); this._changeDetectorRef.detectChanges(); } diff --git a/apps/red-ui/src/app/screens/project-overview-screen/project-details/project-details.component.html b/apps/red-ui/src/app/screens/project-overview-screen/project-details/project-details.component.html index d29471eb6..1dadeee90 100644 --- a/apps/red-ui/src/app/screens/project-overview-screen/project-details/project-details.component.html +++ b/apps/red-ui/src/app/screens/project-overview-screen/project-details/project-details.component.html @@ -64,29 +64,23 @@ [config]="documentsChartData" [radius]="70" [strokeWidth]="15" - [subtitle]="'project-overview.project-details.charts.total-documents'" + [subtitle]="'project-overview.project-details.charts.documents-in-project'" direction="row" + [filter]="filters.statusFilters" + (toggleFilter)="toggleFilter('statusFilters', $event)" >
-
+
- {{ 'project-overview.legend.contains-hints' | translate }} -
-
- - {{ 'project-overview.legend.contains-redactions' | translate }} -
-
- - {{ 'project-overview.legend.contains-suggestions' | translate }} + {{ 'project-overview.legend.' + filter.key | translate }}
diff --git a/apps/red-ui/src/app/screens/project-overview-screen/project-details/project-details.component.scss b/apps/red-ui/src/app/screens/project-overview-screen/project-details/project-details.component.scss index 2a0234af9..ac0ffd3c8 100644 --- a/apps/red-ui/src/app/screens/project-overview-screen/project-details/project-details.component.scss +++ b/apps/red-ui/src/app/screens/project-overview-screen/project-details/project-details.component.scss @@ -1,3 +1,5 @@ +@import '../../../../assets/styles/red-variables'; + .members-container { gap: 5px; } @@ -5,12 +7,24 @@ .legend { display: flex; flex-direction: column; - gap: 8px; + gap: 4px; + margin-left: -8px; > div { display: flex; gap: 8px; align-items: center; + border-radius: 4px; + cursor: pointer; + padding: 3px 8px; + + &:hover { + background-color: $grey-6; + } + + &.active { + background-color: rgba($primary, 0.1); + } } } diff --git a/apps/red-ui/src/app/screens/project-overview-screen/project-details/project-details.component.ts b/apps/red-ui/src/app/screens/project-overview-screen/project-details/project-details.component.ts index 171c22094..921d4f22d 100644 --- a/apps/red-ui/src/app/screens/project-overview-screen/project-details/project-details.component.ts +++ b/apps/red-ui/src/app/screens/project-overview-screen/project-details/project-details.component.ts @@ -1,10 +1,11 @@ -import { Component, OnInit, Output, EventEmitter, ChangeDetectorRef } from '@angular/core'; +import { Component, OnInit, Output, EventEmitter, Input, ChangeDetectorRef } from '@angular/core'; import { AppStateService } from '../../../state/app-state.service'; import { UserService } from '../../../user/user.service'; import { groupBy } from '../../../utils/functions'; import { DoughnutChartConfig } from '../../../components/simple-doughnut-chart/simple-doughnut-chart.component'; import { DialogService } from '../../../dialogs/dialog.service'; import { Router } from '@angular/router'; +import { FilterModel } from '../../../common/filter/model/filter.model'; @Component({ selector: 'redaction-project-details', @@ -13,7 +14,9 @@ import { Router } from '@angular/router'; }) export class ProjectDetailsComponent implements OnInit { public documentsChartData: DoughnutChartConfig[] = []; - @Output() public reloadProjects = new EventEmitter(); + @Input() public filters: { needsWorkFilters: FilterModel[]; statusFilters: FilterModel[] }; + @Output() public reloadProjects = new EventEmitter(); + @Output() public filtersChanged = new EventEmitter(); constructor( public readonly appStateService: AppStateService, @@ -61,7 +64,7 @@ export class ProjectDetailsComponent implements OnInit { ); } - public openAssignProjectMembersDialog() { + public openAssignProjectMembersDialog(): void { this._dialogService.openAssignProjectMembersAndOwnerDialog( null, this.appStateService.activeProject.project, @@ -71,12 +74,12 @@ export class ProjectDetailsComponent implements OnInit { ); } - public downloadRedactionReport($event: MouseEvent) { + public downloadRedactionReport($event: MouseEvent): void { $event.stopPropagation(); this.appStateService.downloadRedactionReport(); } - public calculateChartConfig() { + public calculateChartConfig(): void { if (this.appStateService.activeProject) { const groups = groupBy(this.appStateService.activeProject?.files, 'status'); this.documentsChartData = []; @@ -87,7 +90,13 @@ export class ProjectDetailsComponent implements OnInit { } } - get hasFiles() { + get hasFiles(): boolean { return this.appStateService.activeProject.hasFiles; } + + public toggleFilter(filterType: 'needsWorkFilters' | 'statusFilters', key: string): void { + const filter = this.filters[filterType].find((f) => f.key === key); + filter.checked = !filter.checked; + this.filtersChanged.emit(this.filters); + } } diff --git a/apps/red-ui/src/app/screens/project-overview-screen/project-overview-screen.component.html b/apps/red-ui/src/app/screens/project-overview-screen/project-overview-screen.component.html index 3f8077da6..aea8acd60 100644 --- a/apps/red-ui/src/app/screens/project-overview-screen/project-overview-screen.component.html +++ b/apps/red-ui/src/app/screens/project-overview-screen/project-overview-screen.component.html @@ -159,24 +159,21 @@ >
-
-
-
- {{ fileStatus.filename }} -
- +
+
+ {{ fileStatus.filename }}
+
@@ -355,6 +352,8 @@
diff --git a/apps/red-ui/src/app/screens/project-overview-screen/project-overview-screen.component.scss b/apps/red-ui/src/app/screens/project-overview-screen/project-overview-screen.component.scss index e64c522df..6c4b28717 100644 --- a/apps/red-ui/src/app/screens/project-overview-screen/project-overview-screen.component.scss +++ b/apps/red-ui/src/app/screens/project-overview-screen/project-overview-screen.component.scss @@ -57,13 +57,6 @@ .status-container { align-items: flex-end; } - - .filename-wrapper { - display: flex; - justify-content: space-between; - align-items: center; - gap: 8px; - } } } diff --git a/apps/red-ui/src/app/screens/project-overview-screen/project-overview-screen.component.ts b/apps/red-ui/src/app/screens/project-overview-screen/project-overview-screen.component.ts index f4381926a..cd5a44331 100644 --- a/apps/red-ui/src/app/screens/project-overview-screen/project-overview-screen.component.ts +++ b/apps/red-ui/src/app/screens/project-overview-screen/project-overview-screen.component.ts @@ -43,6 +43,11 @@ export class ProjectOverviewScreenComponent implements OnInit, OnDestroy { public displayedFiles: FileStatusWrapper[] = []; + public detailsContainerFilters: { + needsWorkFilters: FilterModel[]; + statusFilters: FilterModel[]; + }; + @ViewChild('projectDetailsComponent', { static: false }) private _projectDetailsComponent: ProjectDetailsComponent; @@ -313,7 +318,14 @@ export class ProjectOverviewScreenComponent implements OnInit, OnDestroy { this.needsWorkFilters = needsWorkFilters; } - filtersChanged() { + filtersChanged(filters?: { [key: string]: FilterModel[] }): void { + if (filters) { + for (const key of Object.keys(filters)) { + for (let idx = 0; idx < this[key].length; ++idx) { + this[key][idx] = filters[key][idx]; + } + } + } this._filterFiles(); } @@ -327,6 +339,10 @@ export class ProjectOverviewScreenComponent implements OnInit, OnDestroy { this.appStateService.activeProject.files, filters ); + this.detailsContainerFilters = { + needsWorkFilters: this.needsWorkFilters.map((f) => ({ ...f })), + statusFilters: this.statusFilters.map((f) => ({ ...f })) + }; this._changeDetectorRef.detectChanges(); } diff --git a/apps/red-ui/src/assets/i18n/en.json b/apps/red-ui/src/assets/i18n/en.json index 3cf84fd3a..6e8be4829 100644 --- a/apps/red-ui/src/assets/i18n/en.json +++ b/apps/red-ui/src/assets/i18n/en.json @@ -226,7 +226,7 @@ }, "project-details": { "charts": { - "total-documents": "Total Documents" + "documents-in-project": "Documents in Project" }, "stats": { "documents": "{{count}} documents", @@ -241,9 +241,9 @@ "upload-document": "Upload Document", "no-project": "Requested project: {{projectId}} does not exist! Back to Project Listing. ", "legend": { - "contains-hints": "Hints only ", - "contains-redactions": "Redacted ", - "contains-suggestions": "Suggested Redaction " + "hints": "Hints only", + "redactions": "Redacted", + "requests": "Redaction requests" } }, "file-preview": { diff --git a/package.json b/package.json index 50794a43a..3272f92a9 100644 --- a/package.json +++ b/package.json @@ -1,96 +1,96 @@ { - "name": "redaction", - "version": "0.0.123", - "license": "MIT", - "husky": { - "hooks": { - "pre-commit": "pretty-quick --staged && ng lint --project=red-ui-http && ng lint --project=red-ui --fix" + "name": "redaction", + "version": "0.0.123", + "license": "MIT", + "husky": { + "hooks": { + "pre-commit": "pretty-quick --staged && ng lint --project=red-ui-http && ng lint --project=red-ui --fix" + } + }, + "scripts": { + "build-lint-all": "ng lint --project=red-ui-http --fix && ng build --project=red-ui-http && ng lint --project=red-ui --fix && ng build --project=red-ui --prod", + "nx": "nx", + "start": "nx serve", + "build": "nx build", + "test": "nx test", + "lint": "nx workspace-lint && nx lint", + "e2e": "nx e2e", + "affected:apps": "nx affected:apps", + "affected:libs": "nx affected:libs", + "affected:build": "nx affected:build", + "affected:e2e": "nx affected:e2e", + "affected:test": "nx affected:test", + "affected:lint": "nx affected:lint", + "affected:dep-graph": "nx affected:dep-graph", + "affected": "nx affected", + "format": "nx format:write", + "format:write": "nx format:write", + "format:check": "nx format:check", + "update": "nx migrate latest", + "workspace-schematic": "nx workspace-schematic", + "dep-graph": "nx dep-graph", + "help": "nx help", + "postinstall": "ngcc --properties es2015 browser module main --first-only --create-ivy-entry-points" + }, + "private": true, + "dependencies": { + "@angular/animations": "^10.0.0", + "@angular/cdk": "^10.2.3", + "@angular/common": "^10.0.0", + "@angular/core": "^10.0.0", + "@angular/forms": "^10.0.0", + "@angular/material": "^10.2.1", + "@angular/platform-browser": "^10.0.0", + "@angular/platform-browser-dynamic": "^10.0.0", + "@angular/router": "^10.0.0", + "@angular/service-worker": "^10.0.0", + "@ngx-translate/core": "^13.0.0", + "@ngx-translate/http-loader": "^6.0.0", + "@nrwl/angular": "^10.2.0", + "@pdftron/webviewer": "^7.0.1", + "file-saver": "^2.0.2", + "jwt-decode": "^3.0.0", + "keycloak-angular": "^8.0.1", + "keycloak-js": "10.0.2", + "lint-staged": "^10.5.0", + "ng2-file-upload": "^1.4.0", + "ngp-sort-pipe": "^0.0.4", + "ngx-dropzone": "^2.2.2", + "ngx-toastr": "^13.0.0", + "rxjs": "~6.5.5", + "scroll-into-view-if-needed": "^2.2.26", + "zone.js": "^0.10.2" + }, + "devDependencies": { + "@angular-devkit/build-angular": "~0.1000.0", + "@angular-devkit/build-ng-packagr": "^0.1001.3", + "@angular/cli": "^10.1.2", + "@angular/compiler": "^10.0.0", + "@angular/compiler-cli": "^10.0.0", + "@angular/language-service": "^10.0.0", + "@nrwl/cypress": "10.2.0", + "@nrwl/jest": "10.2.0", + "@nrwl/workspace": "10.2.0", + "@types/jest": "26.0.8", + "@types/node": "~8.9.4", + "codelyzer": "~5.0.1", + "cypress": "^4.1.0", + "dotenv": "6.2.0", + "eslint": "6.8.0", + "google-translate-api-browser": "^1.1.71", + "husky": "^4.3.0", + "jest": "26.2.2", + "jest-preset-angular": "8.2.1", + "lodash": "^4.17.20", + "moment": "^2.29.1", + "ng-packagr": "^10.1.2", + "prettier": "2.0.4", + "pretty-quick": "^3.1.0", + "superagent": "^6.1.0", + "superagent-promise": "^1.1.0", + "ts-jest": "26.1.4", + "ts-node": "~7.0.0", + "tslint": "~6.0.0", + "typescript": "~3.9.3" } - }, - "scripts": { - "build-lint-all": "ng lint --project=red-ui-http --fix && ng build --project=red-ui-http && ng lint --project=red-ui --fix && ng build --project=red-ui --prod", - "nx": "nx", - "start": "nx serve", - "build": "nx build", - "test": "nx test", - "lint": "nx workspace-lint && nx lint", - "e2e": "nx e2e", - "affected:apps": "nx affected:apps", - "affected:libs": "nx affected:libs", - "affected:build": "nx affected:build", - "affected:e2e": "nx affected:e2e", - "affected:test": "nx affected:test", - "affected:lint": "nx affected:lint", - "affected:dep-graph": "nx affected:dep-graph", - "affected": "nx affected", - "format": "nx format:write", - "format:write": "nx format:write", - "format:check": "nx format:check", - "update": "nx migrate latest", - "workspace-schematic": "nx workspace-schematic", - "dep-graph": "nx dep-graph", - "help": "nx help", - "postinstall": "ngcc --properties es2015 browser module main --first-only --create-ivy-entry-points" - }, - "private": true, - "dependencies": { - "@angular/animations": "^10.0.0", - "@angular/cdk": "^10.2.3", - "@angular/common": "^10.0.0", - "@angular/core": "^10.0.0", - "@angular/forms": "^10.0.0", - "@angular/material": "^10.2.1", - "@angular/platform-browser": "^10.0.0", - "@angular/platform-browser-dynamic": "^10.0.0", - "@angular/router": "^10.0.0", - "@angular/service-worker": "^10.0.0", - "@ngx-translate/core": "^13.0.0", - "@ngx-translate/http-loader": "^6.0.0", - "@nrwl/angular": "^10.2.0", - "@pdftron/webviewer": "^7.0.1", - "file-saver": "^2.0.2", - "jwt-decode": "^3.0.0", - "keycloak-angular": "^8.0.1", - "keycloak-js": "10.0.2", - "lint-staged": "^10.5.0", - "ng2-file-upload": "^1.4.0", - "ngp-sort-pipe": "^0.0.4", - "ngx-dropzone": "^2.2.2", - "ngx-toastr": "^13.0.0", - "rxjs": "~6.5.5", - "scroll-into-view-if-needed": "^2.2.26", - "zone.js": "^0.10.2" - }, - "devDependencies": { - "@angular-devkit/build-angular": "~0.1000.0", - "@angular-devkit/build-ng-packagr": "^0.1001.3", - "@angular/cli": "^10.1.2", - "@angular/compiler": "^10.0.0", - "@angular/compiler-cli": "^10.0.0", - "@angular/language-service": "^10.0.0", - "@nrwl/cypress": "10.2.0", - "@nrwl/jest": "10.2.0", - "@nrwl/workspace": "10.2.0", - "@types/jest": "26.0.8", - "@types/node": "~8.9.4", - "codelyzer": "~5.0.1", - "cypress": "^4.1.0", - "dotenv": "6.2.0", - "eslint": "6.8.0", - "google-translate-api-browser": "^1.1.71", - "husky": "^4.3.0", - "jest": "26.2.2", - "jest-preset-angular": "8.2.1", - "lodash": "^4.17.20", - "moment": "^2.29.1", - "ng-packagr": "^10.1.2", - "prettier": "2.0.4", - "pretty-quick": "^3.1.0", - "superagent": "^6.1.0", - "superagent-promise": "^1.1.0", - "ts-jest": "26.1.4", - "ts-node": "~7.0.0", - "tslint": "~6.0.0", - "typescript": "~3.9.3" - } }