import { IRawRepairTask } from '../RawDataTypes' ; import { TimeUtils } from 'src/app/Utils/TimeUtils' ; import { DataModelBase } from './Base' ; import { DataService } from 'src/app/services/data.service' ; import { Observable , of } from 'rxjs' ; export enum RepairJobType { TenantUpdate = 'TenantUpdate' , PlatformUpdate = 'PlatformUpdate' , TenantMaintenance = 'TenantMaintenance' , PlatformMaintenance = 'PlatformMaintenance' } export interface IRepairTaskHistoryPhase { timestamp : string ; phase : string ; duration : string ; durationMilliseconds : number ; displayInfo : IDisplayStatus ; } export interface IDisplayStatus { badgeIcon : string ; status : string ; statusCss : string ; } export interface IRepairTaskPhase { name : string ; duration : string ; durationMilliseconds : number ; phases : IRepairTaskHistoryPhase [ ] ; startCollapsed : boolean ; status : string ; statusCss : string ; } export enum StatusCSS { Finished = 'repair-green' , InProgress = 'repair-blue' , NotStarted = 'repair-gray' } export const FinishedStatus = { badgeIcon : 'mif-done' , status : 'This step is Finished' , statusCss : StatusCSS . Finished } ; export const InProgressStatus = { badgeIcon : 'mif-spinner4' , status : 'This step is in progress' , statusCss : StatusCSS . InProgress } ; export const NotStartedStatus = { badgeIcon : '' , status : 'This step is not started' , statusCss : StatusCSS . NotStarted } ; export class RepairTask extends DataModelBase < IRawRepairTask > { public static readonly ExecutingStatus = 'Executing' ; public static readonly PreparingStatus = 'Preparing' ; public static NonStartedTimeStamp = '0001-01-01T00:00:00.000Z' ; public get id ( ) : string { return this . raw . TaskId ; } public isSecondRowCollapsed = true ; public activeTab = 1 ; public impactedNodes : string [ ] = [ ] ; public history : IRepairTaskHistoryPhase [ ] = [ ] ; private timeStampsCollapses : Record < string , boolean > = { } ; public createdAt = '' ; public couldParseExecutorData = false ; public inProgress = true ; public duration : number ; public displayDuration : string ; public historyPhases : IRepairTaskPhase [ ] ; public executorData : any ; constructor ( public dataService , public raw , private dateRef ? ) { super ( dataService , raw ) ; this . updateInternal ( ) ; } public get startTime ( ) : Date { return new Date ( this . raw . History . ExecutingUtcTimestamp === RepairTask . NonStartedTimeStamp ? this . raw . History . CreatedUtcTimestamp : this . raw . History . ExecutingUtcTimestamp ) ; } private getRefDate ( ) { return this . dateRef || new Date ( ) ; } private parseHistory ( ) { let history = [ { timestamp : this . raw . History . ClaimedUtcTimestamp , phase : 'Claimed' } , { timestamp : this . raw . History . CreatedUtcTimestamp , phase : 'Created' } , { timestamp : this . raw . History . PreparingUtcTimestamp , phase : 'Preparing' } , { timestamp : this . raw . History . PreparingHealthCheckStartUtcTimestamp , phase : 'Preparing Health Check start' } , { timestamp : this . raw . History . PreparingHealthCheckEndUtcTimestamp , phase : 'Preparing Health check End' } , { timestamp : this . raw . History . ApprovedUtcTimestamp , phase : 'Approved' } , { timestamp : this . raw . History . ExecutingUtcTimestamp , phase : 'Executing' } , { timestamp : this . raw . History . RestoringUtcTimestamp , phase : 'Restoring' } , { timestamp : this . raw . History . RestoringHealthCheckStartUtcTimestamp , phase : 'Restoring health check start' } , { timestamp : this . raw . History . RestoringHealthCheckEndUtcTimestamp , phase : 'Restoring Health check end' } , { timestamp : this . raw . History . CompletedUtcTimestamp , phase : 'Completed' } , ] ; if ( this . raw . ResultStatus === 'Cancelled' ) { history = history . filter ( stamp => ! [ 'Approved' , 'Executing' ] . includes ( stamp . phase ) ) ; } this . history = history . map ( ( phase , index ) => { let duration = '' ; let displayInfo = NotStartedStatus ; let phaseDuration = 0 ; if ( index < ( history . length - 1 ) ) { const nextPhase = history [ index + 1 ] ; if ( nextPhase . timestamp !== RepairTask . NonStartedTimeStamp ) { phaseDuration = new Date ( nextPhase . timestamp ) . getTime ( ) - new Date ( phase . timestamp ) . getTime ( ) ; duration = TimeUtils . formatDurationAsAspNetTimespan ( phaseDuration ) ; displayInfo = FinishedStatus ; } else if ( phase . timestamp !== RepairTask . NonStartedTimeStamp ) { phaseDuration = this . getRefDate ( ) . getTime ( ) - new Date ( phase . timestamp ) . getTime ( ) ; duration = TimeUtils . formatDurationAsAspNetTimespan ( phaseDuration ) ; displayInfo = InProgressStatus ; } } if ( index === ( history . length - 1 ) ) { if ( phase . timestamp !== RepairTask . NonStartedTimeStamp ) { displayInfo = FinishedStatus ; } } return { ... phase , timestamp : phase . timestamp === RepairTask . NonStartedTimeStamp ? '' : phase . timestamp , duration , displayInfo , durationMilliseconds : phaseDuration , } ; } ) ; } private generateHistoryPhase ( name , phases ) { let duration = 0 ; let status = - 1 ; phases . forEach ( ( phase , index ) => { duration += phase . durationMilliseconds ; if ( phase . displayInfo === InProgressStatus ) { status = 0 ; } if ( ( index + 1 ) === phases . length ) { if ( phase . displayInfo === FinishedStatus ) { status = 1 ; } } } ) ; let statusText ; let statusCss ; let startCollapsed ; switch ( status ) { case 1 : statusCss = StatusCSS . Finished ; statusText = 'Done' ; startCollapsed = true ; break ; case 0 : statusCss = StatusCSS . InProgress ; statusText = 'In Progress' ; startCollapsed = false ; break ; default : statusCss = StatusCSS . NotStarted ; statusText = 'Not Started' ; startCollapsed = true ; break ; } if ( this . timeStampsCollapses [ name ] === false ) { startCollapsed = false ; } else { this . timeStampsCollapses [ name ] = startCollapsed ; } return { name , status : statusText , statusCss , duration : TimeUtils . formatDurationAsAspNetTimespan ( duration ) , durationMilliseconds : duration , phases , startCollapsed } ; } updateInternal ( ) { if ( this . raw . Impact ) { this . impactedNodes = this . raw . Impact . NodeImpactList . map ( node => node . NodeName ) ; } this . createdAt = new Date ( this . raw . History . CreatedUtcTimestamp ) . toLocaleString ( ) ; this . inProgress = this . raw . State !== 'Completed' ; const start = new Date ( this . createdAt ) . getTime ( ) ; if ( this . inProgress ) { const now = this . getRefDate ( ) . getTime ( ) ; this . duration = now - start ; } else { this . duration = new Date ( this . raw . History . CompletedUtcTimestamp ) . getTime ( ) - start ; } this . displayDuration = TimeUtils . formatDurationAsAspNetTimespan ( this . duration ) ; try { this . executorData = JSON . parse ( this . raw . ExecutorData ) ; this . couldParseExecutorData = true ; } catch ( e ) { console . log ( e ) ; this . couldParseExecutorData = false ; } this . parseHistory ( ) ; this . historyPhases = [ this . generateHistoryPhase ( 'Preparing' , this . history . slice ( 0 , 5 ) ) , ] ; if ( this . raw . ResultStatus === 'Cancelled' ) { this . historyPhases . push ( this . generateHistoryPhase ( 'Restoring' , this . history . slice ( 6 ) ) ) ; } else { this . historyPhases . push ( this . generateHistoryPhase ( 'Executing' , [ this . history [ 5 ] , this . history [ 6 ] ] ) , this . generateHistoryPhase ( 'Restoring' , this . history . slice ( 7 ) ) ) ; } return of ( null ) ; } public getPhase ( phase ) { return this . history . find ( historyPhase => historyPhase . phase === phase ) ; } public tooltipInfo ( ) { const id = this . raw . TaskId ; let tooltip = '' ; let type = '' ; if ( id . includes ( RepairJobType . TenantUpdate ) ) { type = RepairJobType . TenantUpdate ; tooltip = 'This is either initiated by the user or on behalf of the user (auto-os upgrade for example)' ; } else if ( id . includes ( RepairJobType . PlatformUpdate ) ) { tooltip = 'An operation underneath the user' ; type = RepairJobType . PlatformUpdate ; } else if ( id . includes ( RepairJobType . TenantMaintenance ) ) { tooltip = 'Intitiated by the user either via SF or portal' ; type = RepairJobType . TenantMaintenance ; } else if ( id . includes ( RepairJobType . PlatformMaintenance ) ) { tooltip = 'Intitiated by the platform to heal something' ; type = RepairJobType . PlatformMaintenance ; } return { tooltip , type } ; } public getHistoryPhase ( phase ) { return this . historyPhases . find ( historyPhase => historyPhase . name === phase ) ; } public changePhaseCollapse ( phase , state ) { this . getHistoryPhase ( phase ) . startCollapsed = state ; this . timeStampsCollapses [ phase ] = state ; } }