dynamic-display-shared
Version:
A library for dynamic view
1 lines • 238 kB
Source Map (JSON)
{"version":3,"file":"dynamic-display-shared.mjs","sources":["../../../projects/dynamic-display-shared/src/lib/dynamic-display-shared.service.ts","../../../projects/dynamic-display-shared/src/lib/dynamic-display-shared.component.ts","../../../projects/dynamic-display-shared/src/lib/dynamic-display-shared.module.ts","../../../projects/dynamic-display-shared/src/lib/shared/model/entity.ts","../../../projects/dynamic-display-shared/src/lib/shared/model/entity-details.view-model.ts","../../../projects/dynamic-display-shared/src/lib/shared/services/device-type.service.ts","../../../projects/dynamic-display-shared/src/lib/infrastructure/logger.ts","../../../projects/dynamic-display-shared/src/lib/infrastructure/guid.ts","../../../projects/dynamic-display-shared/src/lib/shared/documents/documents.helper.ts","../../../projects/dynamic-display-shared/src/lib/shared/store/filter.actions.ts","../../../projects/dynamic-display-shared/src/lib/shared/services/entity.service.ts","../../../projects/dynamic-display-shared/src/lib/shared/documents/azure-storage.service.ts","../../../projects/dynamic-display-shared/src/lib/infrastructure/data/api-base.service.ts","../../../projects/dynamic-display-shared/src/lib/shared/documents/storage.service.ts","../../../projects/dynamic-display-shared/src/lib/infrastructure/date.utility.ts","../../../projects/dynamic-display-shared/src/lib/shared/model/entity-type-instance.ts","../../../projects/dynamic-display-shared/src/lib/shared/model/view-model.helper.ts","../../../projects/dynamic-display-shared/src/lib/shared/components/long-text-dialog/long-text-dialog.component.ts","../../../projects/dynamic-display-shared/src/lib/shared/components/long-text-dialog/long-text-dialog.component.html","../../../projects/dynamic-display-shared/src/lib/shared/components/recursive-components.ts","../../../projects/dynamic-display-shared/src/lib/shared/components/entities-collection-view/entities-collection-view.component.html","../../../projects/dynamic-display-shared/src/lib/shared/components/entities-list/entities-list.component.html","../../../projects/dynamic-display-shared/src/lib/shared/components/inner-entity-details/inner-entity-details.component.html","../../../projects/dynamic-display-shared/src/lib/shared/components/parameters-group/parameters-group.component.html","../../../projects/dynamic-display-shared/src/lib/shared/components/groups-collection/groups-collection.component.html","../../../projects/dynamic-display-shared/src/lib/shared/components/user-account/user-account.component.ts","../../../projects/dynamic-display-shared/src/lib/shared/components/user-account/user-account.component.html","../../../projects/dynamic-display-shared/src/lib/shared/components/buildings-animation/buildings-animation.component.ts","../../../projects/dynamic-display-shared/src/lib/shared/components/buildings-animation/buildings-animation.component.html","../../../projects/dynamic-display-shared/src/lib/shared/components/file-upload/file-upload.component.ts","../../../projects/dynamic-display-shared/src/lib/shared/components/file-upload/file-upload.component.html","../../../projects/dynamic-display-shared/src/lib/shared/components/unauthorized-page/unauthorized-page.component.ts","../../../projects/dynamic-display-shared/src/lib/shared/components/unauthorized-page/unauthorized-page.component.html","../../../projects/dynamic-display-shared/src/lib/shared/auth/auth.config.model.ts","../../../projects/dynamic-display-shared/src/lib/shared/auth/identity-initializer.ts","../../../projects/dynamic-display-shared/src/lib/shared/custom-material-module.module.ts","../../../projects/dynamic-display-shared/src/lib/shared/documents/azure-file-upload-bl.service.ts","../../../projects/dynamic-display-shared/src/lib/shared/services/entity-base.service.ts","../../../projects/dynamic-display-shared/src/lib/shared/store/entity-management.actions.ts","../../../projects/dynamic-display-shared/src/lib/shared/auth/group-number.enum.ts","../../../projects/dynamic-display-shared/src/lib/shared/auth/user.service.ts","../../../projects/dynamic-display-shared/src/lib/shared/services/update-entity.service.ts","../../../projects/dynamic-display-shared/src/lib/shared/shared.module.ts","../../../projects/dynamic-display-shared/src/lib/shared/services/action-notifier.service.ts","../../../projects/dynamic-display-shared/src/lib/infrastructure/deep-clone.utility.ts","../../../projects/dynamic-display-shared/src/lib/infrastructure/group-by.utility.ts","../../../projects/dynamic-display-shared/src/lib/infrastructure/notification.service.ts","../../../projects/dynamic-display-shared/src/lib/infrastructure/script-loader.utility.ts","../../../projects/dynamic-display-shared/src/lib/infrastructure/sort.utility.ts","../../../projects/dynamic-display-shared/src/lib/infrastructure/string.utility.ts","../../../projects/dynamic-display-shared/src/lib/infrastructure/pipes/safe-url.pipe.ts","../../../projects/dynamic-display-shared/src/lib/shared/auth/admin.guard.service.ts","../../../projects/dynamic-display-shared/src/lib/shared/documents/requiredFileType.ts","../../../projects/dynamic-display-shared/src/lib/shared/helpers/scroll-page.helper.ts","../../../projects/dynamic-display-shared/src/lib/shared/model/acumulated-data.ts","../../../projects/dynamic-display-shared/src/lib/shared/model/comment.ts","../../../projects/dynamic-display-shared/src/lib/shared/model/entities.group.ts","../../../projects/dynamic-display-shared/src/lib/shared/model/entity-chart-color-palette.ts","../../../projects/dynamic-display-shared/src/lib/shared/model/entity-metadata.ts","../../../projects/dynamic-display-shared/src/lib/shared/model/entity-parameter.ts","../../../projects/dynamic-display-shared/src/lib/shared/model/entity-parameter-metadata.ts","../../../projects/dynamic-display-shared/src/lib/shared/model/entity-status.ts","../../../projects/dynamic-display-shared/src/lib/shared/model/field-type.ts","../../../projects/dynamic-display-shared/src/lib/shared/model/filter-category.ts","../../../projects/dynamic-display-shared/src/lib/shared/model/filter-data.ts","../../../projects/dynamic-display-shared/src/lib/shared/model/filter-range-parameter.ts","../../../projects/dynamic-display-shared/src/lib/shared/model/filter.ts","../../../projects/dynamic-display-shared/src/lib/shared/model/housing-units-chart.ts","../../../projects/dynamic-display-shared/src/lib/shared/model/housing-units-chart-header.ts","../../../projects/dynamic-display-shared/src/lib/shared/model/housing-units-chart-categoty.ts","../../../projects/dynamic-display-shared/src/lib/shared/model/process-status.ts","../../../projects/dynamic-display-shared/src/lib/shared/model/process.ts","../../../projects/dynamic-display-shared/src/lib/shared/model/sort-option.ts","../../../projects/dynamic-display-shared/src/lib/shared/model/stacked-column-chart-view-model.ts","../../../projects/dynamic-display-shared/src/lib/shared/model/target-chart.ts","../../../projects/dynamic-display-shared/src/lib/shared/model/year-target.ts","../../../projects/dynamic-display-shared/src/lib/shared/pipes/to-array.pipe.ts","../../../projects/dynamic-display-shared/src/lib/shared/services/idle.service.ts","../../../projects/dynamic-display-shared/src/lib/shared/store/entity-management.reducer.ts","../../../projects/dynamic-display-shared/src/public-api.ts","../../../projects/dynamic-display-shared/src/dynamic-display-shared.ts"],"sourcesContent":["import { Injectable } from '@angular/core';\n\n@Injectable({\n providedIn: 'root'\n})\nexport class DynamicDisplaySharedService {\n\n constructor() { }\n}\n","import { Component, OnInit } from '@angular/core';\n\n@Component({\n selector: 'lib-dynamic-display-shared',\n template: `\n <p>\n dynamic-display-shared works!\n </p>\n `,\n styles: [\n ]\n})\nexport class DynamicDisplaySharedComponent implements OnInit {\n\n constructor() { }\n\n ngOnInit(): void {\n }\n\n}\n","import { NgModule } from '@angular/core';\nimport { DynamicDisplaySharedComponent } from './dynamic-display-shared.component';\n\n\n\n@NgModule({\n declarations: [\n DynamicDisplaySharedComponent\n ],\n imports: [\n ],\n exports: [\n DynamicDisplaySharedComponent\n ]\n})\nexport class DynamicDisplaySharedModule { }\n","import { AnyParameter } from './entity-parameter';\r\nimport { Process } from './process';\r\nimport { Comment } from './comment';\r\nimport { EntityMetadata } from './entity-metadata';\r\n\r\nexport class EntityBase {\r\n id!: number;\r\n fixedId!: string;\r\n isDisplayDescription!: boolean;\r\n iconName!: string;\r\n gisId!: string;\r\n cssClasses!: string;\r\n color!: string;\r\n pluralEntitiesDescription!: string;\r\n orderBy!: number;\r\n comments!: Comment[];\r\n presentationEntityId!: number;\r\n superRange!: boolean;\r\n}\r\nexport class Entity extends EntityBase {\r\n entityMetadata!: EntityMetadata;\r\n parameters!: AnyParameter[];\r\n processes!: Process[];\r\n\r\n}\r\n","import { AnyParameter } from './entity-parameter';\r\nimport { EntityBase } from './entity';\r\nimport { EntityTypeInstance } from './entity-type-instance';\r\nimport { ProcessViewModel } from './process';\r\nimport { Comment } from './comment';\r\n\r\n\r\nexport class ParametersGroup {\r\n order!: number;\r\n description!: string;\r\n parameters!: AnyParameter[];\r\n}\r\n\r\nexport class EntityDetailsViewModel extends EntityBase {\r\n type!: EntityTypeInstance;\r\n\r\n description!: string;\r\n shortDescription!: string;\r\n // isDisplayDescription: boolean;\r\n parametersGroups!: ParametersGroup[];\r\n // headersParameters: ParametersGroup;\r\n // subHeadersParameters: ParametersGroup;\r\n // color: string;\r\n // iconName: string;\r\n // cssClasses: string;\r\n // gisId: string;\r\n gisIdFieldName!: string;\r\n gisLayers!: string;\r\n gisBs!: string;\r\n override pluralEntitiesDescription!: string;\r\n processes!: ProcessViewModel[];\r\n override comments!: Comment[];\r\n}\r\nexport class MasterEntityDetailsViewModel extends EntityDetailsViewModel {\r\n headersParameters: ParametersGroup | undefined;\r\n subHeadersParameters: ParametersGroup | undefined;\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport { BehaviorSubject, Observable, Subject } from 'rxjs';\r\n\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\nexport class DeviceTypeService {\r\n\r\n public isMobile: Subject<boolean> = new BehaviorSubject<boolean>(false);\r\n public isMobile$: Observable<boolean> = this.isMobile.asObservable();\r\n\r\n constructor() {\r\n window.innerWidth <= 700 || window.innerHeight <= 550 ? this.isMobile.next(true) : this.isMobile.next(false);\r\n window.addEventListener('resize', () => {\r\n window.innerWidth <= 700 || window.innerHeight <= 550 ? this.isMobile.next(true) : this.isMobile.next(false);\r\n });\r\n }\r\n}\r\n","import { Injectable } from '@angular/core';\r\n\r\n@Injectable()\r\nexport abstract class Logger {\r\n fatal(message: string, ...additional: any[]) { }\r\n error(message: string, ...additional: any[]) { }\r\n warn(message: string, ...additional: any[]) { }\r\n info(message: string, ...additional: any[]) { }\r\n log(message: string, ...additional: any[]) { }\r\n debug(message: string, ...additional: any[]) { }\r\n trace(message: string, ...additional: any[]) { }\r\n}","export class Guid {\r\n static newGuid() {\r\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {\r\n var r = Math.random() * 16 | 0,\r\n v = c == 'x' ? r : (r & 0x3 | 0x8);\r\n return v.toString(16);\r\n });\r\n }\r\n}\r\n","import { Guid } from \"../../infrastructure/guid\";\r\n\r\nexport function getFileName(entityId: string, parameterMetadataId: number, originalFileName: string) {\r\n return `${Guid.newGuid()}_${parameterMetadataId}.${getFileExtension(originalFileName)}`;\r\n}\r\nexport function getFileExtension(fileName: string) {\r\n return fileName ? fileName.slice((Math.max(0, fileName.lastIndexOf('.')) || Infinity) + 1) : '';\r\n}\r\n\r\nexport function applyDownloadLink(href: string, fileName: string | null, openInNewWindow = false) {\r\n const downloadLink = document.createElement('a');\r\n downloadLink.href = href;\r\n if (openInNewWindow) {\r\n downloadLink.setAttribute('target', '_blank');\r\n }\r\n if (fileName) {\r\n downloadLink.setAttribute('download', fileName);\r\n }\r\n document.body.appendChild(downloadLink);\r\n downloadLink.click();\r\n downloadLink.parentNode!.removeChild(downloadLink);\r\n}\r\n","import { createAction, props } from '@ngrx/store';\r\nimport { EntityDetailsViewModel } from '../model/entity-details.view-model';\r\nimport { FilterCategory } from '../model/filter-category';\r\nimport { FilterRangeParameter } from '../model/filter-range-parameter';\r\n\r\n\r\nexport const addCategoriesFilter = createAction(\r\n '[Filter] Add Categories Filters',\r\n props<{ categoriesFilter: FilterCategory[] }>()\r\n);\r\n\r\nexport const clearFilter = createAction(\r\n '[Filter] Clear Filter'\r\n);\r\n\r\nexport const removeCategoriesFilter = createAction(\r\n '[Filter] Remove Category Filter',\r\n props<{ categoryFilter: FilterCategory }>()\r\n);\r\nexport const removeCategoriesFilterRange = createAction(\r\n '[Filter] Remove Category Filter Range',\r\n props<{ categoryFilterRange: FilterRangeParameter }>()\r\n);\r\nexport const updateFreeFilter = createAction(\r\n '[Filter] Update Free Filter',\r\n props<{ freeFilter: string }>()\r\n);\r\nexport const updateRangesFilter = createAction(\r\n '[Filter] Update Range Filter',\r\n props<{ ranges: FilterRangeParameter[] }>()\r\n);\r\nexport const fetchFiltersOptions = createAction(\r\n '[Filter] Fetch Filters Options'\r\n);\r\n\r\nexport const loadFiltersOptionsSuccess = createAction(\r\n '[Filter] Load Filters Options',\r\n props<{ categoriesFilter: FilterCategory[] }>()\r\n);\r\n\r\n// export const loadFiltersOptionsSuccess = createAction(\r\n// '[Filter] Load Filters Options Success',\r\n\r\n// );\r\n\r\nexport const loadFiltersOptionsFailure = createAction(\r\n '[Filter] Load Filters Options Failure',\r\n props<{ error: any }>()\r\n);\r\n\r\nexport const downloadFileStarted = createAction(\r\n '[Filter] Download File Started'\r\n);\r\n\r\nexport const downloadFileFinished = createAction(\r\n '[Filter] Download File Finished'\r\n);\r\n\r\n// Statistic actions\r\n\r\nexport const updateSelectedChart = createAction(\r\n '[Statistic] Update Selected Chart',\r\n props<{ chartId: number, selectedChart: string }>()\r\n);\r\n\r\nexport const refreshEntities = createAction(\r\n '[Filter] Refresh Entities',\r\n props<{ entities: EntityDetailsViewModel[] }>()\r\n);\r\n\r\nexport const sortIdChange = createAction(\r\n '[Filter] Sort id changed',\r\n props<{ sortId: number | null | undefined }>()\r\n);\r\n","import { Injectable, Inject } from '@angular/core';\r\nimport { Observable } from 'rxjs';\r\nimport { Entity } from '../../shared/model/entity';\r\n// import { searchCategoriesMock } from '../models/entity-mock';\r\nimport { HttpClient, HttpHeaders, HttpResponse } from '@angular/common/http';\r\nimport { Store } from '@ngrx/store';\r\nimport { Logger } from '../../infrastructure/logger';\r\nimport { applyDownloadLink } from '../documents/documents.helper';\r\nimport { EntityTypeInstance } from '../model/entity-type-instance';\r\nimport { SortOption } from '../model/sort-option';\r\nimport { FilterCategory } from '../model/filter-category';\r\nimport { FilterRangeParameter } from '../model/filter-range-parameter';\r\nimport { HousingUnitsChartHeader } from '../model/housing-units-chart-header';\r\nimport { HousingUnitsChart } from '../model/housing-units-chart';\r\nimport { TargetChart } from '../model/target-chart';\r\nimport { downloadFileFinished, downloadFileStarted } from '../store/filter.actions';\r\nimport { FilterState } from '../store/filter.reducer';\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\nexport class EntityService {\r\n // public pageSize = 5;\r\n // private _entities: Entity[] = [];\r\n // private _entitiesSubject: Subject<Entity[]> = new BehaviorSubject<Entity[]>(this._entities);\r\n\r\n public innerEntitiesProcessHeight: number[] = [];\r\n public cardProcessHeight: number[] = [];\r\n\r\n constructor(\r\n private httpClient: HttpClient,\r\n private store: Store<FilterState>, private logger: Logger,\r\n @Inject('env') protected env: any) { }\r\n\r\n\r\n\r\n public getEntities(filterCategories: FilterCategory[],filtersParametersRange: FilterRangeParameter[], filterTerm: string, skip: number, take: number, presentationTypeId: number,\r\n administrativeCode: number, entrepreneurCode: number, sortId: number)\r\n : Observable<Entity[]> {\r\n const self = this;\r\n return new Observable(observer => {\r\n\r\n const url = `${this.getBaseUrl()}/entities`;\r\n const filtersParameters = filterCategories.map(f => {\r\n return {\r\n parameterId: f.parameterId,\r\n values: f.data.map((d: { dataItem: any; }) => {\r\n return { value: d.dataItem };\r\n })\r\n };\r\n }\r\n );\r\n const requestBody = {\r\n filterTerm,\r\n skip,\r\n take,\r\n presentationTypeId,\r\n filtersParameters,\r\n filtersParametersRange,\r\n sortId\r\n };\r\n const options = {\r\n headers: new HttpHeaders({\r\n 'Content-Type': 'application/json',\r\n })\r\n };\r\n\r\n this.httpClient.post<Entity[]>(url, requestBody, options).subscribe(\r\n response => {\r\n observer.next(response);\r\n observer.complete();\r\n this.logger.debug(`${response.length} Entities have been fetched successfully`);\r\n },\r\n error => {\r\n self.logger.error('An error occurred while fetching entities', error);\r\n observer.error(error);\r\n }\r\n );\r\n });\r\n }\r\n\r\n public downloadResultFile(filterCategories: FilterCategory[], filterParametersRange: FilterRangeParameter[], filterTerm: string)\r\n : Observable<{}> {\r\n // : Observable<{ disposition: string; blobFile: Blob }> {\r\n const self = this;\r\n this.store.dispatch(downloadFileStarted());\r\n return new Observable(observer => {\r\n\r\n const url = `${this.getBaseUrl()}/ExcelExport`;\r\n const filtersParameters = filterCategories.map(f => {\r\n return {\r\n parameterId: f.parameterId,\r\n values: f.data.map((d: { dataItem: any; }) => {\r\n return { value: d.dataItem };\r\n })\r\n };\r\n }\r\n );\r\n const filtersParametersRange = filterParametersRange.map(f => {\r\n return {\r\n parameterMetadataId: f.parameterMetadataId,\r\n valueFrom: f.valueFrom,\r\n valueTo: f.valueTo\r\n };\r\n });\r\n const requestBody = {\r\n filterTerm,\r\n skip: 0,\r\n take: 1000000,\r\n presentationTypeId: 7,\r\n filtersParameters,\r\n filtersParametersRange \r\n };\r\n const options = {\r\n responseType: 'blob' as 'json',\r\n observe: 'response' as 'body',\r\n // withCredentials: true,\r\n headers: new HttpHeaders({\r\n 'content-type': 'application/json',\r\n 'response-type': 'blob' as 'json',\r\n 'Access-Control-Expose-Headers': 'Content-Disposition'\r\n // authorization: 'Bearer my JWT',\r\n // accept: 'text/plain, */*',\r\n // 'Cache-Control': 'no-cache',\r\n })\r\n };\r\n this.httpClient.post(url, requestBody, options).subscribe(\r\n// @ts-ignore\r\n (response: HttpResponse<Blob>) => {\r\n const result = {\r\n// @ts-ignore\r\n blobFile: new Blob([response.body], { type: response.headers.get('Content-Type') }),\r\n disposition: response.headers.get('Content-Disposition')\r\n };\r\n const dataType = result.blobFile.type;\r\n const binaryData = [];\r\n binaryData.push(result.blobFile);\r\n const href = window.URL.createObjectURL(new Blob(binaryData, { type: dataType }));\r\n let filename = null;\r\n if (result.disposition) {\r\n const filenameRegex = /filename[^;=\\n]*=((['\"]).*?\\2|[^;\\n]*)/;\r\n const matches = filenameRegex.exec(result.disposition);\r\n if (matches != null && matches[1]) {\r\n filename = matches[1].replace(/['\"]/g, '');\r\n }\r\n }\r\n applyDownloadLink(href, filename);\r\n this.store.dispatch(downloadFileFinished());\r\n\r\n // observer.next(result);\r\n observer.complete();\r\n this.logger.debug(`File have been fetched successfully`);\r\n },\r\n error => {\r\n self.logger.error('An error occurred while fetching file', error);\r\n observer.error(error);\r\n this.store.dispatch(downloadFileFinished());\r\n }\r\n );\r\n });\r\n }\r\n\r\n\r\n\r\n getEntity(fixedId: string, entityType: EntityTypeInstance, presentationTypeId: number)\r\n : Observable<Entity> {\r\n\r\n const url = `${this.getBaseUrl()}/entities/${fixedId}/${Number(entityType)}/${presentationTypeId}`;\r\n // todo: return native observble\r\n return this.httpClient.get<Entity>(url);\r\n\r\n // }\r\n }\r\n\r\n getEntityByBlockParcel(block: number, parcel: number, entityType: EntityTypeInstance, presentationTypeId: number)\r\n : Observable<Entity> {\r\n // let ntt = this.entities.find((e => e.id === entityCode));\r\n // if (ntt) {\r\n // return of(ntt);\r\n // } else {\r\n const url = `${this.getBaseUrl()}/entities/${block}/${parcel}/${Number(entityType)}/${presentationTypeId}`;\r\n // todo: return native observble\r\n return this.httpClient.get<Entity>(url);\r\n\r\n // }\r\n }\r\n\r\n getEntityBySpecificPresentation(presentationId: number, relatedEntityId: number)\r\n : Observable<Entity> {\r\n const url = `${this.getBaseUrl()}/entities/GetEntityBySpecificPresentation/${presentationId}/${relatedEntityId}`;\r\n // todo: return native observble\r\n return this.httpClient.get<Entity>(url);\r\n\r\n // }\r\n }\r\n\r\n private getBaseUrl(): string {\r\n return this.env.apiUrl;\r\n }\r\n public getSearchCategories(filterCategories: FilterCategory[], filterRangeParameters: FilterRangeParameter[], filterTerm: string, sortId: number)\r\n : Observable<FilterCategory[]> {\r\n\r\n const self = this;\r\n return new Observable(observer => {\r\n const url = `${this.getBaseUrl()}/entities/GetFilterCategories`;\r\n const filtersParameters = filterCategories.map(f => {\r\n return {\r\n parameterId: f.parameterId,\r\n values: f.data.map((d: { dataItem: any; }) => {\r\n return { value: d.dataItem };\r\n })\r\n };\r\n }\r\n );\r\n const requestBody = {\r\n filtersParameters, filterRangeParameters, filterTerm, sortId\r\n };\r\n const options = {\r\n headers: new HttpHeaders({\r\n 'Content-Type': 'application/json',\r\n })\r\n };\r\n\r\n this.httpClient.post<FilterCategory[]>(url, requestBody, options).subscribe(\r\n response => {\r\n\r\n observer.next(response);\r\n self.logger.info('Fetch search categories completed');\r\n observer.complete();\r\n },\r\n error => {\r\n self.logger.error('An error occurred while fetching search categories', error);\r\n observer.error(error);\r\n }\r\n );\r\n });\r\n }\r\n\r\n public getHousingUnitsCharts(filterCategories: FilterCategory[],filtersCategoryRange: FilterRangeParameter[], filterTerm: string)\r\n : Observable<HousingUnitsChart[]> {\r\n\r\n const self = this;\r\n return new Observable(observer => {\r\n const url = `${this.getBaseUrl()}/entities/GetHousingUnitsCharts`;\r\n const filtersParameters = filterCategories.map(f => {\r\n return {\r\n parameterId: f.parameterId,\r\n values: f.data.map((d: { dataItem: any; }) => {\r\n return { value: d.dataItem };\r\n })\r\n };\r\n }\r\n );\r\n const filtersParametersRange = filtersCategoryRange.map(f => {\r\n return {\r\n parameterMetadataId: f.parameterMetadataId,\r\n valueFrom: f.valueFrom,\r\n valueTo: f.valueTo\r\n };\r\n });\r\n const requestBody = {\r\n filtersParameters, filtersParametersRange, filterTerm \r\n };\r\n const options = {\r\n headers: new HttpHeaders({\r\n 'Content-Type': 'application/json',\r\n })\r\n };\r\n\r\n this.httpClient.post<HousingUnitsChart[]>(url, requestBody, options).subscribe(\r\n response => {\r\n\r\n observer.next(response);\r\n self.logger.info('Fetch housing units charts completed');\r\n observer.complete();\r\n },\r\n error => {\r\n self.logger.error('An error occurred while fetching housing units charts', error);\r\n observer.error(error);\r\n }\r\n );\r\n });\r\n }\r\n\r\n public getHousingUnitsChartsHeaders(filterCategories: FilterCategory[],filtersCategoryRange: FilterRangeParameter[], filterTerm: string)\r\n : Observable<HousingUnitsChartHeader[]> {\r\n\r\n const self = this;\r\n return new Observable(observer => {\r\n const url = `${this.getBaseUrl()}/entities/GetHousingUnitsChartsHeaders`;\r\n const filtersParameters = filterCategories.map(f => {\r\n return {\r\n parameterId: f.parameterId,\r\n values: f.data.map((d: { dataItem: any; }) => {\r\n return { value: d.dataItem };\r\n })\r\n };\r\n }\r\n );\r\n const filtersParametersRange = filtersCategoryRange.map(f => {\r\n return {\r\n parameterMetadataId: f.parameterMetadataId,\r\n valueFrom: f.valueFrom,\r\n valueTo: f.valueTo\r\n };\r\n });\r\n const requestBody = {\r\n filtersParameters,filtersParametersRange, filterTerm \r\n };\r\n const options = {\r\n headers: new HttpHeaders({\r\n 'Content-Type': 'application/json',\r\n })\r\n };\r\n\r\n this.httpClient.post<HousingUnitsChartHeader[]>(url, requestBody, options).subscribe(\r\n response => {\r\n\r\n observer.next(response);\r\n self.logger.info('Fetch housing units charts headers completed');\r\n observer.complete();\r\n },\r\n error => {\r\n self.logger.error('An error occurred while fetching housing units charts headers.', error);\r\n observer.error(error);\r\n }\r\n );\r\n });\r\n }\r\n\r\n public getTargetCharts()\r\n : Observable<TargetChart[]> {\r\n\r\n const self = this;\r\n return new Observable(observer => {\r\n const url = `${this.getBaseUrl()}/entities/GetTargetCharts`;\r\n // const filtersParameters = filterCategories.map(f => {\r\n // return {\r\n // parameterId: f.parameterId,\r\n // values: f.data.map(d => {\r\n // return { value: d.dataItem };\r\n // })\r\n // };\r\n // }\r\n // );\r\n const requestBody = {\r\n //filtersParameters, filterTerm\r\n };\r\n const options = {\r\n headers: new HttpHeaders({\r\n 'Content-Type': 'application/json',\r\n })\r\n };\r\n\r\n this.httpClient.get<TargetChart[]>(url, options).subscribe(\r\n response => {\r\n\r\n observer.next(response);\r\n self.logger.info('Fetch target charts completed');\r\n observer.complete();\r\n },\r\n error => {\r\n self.logger.error('An error occurred while fetching target charts', error);\r\n observer.error(error);\r\n }\r\n );\r\n });\r\n }\r\n\r\n public getStatusEntities(processId: number): Observable<Entity[]> {\r\n\r\n const self = this;\r\n return new Observable(observer => {\r\n const url = `${this.getBaseUrl()}/entities/GetStatusEntities`;\r\n const requestBody = { processId };\r\n const options = {\r\n headers: new HttpHeaders({\r\n 'Content-Type': 'application/json',\r\n })\r\n };\r\n\r\n this.httpClient.post<Entity[]>(url, requestBody, options).subscribe(\r\n response => {\r\n observer.next(response);\r\n self.logger.info(`Get entitiesStatus completed`);\r\n observer.complete();\r\n },\r\n error => {\r\n self.logger.error(`An error occurred while get entitiesStatus`, error);\r\n observer.error(error);\r\n }\r\n );\r\n });\r\n }\r\n\r\n getEntityTemplate(entityTypeId: number, presentationTypeId: number, parentRangeId?: string): Observable<Entity> {\r\n const self = this;\r\n return new Observable(observer => {\r\n let url;\r\n if (parentRangeId) {\r\n url = `${this.getBaseUrl()}/entities/GetEntityTemplate/${entityTypeId}/${presentationTypeId}/${parentRangeId}`;\r\n } else {\r\n url = `${this.getBaseUrl()}/entities/GetEntityTemplate/${entityTypeId}/${presentationTypeId}/0`;\r\n\r\n }\r\n // const requestBody = { entityTypeId: entityTypeId };\r\n // const options = {\r\n // headers: new HttpHeaders({\r\n // 'Content-Type': 'application/json',\r\n // })\r\n // };\r\n\r\n this.httpClient.get<Entity>(url).subscribe(\r\n response => {\r\n observer.next(response);\r\n self.logger.info(`Add&Get entitiy completed`);\r\n observer.complete();\r\n },\r\n error => {\r\n self.logger.error(`An error occurred while add&get entity`, error);\r\n observer.error(error);\r\n }\r\n );\r\n });\r\n }\r\n\r\n markSuperRange(entityId: string, isSuperRange: boolean): Observable<{}> {\r\n const self = this;\r\n return new Observable(observer => {\r\n const url = `${this.getBaseUrl()}/entities/MarkSuperRange/${entityId}`;\r\n const options = {\r\n headers: new HttpHeaders({\r\n 'Content-Type': 'application/json',\r\n })\r\n };\r\n this.httpClient.post(url, isSuperRange, options).subscribe(\r\n response => {\r\n observer.next(response);\r\n self.logger.info(`Mark entity ${entityId} as super range completed`);\r\n observer.complete();\r\n },\r\n error => {\r\n self.logger.error(`An error occurred while mark entity ${entityId} as super range`, error);\r\n observer.error(error);\r\n }\r\n );\r\n });\r\n }\r\n\r\n\r\n\r\n deleteEntity(entityId: number): Observable<Entity> {\r\n const self = this;\r\n return new Observable(observer => {\r\n const url = `${this.getBaseUrl()}/entities/Delete/${entityId}`;\r\n this.httpClient.delete<Entity>(url).subscribe(\r\n response => {\r\n observer.next(response);\r\n self.logger.info(`Delete entitiy completed`);\r\n observer.complete();\r\n },\r\n error => {\r\n self.logger.error(`An error occurred while delete entity`, error);\r\n observer.error(error);\r\n }\r\n );\r\n });\r\n }\r\n\r\n getSortOptions(entityMetadataId: number)\r\n : Observable<SortOption[]> {\r\n const url = `${this.getBaseUrl()}/entities/GetSortOptions/${entityMetadataId}`;\r\n // todo: return native observble\r\n return this.httpClient.get<SortOption[]>(url);\r\n\r\n // }\r\n }\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport { HttpClient, HttpHeaders } from '@angular/common/http';\r\nimport { UploadConfig, UploadParams } from './azure-file-upload-bl.service';\r\nimport { Observable } from 'rxjs';\r\n\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\nexport class AzurestorageService {\r\n static DefaultBlockSize = 1024 * 500;\r\n constructor(private http: HttpClient) { }\r\n generateBlobUrl(\r\n params: UploadParams,\r\n filename: string,\r\n useAzureStorageEmulator = false,\r\n azureStorageEmulatorBaseUrl = '') {\r\n const url = useAzureStorageEmulator ? azureStorageEmulatorBaseUrl : `https://${params.storageAccount}.blob.core.windows.net`;\r\n return `${url}/${params.containerName}/${filename}`;\r\n }\r\n private uploadFileInBlocks(reader: FileReader, state: any) {\r\n if (!state.cancelled) {\r\n if (state.totalBytesRemaining > 0) {\r\n const fileContent = state.file.slice(state.currentFilePointer, state.currentFilePointer + state.maxBlockSize);\r\n const blockId = state.blockIdPrefix + this.prependZeros(state.blockIds.length, 6);\r\n state.blockIds.push(btoa(blockId));\r\n reader.readAsArrayBuffer(fileContent);\r\n state.currentFilePointer += state.maxBlockSize;\r\n state.totalBytesRemaining -= state.maxBlockSize;\r\n if (state.totalBytesRemaining < state.maxBlockSize) {\r\n state.maxBlockSize = state.totalBytesRemaining;\r\n }\r\n } else {\r\n this.commitBlockList(state);\r\n }\r\n }\r\n }\r\n private commitBlockList(state: { fileUrl: string; file: { type: any; }; blockIds: string | any[]; complete: () => void; error: (arg0: any) => void; }) {\r\n const uri = state.fileUrl + '&comp=blocklist';\r\n const headers = new HttpHeaders({ 'x-ms-blob-content-type': state.file.type });\r\n let requestBody = '<?xml version=\\'1.0\\' encoding=\\'utf-8\\'?><BlockList>';\r\n for (let i = 0; i < state.blockIds.length; i++) {\r\n requestBody += '<Latest>' + state.blockIds[i] + '</Latest>';\r\n }\r\n requestBody += '</BlockList>';\r\n\r\n this.http.put(uri, requestBody, { headers, responseType: 'text' })\r\n .subscribe(elem => {\r\n if (state.complete) {\r\n state.complete();\r\n }\r\n }, err => {\r\n console.log({ error: err });\r\n if (state.error) {\r\n state.error(err);\r\n }\r\n });\r\n }\r\n private initializeState(config: UploadConfig) {\r\n let blockSize = AzurestorageService.DefaultBlockSize;\r\n if (config.blockSize) {\r\n blockSize = config.blockSize;\r\n }\r\n let maxBlockSize = blockSize;\r\n let numberOfBlocks = 1;\r\n const file = config.file;\r\n const fileSize = file.size;\r\n if (fileSize < blockSize) {\r\n maxBlockSize = fileSize;\r\n }\r\n if (fileSize % maxBlockSize === 0) {\r\n numberOfBlocks = fileSize / maxBlockSize;\r\n } else {\r\n numberOfBlocks = fileSize / maxBlockSize + 1;\r\n }\r\n\r\n\r\n\r\n return {\r\n maxBlockSize, // Each file will be split in 256 KB.\r\n numberOfBlocks,\r\n totalBytesRemaining: fileSize,\r\n currentFilePointer: 0,\r\n blockIds: new Array(),\r\n blockIdPrefix: 'block-',\r\n bytesUploaded: 0,\r\n submitUri: null,\r\n file,\r\n baseUrl: config.baseUrl,\r\n sasToken: config.sasToken,\r\n fileUrl: `${config.baseUrl}?${config.sasToken}`,\r\n progress: config.progress,\r\n complete: config.complete,\r\n error: config.error,\r\n cancelled: false\r\n };\r\n }\r\n upload(config: UploadConfig){\r\n const state = this.initializeState(config);\r\n\r\n const reader = new FileReader();\r\n reader.onloadend = (evt: any) => {\r\n if (evt.target.readyState === 2 && !state.cancelled) {\r\n const uri = state.fileUrl + '&comp=block&blockid=' + state.blockIds[state.blockIds.length - 1];\r\n const requestData = evt.target.result;\r\n const requestData2 = new Uint8Array(evt.target.result);\r\n const headers = new HttpHeaders({ 'x-ms-blob-type': 'BlockBlob', 'Content-Type': 'application/octet-stream' });\r\n this.http.put(uri, requestData, { headers, responseType: 'text' })\r\n .subscribe(elem => {\r\n state.bytesUploaded += requestData2.length;\r\n const percentComplete = Math.round((state.bytesUploaded / state.file.size) * 1000) / 10;\r\n if (state.progress) {\r\n state.progress(percentComplete);\r\n }\r\n\r\n this.uploadFileInBlocks(reader, state);\r\n }, err => {\r\n console.log({ error: err });\r\n if (state.error) {\r\n state.error(err);\r\n }\r\n });\r\n }\r\n };\r\n\r\n this.uploadFileInBlocks(reader, state);\r\n\r\n return {\r\n cancel: () => {\r\n state.cancelled = true;\r\n }\r\n };\r\n }\r\n private prependZeros(num: string, length: number) {\r\n let str = '' + num;\r\n while (str.length < length) {\r\n str = '0' + str;\r\n }\r\n return str;\r\n }\r\n}\r\n","import { Inject, Injectable } from '@angular/core';\r\nimport { HttpClient } from '@angular/common/http';\r\nimport { OAuthService } from 'angular-oauth2-oidc';\r\nimport { Logger } from '../logger';\r\n\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\nexport abstract class ApiBaseService {\r\n\r\n\r\n constructor(protected http: HttpClient,\r\n protected logger: Logger, protected oauthService: OAuthService, @Inject('env') protected env: any) { }\r\n\r\n protected get baseUrl(): string {\r\n return `${this.env.apiUrl}`;\r\n }\r\n}\r\n","import { Inject, Injectable, OnDestroy } from '@angular/core';\r\nimport { Observable, Subscription } from 'rxjs';\r\nimport { HttpHeaders, HttpClient } from '@angular/common/http';\r\nimport { OAuthService } from 'angular-oauth2-oidc';\r\nimport { AzurestorageService } from './azure-storage.service';\r\nimport { ApiBaseService } from '../../infrastructure/data/api-base.service';\r\nimport { Logger } from '../../infrastructure/logger';\r\nimport { UploadFileData } from '../services/update-entity.service';\r\n\r\n\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\nexport class StorageService extends ApiBaseService implements OnDestroy {\r\n\r\n uploadConfig!: UploadConfig;\r\n percent!: number;\r\n currentFileName!: string;\r\n private subscriptions: Subscription[] = [];\r\n\r\n constructor(protected override http: HttpClient,\r\n protected override logger: Logger, protected override oauthService: OAuthService, private blobService: AzurestorageService, @Inject('env') protected override env: any) {\r\n super(http, logger, oauthService, env);\r\n }\r\n ngOnDestroy(): void {\r\n this.subscriptions.forEach(subscription => {\r\n if (subscription) {\r\n subscription.unsubscribe();\r\n }\r\n });\r\n }\r\n public getSAS(fileName: string): Observable<string> {\r\n const self = this;\r\n return new Observable(observer => {\r\n const url = `${this.baseUrl}/storage/GetSAS?fileName=${fileName}`;\r\n // const requestBody = entityForUpdate;\r\n const options = {\r\n responseType: 'text' as 'json',\r\n headers: new HttpHeaders({\r\n 'Content-Type': 'application/text',\r\n })\r\n };\r\n self.subscriptions.push(this.http.get<string>(url, options).subscribe(\r\n response => {\r\n observer.next(response);\r\n\r\n observer.complete();\r\n },\r\n error => {\r\n self.logger.error(`An error occurred while get SAS token`, error);\r\n observer.error(error);\r\n }\r\n ));\r\n });\r\n }\r\n\r\n public getReadSASTokenURL(fileName: string): Observable<string> {\r\n const self = this;\r\n return new Observable(observer => {\r\n const url = `${this.baseUrl}/storage/GetReadSASTokenURL?fileName=${fileName}`;\r\n const options = {\r\n responseType: 'text' as 'json',\r\n headers: new HttpHeaders({\r\n 'Content-Type': 'application/text',\r\n })\r\n };\r\n self.subscriptions.push(this.http.get<string>(url, options).subscribe(\r\n response => {\r\n observer.next(response);\r\n observer.complete();\r\n },\r\n error => {\r\n self.logger.error(`An error occurred while get SAS token url`, error);\r\n observer.error(error);\r\n }\r\n ));\r\n });\r\n }\r\n\r\n public UploadFilesData(uploadFilesData: UploadFileData[])\r\n : Observable<boolean> {\r\n const self = this;\r\n let filesUploadCounter = 0;\r\n return new Observable(observer => {\r\n for (const fileData of uploadFilesData) {\r\n // const originalFileName = fileData.file.name;\r\n // const fileName = getFileName(entityId, fileData.parameterMetadataId, originalFileName);\r\n self.subscriptions.push(this.uploadFileByToken(fileData.file, fileData.storedFileName, fileData.file.type)\r\n .subscribe(isUpload => {\r\n if (isUpload) {\r\n filesUploadCounter++;\r\n if (filesUploadCounter == uploadFilesData.length) {\r\n observer.next(true);\r\n observer.complete();\r\n }\r\n } else {\r\n observer.error();\r\n }\r\n }, error => {\r\n observer.error();\r\n }));\r\n }\r\n\r\n });\r\n }\r\n\r\n // upload(formData: FormData) {\r\n // return this.http.post<{ path: string }>(\r\n // 'https://localhost:5001/api/storage/uploadfile',\r\n // formData\r\n // );\r\n // }\r\n // public uploadFile(fileName: string)\r\n // : Observable<any> {\r\n\r\n // const self = this;\r\n\r\n // return new Observable(observer => {\r\n // const url = `${this.baseUrl}/storage/GetSAS?fileName=` + fileName;\r\n // // const requestBody = entityForUpdate;\r\n // const options = {\r\n // responseType: 'text',\r\n // headers: new HttpHeaders({\r\n // 'Content-Type': 'application/text',\r\n // })\r\n // };\r\n // this.http.get<string>(url).subscribe(\r\n // response => {\r\n // observer.next(response);\r\n\r\n // observer.complete();\r\n // },\r\n // error => {\r\n // self.logger.error(`An error occurred while get SAS token`, error);\r\n // observer.error(error);\r\n // }\r\n // );\r\n // });\r\n // }\r\n\r\n uploadFileByToken(file: File, fileName: string, mimeType: string): Observable<boolean> {\r\n const self = this;\r\n return new Observable(observer => {\r\n // this.signalr.startConnection().then(connectionId => {\r\n // console.log('SIGNALR ConnectionId', connectionId);\r\n self.currentFileName = fileName;\r\n const fileToSAS = { FileName: fileName, MimeType: mimeType };\r\n // const fileToSAS: FileToToken = { FileName: fileName, MimeType: mimeType };\r\n self.subscriptions.push(self.getSasTokenWrite(fileName).subscribe(sas => {\r\n self.subscriptions.push(self.uploadFile(file, sas, fileName).subscribe(isUpload => {\r\n observer.next(isUpload);\r\n //observer.complete();\r\n }));\r\n },\r\n ));\r\n\r\n // }).catch(\r\n // err => {\r\n // this.showErrr(err);\r\n // }\r\n // );\r\n });\r\n }\r\n\r\n getSasTokenWrite(file: string): Observable<string> {\r\n // return this.azureFileUploadService.getSasTokenWrite(file);\r\n return this.getSAS(file);\r\n }\r\n\r\n uploadFile(file: File, token: string, fileName?: string): Observable<boolean> {\r\n const self = this;\r\n return new Observable(observer => {\r\n const Config: UploadParams = {\r\n sas: token,\r\n storageAccount: this.env.azureStorageConfig.storageAccount,\r\n containerName: this.env.azureStorageConfig.containerName\r\n };\r\n const res = false;\r\n if (file !== null) {\r\n const fileTitle = fileName == null ? file.name : fileName;\r\n const baseUrl = 'https://' + Config.storageAccount + '/' + Config.containerName + '/' + fileTitle;\r\n this.uploadConfig = {\r\n baseUrl,\r\n blockSize: 1024 * 500,\r\n sasToken: Config.sas,\r\n file,\r\n complete: () => {\r\n console.log('Transfer completed !');\r\n observer.next(true);\r\n observer.complete();\r\n // this.saveFileSuccess(isSave);\r\n },\r\n error: (err) => {\r\n console.log('Transfer Error:', err);\r\n this.saveFileError(err);\r\n observer.next(false);\r\n observer.error(err);\r\n },\r\n progress: (percent) => {\r\n this.percent = percent;\r\n }\r\n };\r\n this.blobService.upload(this.uploadConfig);\r\n }\r\n });\r\n }\r\n saveFileError(error: any) {\r\n console.log('saveFileError', error);\r\n }\r\n}\r\nexport class UploadParams {\r\n sas!: string;\r\n storageAccount!: string;\r\n containerName!: string;\r\n}\r\nexport class UploadConfig {\r\n baseUrl!: string;\r\n blockSize!: number;\r\n sasToken!: string;\r\n file!: File;\r\n complete!: () => void;\r\n error!: (err: any) => void;\r\n progress!: (percent: any) => void;\r\n}\r\n\r\n\r\n","\r\nexport function getTime(date?: Date) {\r\n return date != null ? new Date(date).getTime() : 0;\r\n}\r\n","export enum EntityTypeInstance {\r\n range = 1,\r\n taxationSubRange = 2,\r\n program = 3,\r\n building = 4,\r\n apartment = 5,\r\n blockParcel = 6,\r\n contact = 7,\r\n discussion = 10,\r\n landZoning = 13,\r\n parcel = 14,\r\n localAuthoritieSubRange = 15,\r\n tama38 = 16,\r\n preliminaryRequest = 17,\r\n declarationRequest = 18,\r\n parcelRequest = 21,\r\n constructionEvacuationRequest = 22,\r\n barry = 23,\r\n contract = 24,\r\n entrepreneurContacts = 25,\r\n RangeRequest = 26,\r\n SubRangeRequest = 27,\r\n task = 28,\r\n permitCondition = 29,\r\n programRequest = 30,\r\n permitExpect = 31,\r\n document = 32,\r\n firstSort = 34,\r\n secondSort = 35,\r\n landUse = 36,\r\n withoutFunding = 37,\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n tiyuv_tama38 = 101,\r\n request = 102,\r\n permit = 103,\r\n certificate = 104,\r\n stage = 105,\r\n use = 106\r\n\r\n}\r\n","\r\nimport { Entity, EntityBase } from './entity';\r\nimport { EntityDetailsViewModel, ParametersGroup, MasterEntityDetailsViewModel } from './entity-details.view-model';\r\nimport { AnyParameter, SimpleParameter, EntityParameter, EntityViewModelParameter } from './entity-parameter';\r\nimport { plural } from 'pluralize';\r\nimport { getTime } from '../../infrastructure/date.utility';\r\nimport { EntityTypeInstance } from './entity-type-instance';\r\nexport function getMasterEntityViewModel(entity: Entity): MasterEntityDetailsViewModel {\r\n return getViewModel(entity, true) as MasterEntityDetailsViewModel;\r\n}\r\nexport function getEntityViewModel(entity: Entity): EntityDetailsViewModel {\r\n return getViewModel(entity, false);\r\n}\r\n// function getTime(date?: Date) {\r\n// return date != null ? new Date(date).getTime() : 0;\r\n// }\r\nfunction getViewModel(entity: Entity, isMaster: boolean): EntityDetailsViewModel {\r\n const groupsMap = new Map<number, AnyParameter[]>();\r\n entity.parameters.forEach((param) => {\r\n const key = param.parametersGroupOrder;\r\n const collection = groupsMap.get(key);\r\n if (!collection) {\r\n groupsMap.set(key, [param]);\r\n } else {\r\n collection.push(param);\r\n }\r\n });\r\n // tslint:disable-next-line: one-variable-per-declaration\r\n const groups: ParametersGroup[] = [...groupsMap.entries()].sort()\r\n .map((params) => {\r\n const grp = new ParametersGroup();\r\n grp.order = params[0];\r\n grp.parameters = params[1]\r\n .map(p => {\r\n if (isSimpleParameter(p)) {\r\n return p;\r\n } else {\r\n const entityParameter = p as EntityParameter;\r\n return {\r\n ...entityParameter,\r\n value: entityParameter.value ? entityParameter.value.map(ntt => getEntityViewModel(ntt)) : []\r\n };\r\n }\r\n })\r\n .sort((p1, p2) => p1.order - p2.order);\r\n return grp;\r\n }\r\n );\r\n const processes = entity.processes\r\n .map(prcs => ({\r\n ...prcs,\r\n entities: prcs.entities.map(ntt => getEntityViewModel(ntt)),\r\n editEntities: prcs.editEntities ? prcs.editEntities.map(ntt => getEntityViewModel(ntt)) : null,\r\n // resAppExpansionView: prcs.resAppExpansionView ? getEntityViewModel(prcs.resAppExpansionView) : null,\r\n resAppToggledView: prcs.resAppToggledView ? getEntityViewModel(prcs.resAppToggledView) : null,\r\n }))\r\n .sort((p1, p2) => p1.order - p2.order);\r\n const comments = entity.comments ? entity.comments.map(c => {\r\n const newComment = Object.assign(c, {});\r\n newComment.date = new Date(c.date);\r\n return newComment;\r\n }).sort((c1, c2) => getTime(c2.date) - getTime(c1.date)) : [];\r\n\r\n processes.forEach(p => {\r\n p.statuses = p.statuses.sort((s1, s2) => s1.order - s2.order);\r\n p.statuses.forEach(status => status.entitiesStatus = status.entitiesStatus.sort((e1, e2) => getTime(e2.date) - getTime(e1.date)));\r\n });\r\n const entityBase: EntityBase = entity as EntityBase;\r\n const viewModel: EntityDetailsViewModel = {\r\n ...entityBase,\r\n id: entity.id,\r\n description: entity.entityMetadata.description,\r\n shortDescription: entity.entityMetadata.shortDescription,\r