import { Component , OnDestroy , OnInit , TemplateRef , ViewChild } from '@angular/core' ; import { ReplaySubject } from 'rxjs' ; import { ObjectService } from '../services/object.service' ; import { CmdbObject } from '../models/cmdb-object' ; import { RenderResult } from '../models/cmdb-render' ; import { APIGetMultiResponse } from '../../services/models/api-response' ; import { Column , Sort , SortDirection } from '../../layout/table/table.types' ; import { CollectionParameters } from '../../services/models/api-parameter' ; import { takeUntil } from 'rxjs/operators' ; import { ToastService } from '../../layout/toast/toast.service' ; @ Component ( { selector : 'cmdb-object' , templateUrl : './object.component.html' , styleUrls : [ './object.component.scss' ] } ) export class ObjectComponent implements OnInit , OnDestroy { private private subscriber : ReplaySubject < void > ; /**
     * HTML ID of the table.
     */ public readonly id : string = 'type-list-table' ; /**
     * Empty table info.
     */ public readonly emptyTableInformation : string = 'No objects found!' ; /**
     * Default table info.
     */ public readonly loadingTableInformation : string = 'Objects loading...' ; /**
     * Table info.
     */ public tableInformation : string = this . emptyTableInformation ; /**
     * Displayed objects.
     */ public objects : Array < CmdbObject | RenderResult > = [ ] ; /**
     * API Response of the objects call.
     */ public objectsAPIResponse : APIGetMultiResponse < CmdbObject | RenderResult > ; /**
     * Total number of objects in the database.
     */ public totalObjects : number = 0 ; /**
     * Columns at the beginning of the loading.
     */ public initialVisibleColumns : Array < string > = [ ] ; /**
     * Table columns definition.
     */ public columns : Array < Column > = [ ] ; /**
     * Begin with first page.
     */ public readonly initPage : number = 1 ; public page : number = this . initPage ; private private readonly initLimit : number = 25 ; public limit : number = this . initLimit ; /**
     * Filter query from the table search input.
     */ public filter : string ; /**
     * Default sort filter.
     */ public sort : Sort = { name : 'public_id' , order : SortDirection . DESCENDING } as Sort ; /**
     * Loading indicator.
     */ public loading : boolean = false ; /**
     * Table Template: Active column.
     */ @ ViewChild ( 'activeTemplate' , { static : true } ) activeTemplate : TemplateRef < any > ; /**
     * Table Template: Type name column.
     */ @ ViewChild ( 'typeNameTemplate' , { static : true } ) typeNameTemplate : TemplateRef < any > ; /**
     * Table Template: Type date column.
     */ @ ViewChild ( 'dateTemplate' , { static : true } ) dateTemplate : TemplateRef < any > ; /**
     * Table Template: Last edit column.
     */ @ ViewChild ( 'lastEditTemplate' , { static : true } ) lastEditTemplate : TemplateRef < any > ; /**
     * Table Template: Action column.
     */ @ ViewChild ( 'actionTemplate' , { static : true } ) actionTemplate : TemplateRef < any > ; constructor ( private objectService , private toastService ) { this . subscriber = new ReplaySubject < void > ( ) ; } public ngOnInit ( ) { const columns = [ { display : 'Active' , name : 'active' , data : 'object_information.active' , searchable : false , sortable : true , template : this . activeTemplate , style : { width : '6rem' } } , { display : 'Public ID' , name : 'public_id' , data : 'object_information.object_id' , searchable : true , sortable : true } , { display : 'Type' , name : 'type.name' , data : 'type_information' , searchable : true , sortable : true , template : this . typeNameTemplate , } , { display : 'Summary' , name : 'summary_line' , data : 'summary_line' , searchable : false , sortable : false } , { display : 'Author' , name : 'author.user_name' , data : 'object_information.author_name' , searchable : true , sortable : true } , { display : 'Creation' , name : 'creation_time' , data : 'object_information.creation_time' , searchable : true , sortable : true , template : this . dateTemplate , } , { display : 'Last editor' , name : 'editor.user_name' , data : 'object_information.editor_name' , searchable : true , sortable : true } , { display : 'Last modification' , name : 'last_edit_time' , data : 'object_information.last_edit_time' , searchable : true , sortable : true , template : this . lastEditTemplate , } , { display : 'Actions' , name : 'actions' , data : 'object_information.object_id' , sortable : false , searchable : false , fixed : true , template : this . actionTemplate , cssClasses : [ 'text-center' ] , style : { width : '6em' } } ] as Array < Column > ; this . initialVisibleColumns = columns . filter ( c => ! c . hidden ) . map ( c => c . name ) ; this . columns = [ ... columns ] ; this . loadObjectsFromAPI ( ) ; } private setLoadingState ( isLoading ) { this . loading = isLoading ; this . tableInformation = this . loading ? this . loadingTableInformation : this . emptyTableInformation ; } private private loadObjectsFromAPI ( ) { this . setLoadingState ( true ) ; const filter = this . filterBuilder ( ) ; const params = { filter , limit : this . limit , sort : this . sort . name , order : this . sort . order , page : this . page } ; this . objectService . getObjects ( params ) . pipe ( takeUntil ( this . subscriber ) ) . subscribe ( ( apiResponse ) => { this . objectsAPIResponse = apiResponse ; this . objects = apiResponse . results as Array < RenderResult > ; this . totalObjects = apiResponse . total ; } , ( error ) => this . toastService . error ( error ) , ( ) => this . setLoadingState ( false ) ) ; } return query  {@link: any[]} private filterBuilder ( ) { let query ; if ( this . filter ) { query = [ ] ; const or = [ ] ; query . push ( { $lookup : { from : 'framework.objects' , localField : 'fields.value' , foreignField : 'public_id' , as : 'data' } } ) ; query . push ( { $project : { _id : 1 , public_id : 1 , type_id : 1 , active : 1 , author_id : 1 , creation_time : 1 , last_edit_time : 1 , fields : 1 , simple : { $reduce : { input : '$data.fields' , initialValue : [ ] , in : { $setUnion : [ '$$value' , '$$this' ] } } } } } ) ; query . push ( { $group : { _id : '$_id' , public_id : { $first : '$public_id' } , type_id : { $first : '$type_id' } , active : { $first : '$active' } , author_id : { $first : '$author_id' } , creation_time : { $first : '$creation_time' } , last_edit_time : { $first : '$last_edit_time' } , fields : { $first : '$fields' } , simple : { $first : '$simple' } , } } ) ; query . push ( { $project : { _id : '$_id' , public_id : 1 , type_id : 1 , active : 1 , author_id : 1 , creation_time : 1 , last_edit_time : 1 , fields : 1 , references : { $setUnion : [ '$fields' , '$simple' ] } , } } ) ; query . push ( { $addFields : { creationString : { $dateToString : { format : '%Y-%m-%dT%H:%M:%S.%LZ' , date : '$creation_time' } } } } ) ; query . push ( { $addFields : { editString : { $dateToString : { format : '%Y-%m-%dT%H:%M:%S.%LZ' , date : '$last_edit_time' } } } } ) ; query . push ( { $addFields : { references : { $map : { input : '$references' , as : 'new_fields' , in : { $cond : [ { $eq : [ { $type : '$$new_fields.value' } , 'date' ] } , { name : '$$new_fields.name' , value : { $dateToString : { format : '%Y-%m-%dT%H:%M:%S.%LZ' , date : '$$new_fields.value' } } } , { name : '$$new_fields.name' , value : '$$new_fields.value' } ] } } } } } ) ; query . push ( { $addFields : { public_id : { $toString : '$public_id' } } } ) ; or . push ( { public_id : { $elemMatch : { value : { $regex : String ( this . filter ) , $options : 'ism' } } } } ) ; or . push ( { creationString : { $regex : String ( this . filter ) , $options : 'ims' } } ) ; or . push ( { editString : { $regex : String ( this . filter ) , $options : 'ims' } } ) ; or . push ( { references : { $elemMatch : { value : { $regex : String ( this . filter ) , $options : 'ism' } } } } ) ; query . push ( { $match : { $or : or } } ) ; } return query ; } param sort public onSortChange ( sort ) { this . sort = sort ; this . loadObjectsFromAPI ( ) ; } param page public onPageChange ( page ) { this . page = page ; this . loadObjectsFromAPI ( ) ; } param limit public onPageSizeChange ( limit ) { this . limit = limit ; this . page = this . initPage ; this . loadObjectsFromAPI ( ) ; } param search public onSearchChange ( search ) { if ( search ) { this . filter = search ; } else { this . filter = undefined ; } this . loadObjectsFromAPI ( ) ; } param objectID public onObjectDelete ( objectID ) { this . objectService . deleteObject ( objectID ) . pipe ( takeUntil ( this . subscriber ) ) . subscribe ( ( ) => { this . toastService . success ( `Object ${ objectID } was deleted successfully` ) ; this . loadObjectsFromAPI ( ) ; } , ( error ) => { this . toastService . error ( `Error while deleting object ${ objectID } | Error: ${ error }` ) ; } ) ; } /**
     * Destroy subscriptions after closed.
     */ public ngOnDestroy ( ) { this . subscriber . next ( ) ; this . subscriber . complete ( ) ; } }