Commit 0d21750f authored by Maxime Chaillet's avatar Maxime Chaillet

work in progress

parent 1ae98a91
......@@ -73,7 +73,7 @@ class EventContentPanel extends React.Component {
* @param {string} content content data to store
* @param {string} contentFormat data format
*/
storeToLocalStorage = (context, content, contentFormat) => {
storeToLocalStorage(context, content, contentFormat) {
if (context && contentFormat) {
if (context === NEW_EVENT_CONTEXT) {
if (contentFormat === PLAINTEXT_CONTENT_FORMAT) {
......
......@@ -73,7 +73,7 @@ class HTMLEditor extends Component {
this.setEditingAreaHeight();
}
setEditingAreaHeight = () => {
setEditingAreaHeight() {
let panelPart = document.getElementById('refForEditorHeightCalculation');
let editorHeader = document.getElementsByClassName("mce-top-part mce-container mce-stack-layout-item mce-first")[0];
let iframe = this.props.text ? document.getElementById(EDITOR_ID_FOR_EDITION + '_ifr') : document.getElementById(EDITOR_ID_FOR_CREATION + '_ifr');
......
......@@ -55,7 +55,7 @@ class LabeledElement extends React.Component {
if (this.props.type === 'input') { this.props.onEventModified(); };
}
onChangeInputValue = (e) => {
onChangeInputValue(e) {
this.setState({ inputValue: e.target.value });
}
};
......
......@@ -82,7 +82,7 @@ class EventListMenu extends React.Component {
<EventListMenuButton text='PDF' glyph='download' tooltipText='Download as PDF' isEnabled={!(isNewEventVisible === undefined || isNewEventVisible === true || numberOfMatchingEventsFound === 0)} />
</NavItem>
<NavItem>
<NewlyAvailableEventsDialogue latestEvents={this.props.periodicData} eventCountSinceLastRefresh={this.props.eventCountSinceLastRefresh} />
<NewlyAvailableEventsDialogue latestEvents={this.props.periodicData} eventCountSinceLastRefresh={this.props.eventCountSinceLastRefresh} onIconClicked={this.props.getEvents} />
</NavItem>
</Nav>
......@@ -114,7 +114,7 @@ class EventListMenu extends React.Component {
);
}
getSelectPickerData = () => {
getSelectPickerData() {
let selectPickerData = { category: ['Info', 'Error', 'Command', 'Comment', 'Debug'] };
if (this.props.availableTags) {
......@@ -126,7 +126,7 @@ class EventListMenu extends React.Component {
/**
* Callback triggered when the user clicks the button to expand the navbar in mobile layout
*/
onToggleNavbar = () => {
onToggleNavbar() {
this.setState({ isNavbarExpanded: !this.state.isNavbarExpanded });
}
......@@ -134,17 +134,17 @@ class EventListMenu extends React.Component {
* Callback triggered when the user clicks an element of the navbar.
* @param {*} eventKey key of the element
*/
onSelectNavbar = (eventKey) => {
onSelectNavbar(eventKey) {
if (eventKey != 6) {
this.onToggleNavbar();
}
}
onSearch = (data) => {
onSearch(data) {
return this.props.searchEvents(data);
}
sortByDate = (sortingOrder) => {
sortByDate(sortingOrder) {
if (sortingOrder && this.props.sortingFilter.createdAt !== sortingOrder) {
//this.setState({ sortingOrder: sortingOrder })
this.props.reverseEventsSortingByCreationDate();
......
......@@ -5,12 +5,13 @@ import { Glyphicon } from 'react-bootstrap';
class NewlyAvailableEventsDialogue extends React.Component {
render() {
let { eventCountSinceLastRefresh, onIconClicked, latestEvents } = this.props;
let newEventCountSinceLastRefresh = 0;
if (this.props.latestEvents && this.props.latestEvents.data && this.props.eventCountSinceLastRefresh) {
newEventCountSinceLastRefresh = this.props.latestEvents.data.length - this.props.eventCountSinceLastRefresh
if (latestEvents && latestEvents.data && eventCountSinceLastRefresh) {
newEventCountSinceLastRefresh = (latestEvents.data.length < eventCountSinceLastRefresh) ? 0 : latestEvents.data.length - eventCountSinceLastRefresh
}
return (<span style={{ color: '#888888' }}> {newEventCountSinceLastRefresh
} new logs arrived. <Glyphicon glyph='refresh' /> </span>)
} new logs arrived. <Glyphicon onClick={onIconClicked} glyph='refresh' /> </span>)
}
}
......@@ -19,6 +20,8 @@ export default NewlyAvailableEventsDialogue;
NewlyAvailableEventsDialogue.proptype = {
/* Total number of event in the logbook known by the client since the last refresh of the event list */
eventCountSinceLastRefresh: PropTypes.number,
/* Latests events of the logbook. Array is in latestEvents.data */
/* Callback function triggered which the user clicks the icon*/
onIconClicked: PropTypes.func,
/* Latest events of the logbook. Array is in latestEvents.data */
latestEvents: PropTypes.object
}
\ No newline at end of file
......@@ -104,7 +104,7 @@ class NewOrEditEventPanel extends React.Component {
* -1- hasText boolean which indicates whether the editor content has text or not; not null
* -2- currentTextEqualsOriginal, boolean, which indicates whether the current content is the same as the original content; not null
*/
onEventModified = (change) => {
onEventModified(change) {
let hasEventTitleChangedFromItsOriginalValue = this.inputTitle && this.props.event && this.inputTitle.props.value !== this.props.event.title;
let hasEventTagsChangedFromItsOriginalValue = this.tagContainer && this.props.event &&
......@@ -153,7 +153,7 @@ class NewOrEditEventPanel extends React.Component {
/**
* Callback function triggered when the user clicks on the cancel button
*/
onCancelButtonClicked = () => {
onCancelButtonClicked() {
if (this.props.context) {
if (this.props.context === NEW_EVENT_CONTEXT) {
localStorage.removeItem('plainText');
......@@ -169,7 +169,7 @@ class NewOrEditEventPanel extends React.Component {
/**
* Callback function triggered when the user click the save button while an event is being created or updated.
*/
onSaveButtonClicked = () => {
onSaveButtonClicked() {
if (this.props.context) {
if (this.props.context === NEW_EVENT_CONTEXT) {
this.createEvent();
......@@ -182,14 +182,14 @@ class NewOrEditEventPanel extends React.Component {
/**
* Callback triggered when the event has been successfully created on the server side
*/
onSuccessfullyCreated = () => {
onSuccessfullyCreated() {
this.props.onNewEventUploaded();
}
/**
* Callback triggered when the event has been successfully updated on the server side
*/
onSuccessfullyUpdated = (updatedEvent) => {
onSuccessfullyUpdated(updatedEvent) {
this.props.onEventUpdated(updatedEvent);
}
......@@ -197,19 +197,19 @@ class NewOrEditEventPanel extends React.Component {
/**
* Callback function used to set the tagcontainer instance to a class instance variable in order to access data stored within the tag container
*/
setTagContainer = (element) => {
setTagContainer(element) {
this.tagContainer = element;
}
/** Callback function used to set the titleInput instance to a class instance variable inorder to access data stored within the title input */
setTitleInput = (element) => {
setTitleInput(element) {
this.inputTitle = element;
}
/**
* Creates an event. It's a request to the server which may fail.
*/
createEvent = () => {
createEvent() {
let currentTagIds = this.tagContainer.state.selectedTags.map((tag) => tag._id);
let newEvent = {
......@@ -232,7 +232,7 @@ class NewOrEditEventPanel extends React.Component {
/**
* Updates an event. It's a request to the server which may fail.
*/
updateEvent = () => {
updateEvent() {
let { investigationId, event, user } = this.props;
// get tags
......
......@@ -31,7 +31,7 @@ class OverlayBox extends React.Component {
}
/** Callback triggered when the overlay box is opened. */
onEntered = () => {
onEntered() {
/** this is a trick to circumvent a bug with tinymce in modals. the modal needs to be displayed first and tinymce shown afterwards otherwise a bug occurs in tinymce. */
let timer = setTimeout(() => { this.setState({ isChildComponentVisible: true }) }, 100);
}
......@@ -39,7 +39,7 @@ class OverlayBox extends React.Component {
/**
* Callback triggered when the modal is close. This happends when props.open becomes false
*/
onExited = () => {
onExited() {
this.setState({ isChildComponentVisible: false })
}
}
......
......@@ -45,7 +45,6 @@ class LogbookContainer extends React.Component {
view: LIST_VIEW,
};
this.downloadEvents = this.downloadEvents.bind(this);
this.isAppProperlyConfigured = this.isAppProperlyConfigured.bind(this);
this.onEventsReceptionFailure = this.onEventsReceptionFailure.bind(this);
this.onEventUpdated = this.onEventUpdated.bind(this);
......@@ -71,6 +70,7 @@ class LogbookContainer extends React.Component {
}
if (this.isAppProperlyConfigured()) {
debugger;
return (
<div style={{ marginBottom: '40px' }}>
<OverlayBox open={this.state.errorMessage} onClose={() => { this.setState({ errorMessage: null }) }} classNames={{ modal: 'userMessageModalClass', closeButton: 'userMessageCloseButton' }}>
......@@ -79,12 +79,13 @@ class LogbookContainer extends React.Component {
<PeriodicRefresher
initialValue={this.state.pageEvents.length}
intervalInMilliSeconds={2000}
intervalInMilliSeconds={20000}
isEnabled={true}
periodicCallback={(onSuccess, onFailure) => getEventsByInvestigationIdRequest(user.sessionId, investigationId, GUI_CONFIG().EVENTS_PER_DOWNLOAD, 0, selectionFilter.find, GUI_CONFIG().DEFAULT_SORTING_FILTER, onSuccess, onFailure)}>
<EventListMenu
eventCountSinceLastRefresh={this.state.eventCountSinceLastRefresh}
availableTags={this.props.availableTags}
eventCountSinceLastRefresh={this.state.eventCountSinceLastRefresh}
getEvents={this.getEvents}
investigationId={investigationId}
isNewEventVisible={this.state.isNewEventVisible}
numberOfMatchingEventsFound={this.state.eventCountSinceLastRefreshForCurrentSelectionFilter}
......@@ -159,8 +160,19 @@ class LogbookContainer extends React.Component {
}
}
/**
* Executed the first time the component is mounted
*/
componentWillMount() {
this.getEvents(0, getSelectionFiltersBySearchCriteria(this.state.userSearchCriteria, this.state.view), true);
}
componentWillUnmount() {
this.props.clearAvailableTags();
}
/** Get the height percentage value for the panels for new and edition of an event */
getPanelHeightInPercent = (context) => {
getPanelHeightInPercent(context) {
if (context) {
if (context === NEW_EVENT_CONTEXT) {
return this.state.isNewEventVisible === false ? '0%' : this.state.eventBeingEdited === null ? '100%' : '50%';
......@@ -172,29 +184,20 @@ class LogbookContainer extends React.Component {
return '100%';
}
onEventClicked = (event) => {
onEventClicked(event) {
if (this.state.eventBeingEdited && this.state.eventBeingEdited != event) {
this.setState({ errorMessage: 'Action refused. Please save or cancel the log which is currently being edited.' });
}
this.setState({ eventBeingEdited: event });
}
/**
* Executed the first time the component is mounted
*/
componentWillMount() {
this.downloadEvents(0, getSelectionFiltersBySearchCriteria(this.state.userSearchCriteria, this.state.view), true);
}
componentWillUnmount() {
this.props.clearAvailableTags();
}
/** 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.downloadEvents(0, getSelectionFiltersBySearchCriteria(searchCriteria, this.state.view), true);
this.getEvents(0, getSelectionFiltersBySearchCriteria(searchCriteria, this.state.view), true);
this.setState({ userSearchCriteria: searchCriteria });
}
......@@ -205,7 +208,7 @@ class LogbookContainer extends React.Component {
* @param {Object} selectionFilter optional; selection filter in mongodb format
* @param {bool} isEventCountRequestNeeded whether the event count request is needed or not
*/
downloadEvents(offset, selectionFilter, isEventCountRequestNeeded, sortingFilter) {
getEvents(offset, selectionFilter, isEventCountRequestNeeded, sortingFilter) {
const { investigationId, user } = this.props;
sortingFilter = sortingFilter || GUI_CONFIG().DEFAULT_SORTING_FILTER;
......@@ -216,6 +219,7 @@ class LogbookContainer extends React.Component {
//Get all events
const onSuccess = (data) => {
console.log(JSON.stringify(data.data))
this.setState({
downloadedEvents: data.data,
downloadedEventIndexes: {
......@@ -271,7 +275,7 @@ class LogbookContainer extends React.Component {
*/
setView(view) {
if (view && view !== this.state.view) {
this.downloadEvents(0, getSelectionFiltersBySearchCriteria(this.state.userSearchCriteria, view), true);
this.getEvents(0, getSelectionFiltersBySearchCriteria(this.state.userSearchCriteria, view), true);
}
this.setState({ view: view });
}
......@@ -295,7 +299,7 @@ class LogbookContainer extends React.Component {
* Set the visibility of the edit event panel
* @param {string} newVisibility the requested visibility
*/
setEditEventVisibility = (newVisibility) => {
setEditEventVisibility(newVisibility) {
if (newVisibility) {
if (newVisibility === EDIT_EVENT_VISIBLE) {
//this.setState({ isNewEventVisible: true });
......@@ -314,7 +318,7 @@ class LogbookContainer extends React.Component {
activePage: 1,
});
this.downloadEvents(0, getSelectionFiltersBySearchCriteria(this.state.userSearchCriteria, this.state.view), true);
this.getEvents(0, getSelectionFiltersBySearchCriteria(this.state.userSearchCriteria, this.state.view), true);
}
/**
......@@ -333,7 +337,7 @@ class LogbookContainer extends React.Component {
pageEventIndexes.end - this.state.downloadedEventIndexes.start + 1)
});
} else {
this.downloadEvents(pageEventIndexes.start, false, false, this.state.sortingFilter);
this.getEvents(pageEventIndexes.start, false, false, this.state.sortingFilter);
}
this.setState({
......@@ -362,7 +366,7 @@ class LogbookContainer extends React.Component {
let rankInFutureList = this.state.eventCountSinceLastRefreshForCurrentSelectionFilter - indexOfEventOnAllEventsFound;
let newPage = Math.ceil(rankInFutureList / GUI_CONFIG().EVENTS_PER_PAGE);
let offset = (newPage - 1) * GUI_CONFIG().EVENTS_PER_PAGE;
this.downloadEvents(offset, selectionFilter, false, newSortingFilter);
this.getEvents(offset, selectionFilter, false, newSortingFilter);
this.setState({
activePage: newPage,
selectedEventId: selectedEventId
......@@ -370,7 +374,7 @@ class LogbookContainer extends React.Component {
return;
}
}
this.downloadEvents(0, selectionFilter, false, newSortingFilter);
this.getEvents(0, selectionFilter, false, newSortingFilter);
this.setState({ activePage: 1, selectedEventId: 0 });
}
......
......@@ -5,19 +5,18 @@ class PeriodicRefresher extends React.Component {
this.state = {
data: this.props.data
}
this.timer = setInterval(() => { return this.props.periodicCallback(this.onSuccess, this.onFailure) }, this.props.intervalInMilliSeconds);
}
render() {
let timer = setTimeout(() => { return this.props.periodicCallback(this.onSuccess, this.onFailure) }, this.props.intervalInMilliSeconds);
return React.cloneElement(this.props.children, { periodicData: this.state.data, initialValue: this.props.initialValue });
}
onSuccess = (data) => {
onSuccess(data) {
this.setState({ data: data })
}
onFailure = () => {
onFailure() {
}
}
......
import React from 'react';
import Enzyme from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import { createStore, applyMiddleware } from 'redux'
import { persistReducer } from 'redux-persist'
import storage from 'redux-persist/lib/storage'
import logger from 'redux-logger'
import thunk from 'redux-thunk'
import reducer from '../../src/reducers'
import promise from "redux-promise-middleware"
import { LOGGED_IN } from '../../src/constants/ActionTypes';
import { GUI_CONFIG } from '../../src/config/gui.config';
//import NewlyAvailableEventsDialogue from '../../src/components/Logbook/Menu/NewlyAvailableEventsDialogue';
//import { getEventsByInvestigationId } from '../../src/containers/Logbook/IORequests';
const IORequestModule = require('../../src/containers/Logbook/IORequests')
import LogbookContainer from '../../src/containers/Logbook/LogbookContainer';
//jest.mock("../../src/containers/Logbook/LogbookContainer");
//const resources = require('../resources/newlyAvailableEventsDialogue.resource.js')
jest.mock("../../src/config/gui.config");
require('it-each')({ testPerIteration: true });
beforeEach(() => {
Enzyme.configure({ adapter: new Adapter() })
})
describe("NewlyAvailableEventsDialogue integration tests", () => {
function getWrapper() {
/* overrides default configuration */
GUI_CONFIG.mockReturnValue({
EVENTS_PER_PAGE: 2,
DEFAULT_SORTING_FILTER: {
createdAt: -1 // temporary workaround. createdAt must be replaced by creationDate
}
})
const middleware = [thunk];
const persistConfig = { key: 'root', storage }
const persistedReducer = persistReducer(persistConfig, reducer)
const store = createStore(
persistedReducer,
{ user: { type: LOGGED_IN, username: 'username', sessionId: 'testSessionId' } },
applyMiddleware(...middleware, logger, promise(), thunk)
)
return Enzyme.mount(<LogbookContainer
investigationId="testInvestigationId"
store={store}
/>)
};
it('refreshes the event list when the user clicks the refresh icon on the NewlyAvailableEventsDialogue', () => {
IORequestModule.getEventsByInvestigationId = jest.fn( async (sessionId, investigationId, limit, offset, selectionFilter, sortingFilter, onSuccess, onError) => {
await onSuccess({
data: [{
_id: 'testId1',
category: "comment",
content: [
{ format: 'plainText', text: 'this is a test' },
{ format: 'html', text: '<p> this is a test </p>' }
],
createdAt: '2018-01-01T00:01:00.000Z',
creationDate: '2018-01-01T00:00:00.000Z',
datasetId: null,
file: [],
fileSize: null,
filename: null,
investigationId: 'testInvestigationId',
machine: null,
previousVersionEvent: null,
software: null,
tag: [],
title: 'test title',
type: "annotation",
updatedAt: "2018-01-01T00:00:00.000Z",
username: "mchaille"
}]
})
});
IORequestModule.getEventCountByInvestigationId = jest.fn(async (investigationId, sessionId, selectionFilter, onSuccess, onEventsReceptionFailure) => {
await onSuccess({ data: '1' })
});
async function test() {
const wrapper = await getWrapper();
await wrapper.update();
await console.log(wrapper.debug());
await console.log(IORequestModule.getEventsByInvestigationId.mock.calls);
await console.log(IORequestModule.getEventsByInvestigationId.mock.results);
await console.log(wrapper.find('LogbookContainer').instance())
}
test()
// describe('testing callbacks', () => {
// it('onIConClicked', () => {
// const wrapper = getShallowedWrapper(0, null);
// expect(wrapper.instance().props.onIconClicked).toHaveBeenCalledTimes(0);
// wrapper.find('Glyphicon').simulate('click');
// expect(wrapper.instance().props.onIconClicked).toHaveBeenCalledTimes(1);
// })
// })
})
});
\ No newline at end of file
module.exports = {
rendering: [
{
aboutThisTest: "test 1",
latestEvents: null,
eventCountSinceLastRefresh: null,
expected: 0
},
{
aboutThisTest: "test 2",
latestEvents: { data: null },
eventCountSinceLastRefresh: null,
expected: 0
},
{
aboutThisTest: "test 3",
latestEvents: { data: [getEvent('id1'), getEvent('id2')] },
eventCountSinceLastRefresh: null,
expected: 0
},
{
aboutThisTest: "test 4",
latestEvents: { data: [getEvent('id1'), getEvent('id2'), getEvent('id3')] },
eventCountSinceLastRefresh: 1,
expected: 2
},
{
aboutThisTest: "test 5",
latestEvents: { data: [getEvent('id1'), getEvent('id2'), getEvent('id3')] },
eventCountSinceLastRefresh: 4,
expected: 0
},
]
};
/* return an event object which ID is eventId*/
function getEvent(eventId) {
return {
_id: eventId,
category: "comment",
content: [
{ format: 'plainText', text: 'this is a test' },
{ format: 'html', text: '<p> this is a test </p>' }
],
createdAt: '2018-01-01T00:01:00.000Z',
creationDate: '2018-01-01T00:00:00.000Z',
datasetId: null,
file: [],
fileSize: null,
filename: null,
investigationId: 'testInvestigationId',
machine: null,
previousVersionEvent: null,
software: null,
tag: [],
title: 'test title',
type: "annotation",
updatedAt: "2018-01-01T00:00:00.000Z",
username: "mchaille"
}
}
\ No newline at end of file
import React from 'react';
import Enzyme from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import NewlyAvailableEventsDialogue from '../../src/components/Logbook/Menu/NewlyAvailableEventsDialogue';
const resources = require('../resources/newlyAvailableEventsDialogue.resource.js')
require('it-each')({ testPerIteration: true });
beforeEach(() => {
Enzyme.configure({ adapter: new Adapter() })
})
describe("NewlyAvailableEventsDialogue unit tests", () => {
function getShallowedWrapper(eventCountSinceLastRefresh, latestEvents) {
return Enzyme.shallow(<NewlyAvailableEventsDialogue
eventCountSinceLastRefresh={eventCountSinceLastRefresh}
latestEvents={latestEvents}
onIconClicked={jest.fn() }
/>)
};
describe("rendering", () => {
it.each(resources.rendering, '[note: %s ]', ['aboutThisTest'],
function (element, next) {
expect(getShallowedWrapper(element.eventCountSinceLastRefresh, element.latestEvents).find('span').props().children[1]).toEqual(element.expected);
next();
})
})
describe('testing callbacks', () => {
it('onIConClicked', () => {
const wrapper = getShallowedWrapper(0, null);
expect(wrapper.instance().props.onIconClicked).toHaveBeenCalledTimes(0);
wrapper.find('Glyphicon').simulate('click');
expect(wrapper.instance().props.onIconClicked).toHaveBeenCalledTimes(1);
})
})
})
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment