<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Plato - containers/Logbook/LogbookContainer.js</title>

  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta name="description" content="">
  <meta name="author" content="">

  <!--[if lt IE 9]>
  <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
  <![endif]-->

  <link href="../../assets/css/vendor/morris.css" rel="stylesheet" type="text/css">
  <link href="../../assets/css/vendor/bootstrap.css" rel="stylesheet" type="text/css">
  <link href="../../assets/css/vendor/font-awesome.css" rel="stylesheet" type="text/css">
  <link href="../../assets/css/vendor/codemirror.css" rel="stylesheet" type="text/css">
  <link href="../../assets/css/plato.css" rel="stylesheet" type="text/css">
  <link href="../../assets/css/plato-file.css" rel="stylesheet" type="text/css">

</head>

<body>

<div class="navbar navbar-fixed-top">
  <div class="container">
    <a class="navbar-brand" href="https://github.com/the-simian/es6-plato">ES6 Plato on Github</a>
    <ul class="nav navbar-nav">
      <li>
        <a href="../../index.html">Report Home</a>
      </li>
      <li class="active">
        <a href="display.html">Summary Display</a>
      </li>
    </ul>
  </div>
</div>

<div class="jumbotron">
  <div class="container">
    <h1>containers/Logbook/LogbookContainer.js</h1>
  </div>
</div>

<div class="container aggregate-stats">
  <div class="row">
    <div class="col-md-6">
      <h2 class="header">Maintainability <a href="http://blogs.msdn.com/b/codeanalysis/archive/2007/11/20/maintainability-index-range-and-meaning.aspx"><i class="icon icon-info-sign" rel="popover" data-placement="top" data-trigger="hover" data-content="A value between 0 and 100 that represents the relative ease of maintaining the code. A high value means better maintainability." data-original-title="Maintainability Index"  data-container="body"></i></a></h2>
      <p class="stat">71.12</p>
    </div>
    <div class="col-md-6">
      <h2 class="header">Lines of code <i class="icon icon-info-sign" rel="popover" data-placement="top" data-trigger="hover" data-content="Source Lines of Code / Logical Lines of Code" data-original-title="SLOC/LSLOC" data-container="body"></i></h2>
      <p class="stat">567</p>
    </div>
  </div>
  <div class="row historical">
    <div class="col-md-6">
      <p id="chart_historical_maint" class="chart"></p>
    </div>
    <div class="col-md-6">
      <p id="chart_historical_sloc" class="chart"></p>
    </div>
  </div>
  <div class="row">
    <div class="col-md-6">
      <h2 class="header">Difficulty  <a href="http://en.wikipedia.org/wiki/Halstead_complexity_measures"><i class="icon icon-info-sign" rel="popover" data-placement="top" data-trigger="hover" data-content="The difficulty measure is related to the difficulty of the program to write or understand." data-original-title="Difficulty" data-container="body"></i></a></h2>
      <p class="stat">83.09</p>
    </div>
    <div class="col-md-6">
      <h2 class="header">Estimated Errors  <a href="http://en.wikipedia.org/wiki/Halstead_complexity_measures"><i class="icon icon-info-sign" rel="popover" data-placement="top" data-trigger="hover" data-content="Halstead's delivered bugs is an estimate for the number of errors in the implementation." data-original-title="Delivered Bugs" data-container="body"></i></a></h2>
      <p class="stat">6.65</p>
    </div>
  </div>
</div>

<div class="container charts">
  <div class="row">
    <h2 class="header">Function weight</h2>
  </div>
  <div class="row">
    <div class="col-md-6">
      <h3 class="chart-header">By Complexity <a href="http://en.wikipedia.org/wiki/Cyclomatic_complexity"><i class="icon icon-info-sign" rel="popover" data-placement="top" data-trigger="hover" data-content="This metric counts the number of distinct paths through a block of code. Lower values are better." data-original-title="Cyclomatic Complexity" data-container="body"></i></a></h3>
      <div id="fn-by-complexity" class="stat"></div>
    </div>
    <div class="col-md-6">
      <h3 class="chart-header">By SLOC  <i class="icon icon-info-sign" rel="popover" data-placement="top" data-trigger="hover" data-content="Source Lines of Code / Logical Lines of Code" data-original-title="SLOC/LSLOC" data-container="body"></i></h3>
      <div id="fn-by-sloc" class="stat"></div>
    </div>
  </div>
