@@ -24,6 +24,7 @@ import Header from './Header';
2424import Body from './Body' ;
2525import { MENU } from '../common' ;
2626import type { Content } from '../types/content' ;
27+ import { inserter as logInserter } from './Logs' ;
2728
2829// deepUpdate updates an object corresponding to the given update data, which has
2930// the shape of the same structure as the original object. updater also has the same
@@ -75,8 +76,11 @@ const appender = <T>(limit: number, mapper = replacer) => (update: Array<T>, pre
7576 ...update . map ( sample => mapper ( sample ) ) ,
7677] . slice ( - limit ) ;
7778
78- // defaultContent is the initial value of the state content.
79- const defaultContent : Content = {
79+ // defaultContent returns the initial value of the state content. Needs to be a function in order to
80+ // instantiate the object again, because it is used by the state, and isn't automatically cleaned
81+ // when a new connection is established. The state is mutated during the update in order to avoid
82+ // the execution of unnecessary operations (e.g. copy of the log array).
83+ const defaultContent : ( ) => Content = ( ) => ( {
8084 general : {
8185 version : null ,
8286 commit : null ,
@@ -95,10 +99,14 @@ const defaultContent: Content = {
9599 diskRead : [ ] ,
96100 diskWrite : [ ] ,
97101 } ,
98- logs : {
99- log : [ ] ,
102+ logs : {
103+ chunks : [ ] ,
104+ endTop : false ,
105+ endBottom : true ,
106+ topChanged : 0 ,
107+ bottomChanged : 0 ,
100108 } ,
101- } ;
109+ } ) ;
102110
103111// updaters contains the state updater functions for each path of the state.
104112//
@@ -122,9 +130,7 @@ const updaters = {
122130 diskRead : appender ( 200 ) ,
123131 diskWrite : appender ( 200 ) ,
124132 } ,
125- logs : {
126- log : appender ( 200 ) ,
127- } ,
133+ logs : logInserter ( 5 ) ,
128134} ;
129135
130136// styles contains the constant styles of the component.
@@ -151,10 +157,11 @@ export type Props = {
151157} ;
152158
153159type State = {
154- active : string , // active menu
155- sideBar : boolean , // true if the sidebar is opened
156- content : Content , // the visualized data
157- shouldUpdate : Object , // labels for the components, which need to re-render based on the incoming message
160+ active : string , // active menu
161+ sideBar : boolean , // true if the sidebar is opened
162+ content : Content , // the visualized data
163+ shouldUpdate : Object , // labels for the components, which need to re-render based on the incoming message
164+ server : ?WebSocket ,
158165} ;
159166
160167// Dashboard is the main component, which renders the whole page, makes connection with the server and
@@ -165,8 +172,9 @@ class Dashboard extends Component<Props, State> {
165172 this . state = {
166173 active : MENU . get ( 'home' ) . id ,
167174 sideBar : true ,
168- content : defaultContent ,
175+ content : defaultContent ( ) ,
169176 shouldUpdate : { } ,
177+ server : null ,
170178 } ;
171179 }
172180
@@ -181,7 +189,7 @@ class Dashboard extends Component<Props, State> {
181189 // PROD is defined by webpack.
182190 const server = new WebSocket ( `${ ( ( window . location . protocol === 'https:' ) ? 'wss://' : 'ws://' ) } ${ PROD ? window . location . host : 'localhost:8080' } /api` ) ;
183191 server . onopen = ( ) => {
184- this . setState ( { content : defaultContent , shouldUpdate : { } } ) ;
192+ this . setState ( { content : defaultContent ( ) , shouldUpdate : { } , server } ) ;
185193 } ;
186194 server . onmessage = ( event ) => {
187195 const msg : $Shape < Content > = JSON.parse(event.data);
@@ -192,10 +200,18 @@ class Dashboard extends Component<Props, State> {
192200 this.update(msg);
193201 } ;
194202 server . onclose = ( ) => {
203+ this . setState ( { server : null } ) ;
195204 setTimeout ( this . reconnect , 3000 ) ;
196205 } ;
197206 } ;
198207
208+ // send sends a message to the server, which can be accessed only through this function for safety reasons.
209+ send = ( msg : string ) = > {
210+ if ( this . state . server != null ) {
211+ this . state . server . send ( msg ) ;
212+ }
213+ } ;
214+
199215 // update updates the content corresponding to the incoming message.
200216 update = ( msg : $Shape < Content > ) => {
201217 this. setState ( prevState => ( {
@@ -226,6 +242,7 @@ class Dashboard extends Component<Props, State> {
226242 active = { this . state . active }
227243 content = { this . state . content }
228244 shouldUpdate = { this . state . shouldUpdate }
245+ send = { this . send }
229246 />
230247 </ div >
231248 ) ;
0 commit comments