11// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
22// SPDX-License-Identifier: MIT
3- import { CircularProgress , Container , Link , MenuItem , Paper , Select , Table , TableBody , TableCell , TableContainer , TableRow , Typography } from '@mui/material' ;
3+ import { Button , CircularProgress , Container , Link , MenuItem , Paper , Select , Table , TableBody , TableCell , TableContainer , TableRow , Typography } from '@mui/material' ;
44import moment from 'moment' ;
55import * as React from 'react' ;
66import { TRANSACTION_PER_MINUTE } from '../../common/Constant' ;
77import { usePageEffect } from '../../core/page' ;
88import { PerformanceTable } from '../../core/table' ;
9- import { UseCaseData } from './data' ;
10- import { GetLatestPerformanceReports , GetServiceLatestVersion } from './service' ;
9+ import { ServicePRInformation , UseCaseData } from './data' ;
10+ import { createDefaultServicePRInformation , GetLatestPerformanceReports , GetServiceLatestVersion , GetServicePRInformation } from './service' ;
1111import { PasswordDialog } from '../../common/Dialog' ;
12+ import { SelectChangeEvent } from '@mui/material/Select' ;
13+ import ReactMarkdown from 'react-markdown' ;
14+
1215export default function PerformanceReport ( props : { password : string ; password_is_set : boolean ; set_password_state : any } ) : JSX . Element {
1316 usePageEffect ( { title : 'Amazon CloudWatch Agent' } ) ;
1417 const { password, password_is_set, set_password_state } = props ;
15- const [ { version, commit_date, commit_title, commit_hash, commit_url, use_cases, ami_id, collection_period } ] = useStatePerformanceReport ( password ) ;
18+ const [ { version, commit_date, commit_title, commit_hash, commit_url, use_cases, ami_id, collection_period, body } ] = useStatePerformanceReport ( password ) ;
1619 const [ { data_type } , setDataTypeState ] = useStateDataType ( ) ;
20+ const [ isHidden , setIsHidden ] = React . useState ( true ) ;
21+
22+ const handleDataTypeChange = ( event : SelectChangeEvent ) => {
23+ setDataTypeState ( { data_type : event . target . value } ) ;
24+ } ;
25+
26+ const toggleContent = ( ) => {
27+ setIsHidden ( ! isHidden ) ;
28+ } ;
29+ const selectedUseCaseData : UseCaseData [ ] = use_cases . filter ( ( useCase : UseCaseData ) => useCase ?. data_type ?. toLowerCase ( ) === data_type . toLowerCase ( ) ) ;
1730
1831 return (
1932 < Container >
@@ -56,7 +69,7 @@ export default function PerformanceReport(props: { password: string; password_is
5669 aria-label = "a dense table"
5770 >
5871 < TableBody >
59- { [ 'Version' , 'Architectural' , 'Collection Period' , 'Testing AMI' , 'Commit Hash' , 'Commit Name' , 'Commit Date' , 'Data Type' ] ?. map ( ( name ) => (
72+ { [ 'Version' , 'Architectural' , 'Collection Period' , 'Testing AMI' , 'Commit Hash' , 'Commit Name' , 'Commit Date' , 'Data Type' , 'Release Notes' ] ?. map ( ( name ) => (
6073 < TableRow key = { name } >
6174 < TableCell
6275 sx = { {
@@ -69,7 +82,6 @@ export default function PerformanceReport(props: { password: string; password_is
6982 < TableCell
7083 sx = { {
7184 border : '1px solid #000' ,
72- textAlign : 'center' ,
7385 } }
7486 >
7587 { name === 'Version' ? (
@@ -88,24 +100,33 @@ export default function PerformanceReport(props: { password: string; password_is
88100 </ Link >
89101 ) : name === 'Commit Date' ? (
90102 < Typography variant = "h4" > { commit_date } </ Typography >
91- ) : (
92- < Select
93- sx = { { height : '41px' } }
94- value = { data_type }
95- onChange = { ( e : {
96- target : {
97- value : string ;
98- } ;
99- } ) =>
100- setDataTypeState ( {
101- data_type : e . target . value ,
102- } )
103- }
104- >
103+ ) : name === 'Data Type' ? (
104+ < Select sx = { { height : '41px' } } value = { data_type } onChange = { handleDataTypeChange } >
105105 < MenuItem value = { 'Metrics' } > Metric</ MenuItem >
106106 < MenuItem value = { 'Traces' } > Trace</ MenuItem >
107107 < MenuItem value = { 'Logs' } > Logs</ MenuItem >
108108 </ Select >
109+ ) : (
110+ < div >
111+ < Button
112+ onClick = { toggleContent }
113+ className = "toggle-button"
114+ variant = "outlined"
115+ sx = { {
116+ marginBottom : 0 ,
117+ backgroundColor : '#ffffff' ,
118+ borderColor : '#333333' ,
119+ color : '#333333' ,
120+ '&:hover' : {
121+ backgroundColor : '#f5f5f5' ,
122+ borderColor : '#333333' ,
123+ } ,
124+ } }
125+ >
126+ { isHidden ? 'Show release notes' : 'Hide release notes' }
127+ </ Button >
128+ { ! isHidden && < ReactMarkdown className = "markdown-content" > { body } </ ReactMarkdown > }
129+ </ div >
109130 ) }
110131 </ TableCell >
111132 </ TableRow >
@@ -120,7 +141,7 @@ export default function PerformanceReport(props: { password: string; password_is
120141 < Typography sx = { { mb : 2 , fontWeight : 'bold' } } variant = "h3" >
121142 { data_type } (TPM: { tpm } ){ ' ' }
122143 </ Typography >
123- < PerformanceTable data_rate = { String ( tpm ) } use_cases = { use_cases . filter ( ( use_case : UseCaseData ) => use_case ?. data_type === data_type . toLowerCase ( ) ) } />
144+ < PerformanceTable key = { data_type } data_rate = { String ( tpm ) } use_cases = { selectedUseCaseData } />
124145 </ Container >
125146 ) ) }
126147 </ Container >
@@ -140,6 +161,7 @@ function useStatePerformanceReport(password: string) {
140161 ami_id : undefined as string | undefined ,
141162 collection_period : undefined as string | undefined ,
142163 error : undefined as string | undefined ,
164+ body : undefined as string | undefined ,
143165 } ) ;
144166
145167 React . useEffect ( ( ) => {
@@ -155,8 +177,9 @@ function useStatePerformanceReport(password: string) {
155177
156178 const use_cases : UseCaseData [ ] = [ ] ;
157179 // We only get the latest commit ID; therefore, only use case are different; however, general metadata
158- // information (e.g Commit_Hash, Commit_Date of the PR) would be the same for all datas .
180+ // information (e.g Commit_Hash, Commit_Date of the PR) would be the same for all data .
159181 const commit_hash = performance_reports . at ( 0 ) ?. CommitHash . S || '' ;
182+ const commitHashes = performance_reports . map ( ( report ) => report . CommitHash ?. S ) ;
160183 const commit_date = performance_reports . at ( 0 ) ?. CommitDate . N ;
161184 const collection_period = performance_reports . at ( 0 ) ?. CollectionPeriod . S ;
162185 const ami_id = performance_reports . at ( 0 ) ?. InstanceAMI . S ;
@@ -166,11 +189,10 @@ function useStatePerformanceReport(password: string) {
166189 name : pReport ?. UseCase . S ,
167190 data_type : pReport ?. DataType . S ,
168191 instance_type : pReport ?. InstanceType . S ,
169- data : TRANSACTION_PER_MINUTE . reduce (
192+ data : Object . keys ( pReport ?. Results . M ) . reduce (
170193 ( accu , tpm ) => ( {
171194 ...accu ,
172195 [ tpm ] : {
173- cpu_usage : pReport ?. Results . M [ tpm ] ?. M ?. cpu_usage ?. M ?. Average ?. N ,
174196 procstat_cpu_usage : pReport ?. Results . M [ tpm ] ?. M ?. procstat_cpu_usage ?. M ?. Average ?. N ,
175197 procstat_memory_rss : pReport ?. Results . M [ tpm ] ?. M ?. procstat_memory_rss ?. M ?. Average ?. N ,
176198 procstat_memory_swap : pReport ?. Results . M [ tpm ] ?. M ?. procstat_memory_swap ?. M ?. Average ?. N ,
@@ -187,26 +209,44 @@ function useStatePerformanceReport(password: string) {
187209 ) ,
188210 } ) ;
189211 }
190- // const commit_info = await GetServicePRInformation(password, commit_hash);
212+ const commit_info : ServicePRInformation [ ] = await GetServicePRInformation ( password , commitHashes ) ;
213+ const commit_info_finalized = commit_info . find ( ( value ) => value !== undefined ) ?? createDefaultServicePRInformation ( ) ;
191214
192215 setState ( ( prev : any ) => ( {
193216 ...prev ,
194217 version : service_info . tag_name ,
195218 ami_id : ami_id ,
196219 collection_period : collection_period ,
197220 use_cases : use_cases ,
198- // commit_title: `${commit_info?.title} (#${commit_info?.number})`,
199- // commit_url: commit_info?.html_url,
200- commit_hash : commit_hash ,
201- commit_title : `PlaceHolder` ,
202- commit_url : `www.github.com/aws/amazon-cloudwatch-agent` ,
203- commit_date : moment . unix ( Number ( commit_date ) ) . format ( 'dddd, MMMM Do, YYYY h:mm:ss A' ) ,
221+ commit_title : `${ commit_info_finalized ?. title } (#${ commit_info_finalized ?. number } )` ,
222+ commit_url : commit_info_finalized ?. html_url ,
223+ commit_hash : commit_info_finalized ?. sha ?? commit_hash ,
224+ commit_date : formatUnixTimestamp ( commit_date ?? 0 ) ,
225+ body : service_info . body ?? 'Release notes unavailable' ,
204226 } ) ) ;
205227 } ) ( ) ;
206228 } , [ password , setState ] ) ;
207229 return [ state , setState ] as const ;
208230}
209231
232+ export const formatUnixTimestamp = ( timestamp : string | number , format : string = 'dddd, MMMM Do, YYYY h:mm:ss A' ) : string => {
233+ try {
234+ // Handle string input
235+ const unixTime = typeof timestamp === 'string' ? Number ( timestamp ) : timestamp ;
236+
237+ // Validate timestamp
238+ if ( ! Number . isFinite ( unixTime ) || unixTime < 0 ) {
239+ console . log ( 'invalid unix timestamp:' ) ;
240+ return moment . unix ( 0 ) . format ( format ) ;
241+ }
242+
243+ return moment . unix ( unixTime ) . format ( format ) ;
244+ } catch ( error ) {
245+ console . error ( 'Error formatting unix timestamp:' , error ) ;
246+ return moment . unix ( 0 ) . format ( format ) ;
247+ }
248+ } ;
249+
210250function useStateDataType ( ) {
211251 const [ state , setState ] = React . useState ( {
212252 data_type : 'Metrics' as 'Metrics' | 'Traces' | 'Logs' | string ,
0 commit comments