</div>

<div class="container">
  <div class="row">
    <textarea id="file-source" class="col-md-12">import React from &#039;react&#039;;
import { connect } from &#039;react-redux&#039;;
import PropTypes from &#039;prop-types&#039;;
import _ from &#039;lodash&#039;;

import EventList from &#039;../../components/Logbook/List/EventList&#039;;
import EventListMenu from &#039;../../components/Logbook/Menu/EventListMenu.js&#039;;
import { NEW_EVENT_INVISIBLE, NEW_EVENT_VISIBLE, LIST_VIEW, ERROR_MESSAGE_TYPE, INFO_MESSAGE_TYPE, LOGBOOK_CONTEXT_NAME_PROPOSAL, PUBLIC_EVENT_DETAILS_VISIBLE, PUBLIC_EVENT_DETAILS_INVISIBLE } from &#039;../../constants/EventTypes.js&#039;;
import { convertPageToPageEventIndexes, isRangeAvailableOnTheClient } from &#039;../../helpers/PaginationHelper.js&#039;;
import UI from &#039;../../config/ui/config&#039;;
import Loading from &#039;../../components/Loading.js&#039;;
import UserMessage from &#039;../../components/UserMessage.js&#039;;
import { getSelectionFiltersBySearchCriteria, getSelectionFiltersForMongoQuery } from &#039;./SelectionFilterHelper.js&#039;;
import { setLogbookContextAction } from &#039;../../actions/logbook.js&#039;;
import OverlayBox from &#039;../../components/Logbook/OverlayBox.js&#039;;
import NewOrEditEventPanel from &#039;../../components/Logbook/NewOrEditEventPanel.js&#039;;
import &quot;../../components/Logbook/event.css&quot;;
import PeriodicRefresher from &#039;./PeriodicRefresher.js&#039;;
import PublicEventPanel from &#039;../../components/Logbook/PublicEventPanel&#039;;
import { parseHTTPError, getSortingOrder } from &#039;../../helpers/EventHelpers&#039;;
import axios from &#039;axios&#039;;
import { getEventsByInvestigationId, getEventCountByInvestigationId, updateEvent as updateEventURL, createEvent as createEventURL } from &#039;../../api/icat/icatPlus&#039;;

/**
 * This class represents the event container component. It&#039;s role is to retrieve events from the server asynchronuously. 
 * Also, it is connected to redux and retrieves user data and sessionId.
 */
export class LogbookContainer extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            activePage: 1,
            eventCountBySelectionFilter: 0,  // count of events for the current selection filter found in the logbook since last refresh
            allEventsCountAtLastRefresh: 0, // count of all events found in the logbook since last refresh
            downloadedEvents: [], //events already downloaded
            errorMessage: &#039;&#039;,
            fetchingEventList: true,
            fetchedEventList: false,
            fetchingEventCount: true,
            fetchedEventCount: false,

            event: null, // event being edited
            isNewEventPanelVisible: false,
            isShowingEditEventUI: false,
            isShowingPublicEventUI: false,

            autorefresh: {
                isEnabled: UI.logbook.AUTOREFRESH_EVENTLIST,
                isFetchingEvents: false,
                isLockingRefresh: false // prevent EventList refresh even if isEnabled is true
            },

            pageEvents: [], // events currently displayed on the page
            sortingFilter: { [UI.logbook.SORT_EVENTS_BY]: UI.logbook.SORTING_ORDER }, // current sorting flter
            searchCriteria: [],
            view: LIST_VIEW,
        };

        this.createEvent = this.createEvent.bind(this);
        this.getAllEventsAndRefresh = this.getAllEventsAndRefresh.bind(this);
        this.getEventsBySelectionFilter = this.getEventsBySelectionFilter.bind(this);
        this.getEventCountBySelectionFilter = this.getEventCountBySelectionFilter.bind(this);
        this.isAppProperlyConfigured = this.isAppProperlyConfigured.bind(this);
        this.onCancelButtonClicked = this.onCancelButtonClicked.bind(this);
        this.onCloseButtonClicked = this.onCloseButtonClicked.bind(this);
        this.onEventCountReceptionFailure = this.onEventCountReceptionFailure.bind(this);
        this.onEventClicked = this.onEventClicked.bind(this);
        this.onNewEventCountReceived = this.onNewEventCountReceived.bind(this);
        this.onPageClicked = this.onPageClicked.bind(this);
        this.onSaveButtonClicked = this.onSaveButtonClicked.bind(this);
        this.flipEventsSortingOrder = this.flipEventsSortingOrder.bind(this);
        this.searchEvents = this.searchEvents.bind(this);
        this.setNewEventVisibility = this.setNewEventVisibility.bind(this);
        this.setView = this.setView.bind(this);
    }

    render() {
        const { investigationId, user } = this.props;

        if (this.isAppProperlyConfigured()) {
            return (
                &lt;div style={{ marginBottom: &#039;40px&#039; }}&gt;

                    &lt;OverlayBox open={this.state.errorMessage ? true : false} onClose={() =&gt; { this.setState({ errorMessage: null }) }} classNames={{ modal: &#039;userMessageModalClass&#039;, closeButton: &#039;userMessageCloseButton&#039; }}&gt;
                        {this.state.errorMessage ? &lt;UserMessage type={ERROR_MESSAGE_TYPE} message={this.state.errorMessage} /&gt; : null}
                    &lt;/OverlayBox&gt;

                    &lt;PeriodicRefresher
                        initialValue={0}
                        intervalInMilliSeconds={UI.logbook.AUTOREFRESH_DELAY}
                        isEnabled={true}
                        onCallbackSuccess={this.onNewEventCountReceived}

                        periodicCallback={(onSuccess, onFailure) =&gt; this.getEventCountBySelectionFilter(getSelectionFiltersBySearchCriteria(this.state.searchCriteria, LIST_VIEW)).then(eventCount =&gt; onSuccess(eventCount), error =&gt; onFailure(error))}
                    &gt;
                        &lt;EventListMenu
                            activePage={this.state.activePage}
                            autorefreshEventList={this.state.autorefresh.isEnabled}
                            //availableTags={this.props.availableTags}
                            eventCountBySelectionFilter={this.state.eventCountBySelectionFilter}
                            eventCountSinceLastRefresh={this.state.allEventsCountAtLastRefresh}
                            getEvents={this.getAllEventsAndRefresh}
                            investigationId={investigationId}
                            isNewButtonEnabled={!this.state.isNewEventPanelVisible}
                            isSortingLatestEventsFirst={getSortingOrder(this.state.sortingFilter) === -1 ? true : false}
                            logbookContext={this.props.logbookContext}
                            onPageClicked={this.onPageClicked}
                            onRefreshEventListMenuItemClicked={() =&gt; this.setState({ autorefresh: { ...this.state.autorefresh, isEnabled: !this.state.autorefresh.isEnabled } })}
                            onSortingButtonClicked={this.flipEventsSortingOrder}
                            searchEvents={this.searchEvents}
                            selectionFilter={getSelectionFiltersForMongoQuery(this.state.searchCriteria, this.state.sortingFilter, this.state.view)}
                            sessionId={user.sessionId}
                            setNewEventVisibility={this.setNewEventVisibility}
                            setView={this.setView}
                            view={this.state.view} /&gt;
                    &lt;/PeriodicRefresher&gt;

                    &lt;OverlayBox open={this.state.isNewEventPanelVisible === true || this.state.isShowingEditEventUI === true || this.state.isShowingPublicEventUI === true}
                        classNames={{ overlay: &#039;newOrEditOverlayClass&#039;, modal: &#039;newOrEditModalClass&#039; }}&gt;
                        {this.state.isNewEventPanelVisible === true ?
                            &lt;div style={{ height: this.getPanelHeightInPercent(), paddingBottom: this.state.isShowingEditEventUI ? &#039;5px&#039; : &#039;0px&#039; }}&gt;
                                &lt;NewOrEditEventPanel
                                    investigationId={investigationId}
                                    onCancelButtonClicked={this.onCancelButtonClicked}
                                    onSaveButtonClicked={this.onSaveButtonClicked}
                                    user={user}
                                /&gt;
                            &lt;/div&gt; : null}

                        {this.props.logbookContext.isReleased === true ?
                            &lt;div style={{ height: &#039;100%&#039;, paddingBottom: &#039;0px&#039; }}&gt;
                                &lt;PublicEventPanel
                                    event={this.state.event}
                                    onCloseButtonClicked={this.onCloseButtonClicked} /&gt;
                            &lt;/div&gt;
                            : this.state.isShowingEditEventUI === true ?
                                &lt;div style={{ height: this.getPanelHeightInPercent(), paddingBottom: this.state.isNewEventPanelVisible === true ? &#039;5px&#039; : &#039;0px&#039; }}&gt;
                                    &lt;NewOrEditEventPanel
                                        event={this.state.event}
                                        investigationId={investigationId}
                                        onCancelButtonClicked={this.onCancelButtonClicked}
                                        onSaveButtonClicked={this.onSaveButtonClicked}
                                        user={user} /&gt;
                                &lt;/div&gt; : null}
                    &lt;/OverlayBox&gt;

                    {this.state.fetchedEventList === false &amp;&amp; this.state.fetchingEventList === true ? &lt;Loading message=&#039;Loading logbook&#039;&gt;&lt;/Loading&gt; : null}

                    {this.state.fetchedEventList === true ?
                        &lt;div&gt;
                            {(this.state.pageEvents.length === 0) ?
                                &lt;UserMessage message=&#039;The logbook is empty.&#039; type={INFO_MESSAGE_TYPE} isTextCentered={true} /&gt;
                                : &lt;EventList
                                    activePage={this.state.activePage}
                                    events={this.state.pageEvents}
                                    eventCountBySelectionFilter={this.state.eventCountBySelectionFilter}
                                    logbookContext={this.props.logbookContext}
                                    onEventClicked={this.onEventClicked}
                                    onPageClicked={this.onPageClicked}
                                /&gt;
                            }
                        &lt;/div&gt; : null}
                &lt;/div &gt;
            );
        } else {
            return (&lt;div style={{ marginBottom: &#039;40px&#039; }}&gt;
                &lt;UserMessage type={ERROR_MESSAGE_TYPE} message={&#039;Sorry, the application is not properly configured for wall-eLog. Can not start. Check the console.&#039;} /&gt;
            &lt;/div&gt;
            );
        }
    }

    /**
    * Executed the first time the component is mounted
    */
    componentDidMount() {
        this.getAllEventsAndRefresh(this.state.view);

        const isCurrentProposalReleased = () =&gt; {
            let _this = this;
            return _.find(this.props.releasedInvestigations, releasedInvestigation =&gt; String(releasedInvestigation.id) === _this.props.investigationId) != undefined ? true : false;
        }

        this.props.setLogbookContext({ name: LOGBOOK_CONTEXT_NAME_PROPOSAL, isReleased: isCurrentProposalReleased() });
    }

    /** Get the height percentage value for the panels for new and edition of an event */
    getPanelHeightInPercent() {
        return (this.state.isNewEventPanelVisible === true &amp;&amp; this.state.isShowingEditEventUI === true) ? &#039;50%&#039; : &#039;100%&#039;;
    }

    /**
     * Callback function triggered when event count retreval failed
* @param {*} error
* @param {String} event counter to reset
    */
    onEventCountReceptionFailure(error, eventCounterToReset) {
        this.setState({
            errorMessage: parseHTTPError(error),
            [eventCounterToReset]: 0,
            fetchingEventCount: false,
        });
    }

    onEventClicked(event) {
        if (this.state.isShowingEditEventUI === true &amp;&amp; this.state.event != event) {
            this.setState({ errorMessage: &#039;Action refused. Please save or cancel the log which is currently being edited.&#039; });
        }

        if (this.props.logbookContext.isReleased === true) {
            this.setState({ event: event, isShowingPublicEventUI: true });
        }

        if (this.props.logbookContext.isReleased === false) {
            this.setState({ event: event, isShowingEditEventUI: true });
        }
    }

    /**
     * Function triggered periodically by the periodicRefresher
     * @param {object} eventCount event count received from the periodic refresher
     */
    onNewEventCountReceived(eventCount) {
        if (this.state.autorefresh.isEnabled === true) {
            this.setState({ autorefresh: { ...this.state.autorefresh, isFetchingEvents: true } });
            this.getEventsBySelectionFilter(this.state.downloadedEventIndexes.start, getSelectionFiltersBySearchCriteria(this.state.searchCriteria, this.state.view), this.state.sortingFilter)
                .then(events =&gt; {
                    this.setState({ autorefresh: { ...this.state.autorefresh, isFetchingEvents: false } });
                    if (this.state.autorefresh.isLockingRefresh === true) {
                        console.log(&#039;Event list not refreshed automatically because a user triggered request occured in the mean time&#039;);
                    } else {
                        this.refreshEventList(events, this.state.downloadedEventIndexes.start, getSelectionFiltersBySearchCriteria(this.state.searchCriteria, this.state.view), this.state.sortingFilter)
                    }
                    this.setState({ autorefresh: { ...this.state.autorefresh, isLockingRefresh: false } });
                });

            this.getEventCountBySelectionFilter(getSelectionFiltersBySearchCriteria(this.state.searchCriteria, this.state.view))
                .then(eventCount =&gt; this.setState({ eventCountBySelectionFilter: parseInt(eventCount, 10) }));
        }
    }

    /**
     * Refresh the event list
     * @param {*} events
     * @param {*} offset
     * @param {*} selectionFilter
     * @param {*} sortingFilter
     */
    refreshEventList(events, offset, selectionFilter, sortingFilter) {
        this.setState({
            activePage: offset === 0 ? 1 : this.state.activePage,
            downloadedEvents: events,
            downloadedEventIndexes: { start: offset, end: offset + events.length - 1 },
            fetchedEventList: true,
            pageEvents: _.slice(events, 0, UI.logbook.EVENTS_PER_PAGE),
            selectionFilter: selectionFilter,
            sortingFilter: sortingFilter,
        });
    }

    /**
     * Function triggered when the user clicks on a page
     * @param {integer} page the page the user has clicked
     */
    onPageClicked(page) {
        if (page) {
            page = page.selected + 1;

            let pageEventIndexes = convertPageToPageEventIndexes(page, UI.logbook.EVENTS_PER_PAGE, this.state.eventCountBySelectionFilter);
            let areEventsAlreadyDownloaded = isRangeAvailableOnTheClient(pageEventIndexes, this.state.downloadedEventIndexes);

            if (areEventsAlreadyDownloaded) {
                this.setState({
                    pageEvents: _.slice(this.state.downloadedEvents,
                        pageEventIndexes.start - this.state.downloadedEventIndexes.start,
                        pageEventIndexes.end - this.state.downloadedEventIndexes.start + 1)
                });
            } else {
                this.getEventsBySelectionFilter(pageEventIndexes.start, getSelectionFiltersBySearchCriteria(this.state.searchCriteria, this.state.view), this.state.sortingFilter)
                    .then(events =&gt; {
                        this.refreshEventList(events, pageEventIndexes.start, getSelectionFiltersBySearchCriteria(this.state.searchCriteria, this.state.view), this.state.sortingFilter)
                    });
            }
            this.setState({ activePage: page });
        }
    }

    /** Callback function triggered when the user starts a new search
     * @param {Array} searchCriteria the search criteria as provided by the search component
     */
    searchEvents(searchCriteria) {
        this.setState({ searchCriteria: searchCriteria });

        this.getEventsBySelectionFilter(0, getSelectionFiltersBySearchCriteria(searchCriteria, this.state.view), this.state.sortingFilter)
            .then(events =&gt; {
                if (this.state.autorefresh.isFetchingEvents) {
                    this.setState({ autorefresh: { ...this.state.autorefresh, isLockingRefresh: true } })
                }
                this.refreshEventList(events, 0, getSelectionFiltersBySearchCriteria(searchCriteria, this.state.view), this.state.sortingFilter)
            });

        this.getEventCountBySelectionFilter(getSelectionFiltersBySearchCriteria(searchCriteria, this.state.view))
            .then(eventCount =&gt; { this.setState({ eventCountBySelectionFilter: parseInt(eventCount, 10) }) });
    }


    /**
     * Function triggered when the user hits the cancel button during event creation or edition
     */
    onCancelButtonClicked() {
        if (this.state.event) { // editing an event
            this.setState({ isShowingEditEventUI: false });
        } else { // creating an event
            this.setState({ isNewEventPanelVisible: false });
        }
    }


    /**
     * Set the visibility of the new event panel
    * @param {string} visibility the requested visibility
            */
    setNewEventVisibility(visibility) {
        if (visibility) {
            if (visibility === NEW_EVENT_VISIBLE) {
                this.setState({ isNewEventPanelVisible: true });
            } else if (visibility === NEW_EVENT_INVISIBLE) {
                this.setState({ isNewEventPanelVisible: false });
            }
        };
    }

    /**
     * Function triggered when the user clicks on the close button while view a public event
     */
    onCloseButtonClicked() {
        this.setState({ isShowingPublicEventUI: false });
    }

    /**
     * Change the current view to the requested view
     * @param {string} view the requested view
     */
    setView(view) {
        if (view &amp;&amp; view !== this.state.view) {
            this.getAllEventsAndRefresh(view);
        }
        this.setState({ view: view });
    }

    /**
     * Callback function which reverses the sorting order of events
     */
    flipEventsSortingOrder() {
        let newSortingFilter = { ...this.state.sortingFilter };
        newSortingFilter[Object.keys(this.state.sortingFilter)[0]] = getSortingOrder(this.state.sortingFilter) * (-1);

        this.getEventsBySelectionFilter(0, getSelectionFiltersBySearchCriteria(this.state.searchCriteria, this.state.view), newSortingFilter)
            .then(events =&gt; {
                if (this.state.autorefresh.isFetchingEvents) {
                    this.setState({ autorefresh: { ...this.state.autorefresh, isLockingRefresh: true } })
                }
                this.refreshEventList(events, 0, getSelectionFiltersBySearchCriteria(this.state.searchCriteria, this.state.view), newSortingFilter)
            }
            );

        this.getEventCountBySelectionFilter(getSelectionFiltersBySearchCriteria(this.state.searchCriteria, this.state.view))
            .then(eventCount =&gt; { this.setState({ eventCountBySelectionFilter: parseInt(eventCount, 10) }) });
    }

    /**
     * Get events
     * @param {integer} offset the offset of events
     * @param {Object} selectionFilter selection filter in mongodb format
     * @param {object} sortingFilter the sorting filter to use , optional
     * @param {bool} useLimit if false, the limit property is not used in the request. True by default.
     */
    getEventsBySelectionFilter(offset, selectionFilter, sortingFilter, useLimit = true) {
        const { investigationId, user } = this.props;
        sortingFilter = sortingFilter || { [UI.logbook.SORT_EVENTS_BY]: UI.logbook.SORTING_ORDER }
        if (!selectionFilter) {
            // there is not selectionfilter as parameter when the user has clicked on a page
            selectionFilter = getSelectionFiltersBySearchCriteria(this.state.searchCriteria, this.state.view);
        };

        if (investigationId &amp;&amp; user.sessionId) {
            return new Promise((resolve, reject) =&gt; axios({
                method: &#039;post&#039;,
                url: getEventsByInvestigationId(user.sessionId, investigationId),
                data: {
                    find: selectionFilter,
                    sort: sortingFilter,
                    limit: useLimit === true ? UI.logbook.EVENTS_PER_DOWNLOAD : null,
                    skip: offset
                }
            })
                .then(data =&gt; { resolve(data.data); },
                    error =&gt; { console.log(&#039;[ERROR] An error occured while retrieving the event list.&#039;); }))
        } else {
            //onError(&#039;[ERROR] Missing query parameters in the request handled by getEventsByInvestigationId()&#039;);
        }
    }

    getAllEventsAndRefresh(view) {
        this.getEventsBySelectionFilter(0, getSelectionFiltersBySearchCriteria([], view), this.state.sortingFilter)
            .then(events =&gt; this.refreshEventList(events, 0, getSelectionFiltersBySearchCriteria([], view), this.state.sortingFilter));

        this.getEventCountBySelectionFilter(getSelectionFiltersBySearchCriteria([], view))
            .then(eventCount =&gt; { this.setState({ allEventsCountAtLastRefresh: parseInt(eventCount, 10), eventCountBySelectionFilter: parseInt(eventCount, 10) }) });
    }

    /**
     * Get event count by selection filter
     * @param {object} selectionFilter the selection filter used to know which events of the logbook need to be counted
     */
    getEventCountBySelectionFilter(selectionFilter) {
        const { investigationId, user } = this.props;

        this.setState({ fetchingEventCount: true });

        if (investigationId &amp;&amp; user.sessionId) {
            return new Promise((resolve, reject) =&gt; axios({
                method: &#039;post&#039;,
                url: getEventCountByInvestigationId(user.sessionId, investigationId),
                data: { find: selectionFilter }
            })
                .then(data =&gt; {
                    this.setState({ fetchedEventCount: true });
                    resolve(data.data);
                }, error =&gt; { console.log(&#039;[ERROR] An error occured while retrieving the event count.&#039;); })
            )
        } else {
            //onError(&#039;[ERROR] Missing query parameters in the request handled by getEventCountByInvestigationId()&#039;);
        }
    }

    /**
     * Update the event on ICAT+ server
     * @param {*} event event object to be updated
     */
    updateEvent(event) {
        return new Promise((resolve, reject) =&gt; axios({
            method: &#039;put&#039;,
            url: updateEventURL(this.props.user.sessionId, this.props.investigationId),
            data: { event: event },
        })
            .then(response =&gt; {
                console.log(&#039;the event was modified successfully on ICAT+ server.&#039;);
                resolve(response.data);
            })
            .catch(error =&gt; { this.setState({ errorMessage: parseHTTPError(error) }); }));
    }




    /**
     * Create the event
     * @param {*} newEvent event object to be created
     */
    createEvent(newEvent) {
        return new Promise((resolve, reject) =&gt; axios({
            method: &#039;post&#039;,
            url: createEventURL(this.props.user.sessionId, this.props.investigationId),
            data: newEvent,
        })
            .then(response =&gt; {
                console.log(&#039;The new event was created successfully on ICAT+ server.&#039;);
                resolve();
            })
            .catch(error =&gt; { this.setState({ errorMessage: parseHTTPError(error) }); })
        );
    }


    /**
     * Function triggered when the user hits the save button to create or edit an event
     * @param {*} event event to be created or updated
     */
    onSaveButtonClicked(event) {
        if (this.state.event) { //editing an event
            this.updateEvent(event)
                .then(updatedEvent =&gt; {
                    let copyPageEvents = this.state.pageEvents.map(event =&gt; event);
                    let foundIndex1 = _.findIndex(copyPageEvents, (event) =&gt; event._id === updatedEvent._id);
                    copyPageEvents.splice(foundIndex1, 1, updatedEvent);

                    let copyDownloadedEvents = this.state.downloadedEvents.map(event =&gt; event);
                    let foundIndex2 = _.findIndex(copyDownloadedEvents, (event) =&gt; event._id === updatedEvent._id);
                    copyDownloadedEvents.splice(foundIndex2, 1, updatedEvent);

                    this.setState({
                        downloadedEvents: copyDownloadedEvents,
                        pageEvents: copyPageEvents,
                        event: null,
                        isShowingEditEventUI: false
                    });
                })
        } else { // creating an event
            this.createEvent(event)
                .then(() =&gt; {
                    this.setState({ isNewEventPanelVisible: false, activePage: 1, });

                    this.getEventsBySelectionFilter(0, getSelectionFiltersBySearchCriteria(this.state.searchCriteria, this.state.view), this.state.sortingFilter)
                        .then(events =&gt; this.refreshEventList(events, 0, getSelectionFiltersBySearchCriteria(this.state.searchCriteria, this.state.sortingFilter)));
                    this.getEventCountBySelectionFilter(getSelectionFiltersBySearchCriteria(this.state.searchCriteria, this.state.view))
                        .then(eventCount =&gt; this.setState({ eventCountBySelectionFilter: parseInt(eventCount, 10) }));
                    this.getEventCountBySelectionFilter(getSelectionFiltersBySearchCriteria([], this.state.view))
                        .then(eventCount =&gt; this.setState({ allEventsCountAtLastRefresh: parseInt(eventCount, 10) }));
                })
        }
    }


    /**
     * Checks whether the app is properly configured for wall-eLog
    * @returns {boolean} true when the app is properly configured
        */
    isAppProperlyConfigured() {
        if (!UI.logbook) {
            console.log(&#039;[ERROR] [CONFIG] logbook section is missing in File src/config/ui/config&#039;);
            return false;
        }
        if (!UI.logbook.SORT_EVENTS_BY) {
            console.log(&#039;[ERROR] [CONFIG] SORT_EVENTS_BY object is missing&#039;);
            return false;
        } else if (UI.logbook.SORT_EVENTS_BY !== &#039;creationDate&#039; &amp;&amp; UI.logbook.SORT_EVENTS_BY !== &#039;_id&#039; &amp;&amp; UI.logbook.SORT_EVENTS_BY !== &#039;createdAt&#039; &amp;&amp; UI.logbook.SORT_EVENTS_BY !== &#039;updatedAt&#039;) {
            console.log(&quot;[ERROR] [CONFIG] SORT_EVENTS_BY value is not supported. Possible values are &#039;creationDate&#039;, &#039;_id&#039;, &#039;createdAt&#039; and &#039;updatedAt&#039; &quot;);
            return false;
        }
        if (!UI.logbook.SORTING_ORDER) {
            console.log(&#039;[ERROR] [CONFIG] SORTING_ORDER object is missing&#039;);
            return false;
        }
        if (!UI.logbook.EVENTS_PER_PAGE) {
            console.log(&#039;[ERROR] [CONFIG] EVENTS_PER_PAGE value is missing&#039;);
            return false;
        }
        return true;
    }
}

function mapStateToProps(state) {
    return {
        releasedInvestigations: state.releasedInvestigations.data,
        logbookContext: state.logbook.context,
        user: state.user
    };
}

/**
 * Redux related function which is used to map local function with redux dispatch()
* @param {*} dispatch redux dispatch function
                */
function mapDispatchToProps(dispatch) {
    return {
        setLogbookContext: (context) =&gt; dispatch(setLogbookContextAction(context))
    };
}

LogbookContainer.propTypes = {
    /** the investigationId */
    investigationId: PropTypes.string.isRequired
};

export default connect(mapStateToProps, mapDispatchToProps)(LogbookContainer);</textarea>
  </div>
</div>

<footer class="footer">
  <div class="container">
    <p>.</p>
  </div>
</footer>

<script type="text/html" id="complexity-popover-template">
  <div class="complexity-notice">
    Complexity : {{ complexity.cyclomatic }} <br>
    Length : {{ complexity.halstead.length }} <br>
    Difficulty : {{ complexity.halstead.difficulty.toFixed(2) }} <br>
    Est # bugs : {{ complexity.halstead.bugs.toFixed(2) }}<br>
  </div>
</script>

<script type="text/javascript" src="../../assets/scripts/bundles/core-bundle.js"></script>
<script type="text/javascript" src="../../assets/scripts/bundles/codemirror.js"></script>
<script type="text/javascript" src="../../assets/scripts/codemirror.markpopovertext.js"></script>
<script type="text/javascript" src="report.js"></script>
<script type="text/javascript" src="report.history.js"></script>
<script type="text/javascript" src="../../assets/scripts/plato-file.js"></script>
</body>
</html>
