import type { FormikProps } from 'formik' ; import { get } from 'lodash' ; import React from 'react' ; import { ChecklistInput , FormikFormField , HelpField , NumberInput , ReactSelectInput , SpinFormik } from '@spinnaker/core' ; import type { IJobTimeWindow } from '../../../../../domain' ; import type { ITitusServerGroupCommand } from '../../../serverGroupConfiguration.service' ; export interface IWindowPickerProps { formik : FormikProps < ITitusServerGroupCommand > ; isDisabled : boolean ; } export interface IWindowPickerState { addingNewWindow ? : boolean ; } const DAYS = [ 'Monday' , 'Tuesday' , 'Wednesday' , 'Thursday' , 'Friday' , 'Saturday' , 'Sunday' ] ; interface IJobTimeWindowForm { days : string [ ] ; startHour : number ; endHour : number ; timeZone : string ; } export class WindowPicker extends React . Component < IWindowPickerProps , IWindowPickerState > { constructor ( props ) { super ( props ) ; this . state = { addingNewWindow : false , } ; } private removeWindow ( index , subIndex ) { const { values , setFieldValue } = this . props . formik ; const { timeWindows } = values . disruptionBudget ; const toRemove = timeWindows [ index ] ; if ( toRemove . hourlyTimeWindows . length === 1 ) { setFieldValue ( 'disruptionBudget.timeWindows' , timeWindows . filter ( ( w ) => w !== toRemove ) ) ; } else { const subWindowToRemove = toRemove . hourlyTimeWindows [ subIndex ] ; const newWindows = toRemove . hourlyTimeWindows . filter ( ( w ) => w !== subWindowToRemove ) ; setFieldValue ( `disruptionBudget.timeWindows[${ index }].hourlyTimeWindows` , newWindows ) ; } } /**
     * The Budget API allows multiple hourly windows for a set of days; however, the UI is not really supportive of this,
     * so we'll add them as a single window for a single set of days. It's fine!
     */ private configureNewWindow = ( ) => { this . setState ( { addingNewWindow : true } ) ; } ; private addNewWindow = ( form ) => { const { values , setFieldValue } = this . props . formik ; const { days , startHour , endHour , timeZone } = form ; const newWindow = { days , hourlyTimeWindows : [ { startHour , endHour } ] , timeZone , } ; setFieldValue ( 'disruptionBudget.timeWindows' , values . disruptionBudget . timeWindows . concat ( newWindow ) ) ; this . setState ( { addingNewWindow : false } ) ; } ; private CurrentWindows = ( ) => { const { disruptionBudget } = this . props . formik . values ; const { isDisabled } = this . props ; if ( ! disruptionBudget ) { return null ; } const { timeWindows } = disruptionBudget ; return ( < div className = "sp-formItem" > < div className = "sp-formItem__left" / > < div className = "sp-formItem__right" > { timeWindows . map ( ( timeWindow , i ) => { return timeWindow . hourlyTimeWindows . map ( ( w , i2 ) => ( < div className = "sp-margin-l-yaxis sp-margin-m-right" style = { { display : 'inline-block' } } key = { `${ i }.${ i2 }` } > < div key = { `${ i }.${ i2 }` } className = "horizontal center top sp-padding-m-yaxis sp-padding-s-xaxis" style = { { backgroundColor : 'var(--color-dovegray)' , borderRadius : '4px' } } > < div className = "sp-padding-m-right" style = { { color : 'var(--color-text-on-dark)' , fontSize : '12px' } } > < div > < b > { timeWindow . days . map ( ( d ) => d . substr ( 0 , 3 ) ) . join ( ', ' ) } < /b> < /div> < div > < em > { w . startHour } : 00 - { w . endHour } : 00 { timeWindow . timeZone } < /em> < /div> < /div> { ! isDisabled && ( < a className = "clickable" style = { { color : 'var(--color-text-on-dark)' } } onClick = { ( ) => this . removeWindow ( i , i2 ) } > < span className = "glyphicon glyphicon-remove" / > < /a>)} < /div> < /div>)); } ) } < /div> < /div>); } ; private NewWindowComponent = ( ) => { if ( ! this . state . addingNewWindow ) { return ( < div className = "sp-formItem" > < div className = "sp-formItem__left" / > < div className = "sp-formItem__right sp-margin-l-bottom" > < a className = "button primary" onClick = { this . configureNewWindow } > < i className = "fas fa-plus-circle" / > Define New Window < /a> < /div> < /div>); } return ( < SpinFormik < IJobTimeWindowForm > initialValues = { { days : [ ] , startHour : 10 , endHour : 16 , timeZone : get ( this . props . formik . values . disruptionBudget , 'timeWindows[0].timeZone' , 'PST' ) , } } onSubmit = { this . addNewWindow } render = { ( formik ) => ( < > < FormikFormField name = "days" label = "Define a New Window" input = { ( props ) => < ChecklistInput { ... props } stringOptions = { DAYS } / > } /> < FormikFormField name = "startHour" label = "Start" input = { ( props ) => ( < div > < NumberInput { ... props } min = { 0 } max = { formik . values . endHour } / > < HelpField expand = { true } content = "hour (0-24)" / > < /div>)}/ > < FormikFormField name = "endHour" label = "End" input = { ( props ) => ( < div > < NumberInput { ... props } min = { formik . values . startHour } max = { 23 } / > < HelpField expand = { true } content = "hour (0-24)" / > < /div>)}/ > < FormikFormField name = "timeZone" label = "Timezone" input = { ( props ) => < ReactSelectInput { ... props } clearable = { false } stringOptions = { [ 'PST' , 'UTC' ] } / > } /> < div className = "sp-formItem" > < div className = "sp-formItem__left" / > < div className = "sp-formItem__right sp-margin-l-bottom" > < button className = "primary" type = "submit" onClick = { ( ) => this . addNewWindow ( formik . values ) } > { ' ' } Add Window < /button> < /div> < /div> < />)}/ > ) ; } ; public render ( ) { const { CurrentWindows , NewWindowComponent } = this ; const { isDisabled } = this . props ; return ( < > < CurrentWindows /> { ! isDisabled && < NewWindowComponent />} < />); } }