Commit 472204a2 authored by Maxime Chaillet's avatar Maxime Chaillet

Merge branch 'master' of https://gitlab.esrf.fr/icat/E-DataPortal into issue149

parents a0ba1195 86b376a3
......@@ -29,8 +29,8 @@ class NewOrEditEventPanel extends React.Component {
return (
<Panel bsStyle='primary' style={{ marginBottom: '0px', height: '100%', position: 'relative' }}>
<EventHeader context={context} />
<div id='refForEditorHeightCalculation' style={{ position: 'absolute', top: '41px', bottom: '60px', width: '100%' }} >
<div style={{ padding: '1px', position: 'absolute', top: '0px', bottom: '34px', left: '0px', right: '2px' }}>
<div id='refForEditorHeightCalculation' style={{ position: 'absolute', top: '41px', bottom: '100px', width: '100%' }} >
<div id='editorContainer' style={{ padding: '1px', position: 'absolute', top: '0px', bottom: '34px', left: '0px', right: '2px' }}>
<EventContentPanel
context={context}
event={event}
......@@ -38,37 +38,51 @@ class NewOrEditEventPanel extends React.Component {
onEventModified={this.onEventModified}
user={user}
/>
<Grid fluid style={{ overflow: 'auto', height: '60px' }}>
<Grid fluid style={{ height: '100px' }}>
<Row>
<Col xs={4}> <CreationDate event={event} /> </Col>
<Col xs={4}> <CommentBy event={event} /> </Col>
<Col xs={3}> <EventHistory event={event} /> </Col>
<Col xs={1}>
{/* <Col xs={1}>
<Button bsSize='xsmall' onClick={() => this.setState({ optionPanelDecollaped: !this.state.optionPanelDecollaped })}>
<Glyphicon glyph='option-vertical' />
</Button>
</Col>
</Col> */}
</Row>
<Row>
<Label style={{ margin: '6px 6px 6px 12px', paddingRight: '2px' }}> Tags </Label>
<OverlayTrigger
placement='top'
overlay={<Tooltip id='tooltip'> <p> Manage tags </p> </Tooltip>}>
<a href={"/investigation/" + this.props.investigationId + "/events/tagManager"} target="_blank" style={{ fontSize: '12px' }}> <Glyphicon glyph='cog' /> </a>
</OverlayTrigger>
<TagContainer
canEnableSaveButton={this.onEventModified}
context={context}
event={event}
investigationId={this.props.investigationId}
setTagContainer={this.setTagContainer}
/>
<Panel id="optionPanel" style={{ border: 'none', marginBottom: '0px' }} expanded={this.state.optionPanelDecollaped}>
<Panel.Collapse>
<LabeledElement type='input' data={event ? event.title : null} labelText='title' onEventModified={this.onEventModified} setTitleInput={this.setTitleInput} tooltip='title of the event' />
</Panel.Collapse>
</Panel>
<Col xs={12} style={{ paddingTop: '8px', paddingBottom: '8px' }}>
<div style={{ display: 'flex' }}>
<div style={{ flex: '0 0 70px' }}>
<Label style={{ margin: '0px 6px 0px 0px', paddingRight: '2px' }}> Tags </Label>
<OverlayTrigger
placement='top'
overlay={<Tooltip id='tooltip'> <p> Manage tags </p> </Tooltip>}>
<a href={"/investigation/" + this.props.investigationId + "/events/tagManager"} target="_blank" style={{ fontSize: '12px' }}> <Glyphicon glyph='cog' /> </a>
</OverlayTrigger>
</div>
<div style={{ flex: '1 1 100px' }}>
<TagContainer
canEnableSaveButton={this.onEventModified}
context={context}
event={event}
investigationId={this.props.investigationId}
setTagContainer={this.setTagContainer}
/>
</div>
</div>
{/* <Panel id="optionPanel" style={{ border: 'none', marginBottom: '0px' }} expanded={this.state.optionPanelDecollaped}>
<Panel.Collapse>
<LabeledElement type='input' data={event ? event.title : null} labelText='title' onEventModified={this.onEventModified} setTitleInput={this.setTitleInput} tooltip='title of the event' />
</Panel.Collapse>
</Panel> */}
</Col>
</Row>
</Grid>
</div>
......@@ -80,7 +94,7 @@ class NewOrEditEventPanel extends React.Component {
onCancelButtonClicked={() => this.onCancelButtonClicked()}
onSaveButtonClicked={() => this.onSaveButtonClicked()} />
</div>
</Panel>
</Panel >
)
}
......
......@@ -17,12 +17,12 @@ class OverlayBox extends React.Component {
render() {
return (<Modal
classNames={this.props.classNames}
onClose={() => null}
onClose={this.props.onClose}
onEntered={this.onEntered}
onExited={this.onExited}
open={this.props.open}
blockScroll={false}
showCloseIcon={false}
showCloseIcon={this.props.onClose ? true : false}
focusTrapped={false}
center={true}
>
......
.arrow-prev, .arrow-next {
width: 10px
}
.customInnerWrapperClass {
transform: translate3d(0px, 0px, 0px);
transition: transform 0.4s ease 0s;
width: unset!important;
text-align: left;
user-select: none;
white-space: nowrap;
}
.customWrapperClass {
overflow: hidden;
user-select: none;
flex: 1 1 100px;
}
\ No newline at end of file
import React from 'react';
import PropTypes from 'prop-types';
import { Grid, Row, Col } from 'react-bootstrap';
import { TAG_MANAGER_CONTEXT, BASIC_EVENT_CONTEXT, DETAILED_EVENT_CONTEXT, INFO_MESSAGE_TYPE } from '../../../constants/EventTypes';
import { TAG_MANAGER_CONTEXT, BASIC_EVENT_CONTEXT, EDIT_EVENT_CONTEXT, INFO_MESSAGE_TYPE } from '../../../constants/EventTypes';
import TagViewer from './TagViewer';
import CreatableSelect from 'react-select/lib/Creatable';
import _ from 'lodash';
import { GUI_CONFIG } from '../../../config/gui.config';
import UserMessage from '../../UserMessage';
import ScrollMenu from 'react-horizontal-scrolling-menu';
import './TagList.css';
/**
* React component which handles tags (create, edit, remove)
......@@ -23,7 +25,7 @@ class TagList extends React.Component {
let { availableTags, context } = this.props;
if (context === DETAILED_EVENT_CONTEXT) {
if (context === EDIT_EVENT_CONTEXT) {
// show tags inside a detailed event
const customStyles = {
dropdownIndicator: () => ({
......@@ -50,20 +52,26 @@ class TagList extends React.Component {
...provided,
paddingTop: '0px',
paddingBottom: '0px',
}),
menu: (provided) => ({
...provided,
bottom: '100%',
top: 'unset',
})
};
let selectedTags = this.props.selectedTags ?
this.props.selectedTags.map((tag) => { return (<TagViewer key={tag._id} context={DETAILED_EVENT_CONTEXT} tag={tag} removeTag={this.props.removeTagFromSelection} />); })
this.props.selectedTags.map((tag) => { return (<TagViewer key={tag._id} context={EDIT_EVENT_CONTEXT} tag={tag} removeTag={this.props.removeTagFromSelection} />); })
: null;
let availableTagsForSelect = availableTags ?
availableTags.map((tag) => ({ value: tag._id, label: tag.name }))
: null;
return (
<div style={{ display: 'inline-block' }}>
<div style={{ display: 'inline-block', paddingRight: '10px', paddingTop:'5px' }}>
<div style={{ display: 'flex' }}>
<div style={{ flex: '0 0 148px' }}>
<CreatableSelect
isClearable={false}
noOptionsMessage={() => 'No existing tag'}
......@@ -72,7 +80,16 @@ class TagList extends React.Component {
options={availableTagsForSelect}
isSearchable={true} />
</div>
{selectedTags}
<div style={{ flex: '1 1 100px', overflow: 'hidden' }}>
<ScrollMenu
data={selectedTags}
arrowLeft={<div className='arrow-prev'> &#60; </div>}
arrowRight={<div className='arrow-next'> &#62; </div>}
wrapperClass='customWrapperClass'
innerWrapperClass='customInnerWrapperClass'
/>
</div>
</div>
);
......
......@@ -3,13 +3,13 @@ import PropTypes from 'prop-types';
import { Label, Glyphicon } from 'react-bootstrap';
import { Row, Col, Button } from "react-bootstrap"
import { TAG_MANAGER_CONTEXT, BASIC_EVENT_CONTEXT, DETAILED_EVENT_CONTEXT } from '../../../constants/EventTypes';
import { TAG_MANAGER_CONTEXT, BASIC_EVENT_CONTEXT, EDIT_EVENT_CONTEXT } from '../../../constants/EventTypes';
class TagViewer extends React.Component {
render() {
let { context, tag } = this.props;
if (context === DETAILED_EVENT_CONTEXT) {
if (context === EDIT_EVENT_CONTEXT) {
return (<div style={{ display: 'inline-block', marginRight: '4px' }}>
<Label
style={{
......
......@@ -320,13 +320,22 @@ div.collapsedEventPanel-heading:hover {
}
}
.userMessageModalClass {
padding: unset;
}
.userMessageCloseButton {
top: 7px;
right: 10px;
}
/* TinyMCE editor */
.mce-tinymce, .mce-container-body, #code_ifr {
#editorContainer .mce-tinymce, #editorContainer .mce-tinymce .mce-container-body {
min-height: 100% !important;
}
.mce-container-body {
#editorContainer .mce-tinymce .mce-container-body {
position: absolute!important;
bottom: 0;
left: 0;
......
import React from 'react';
import PropTypes from 'prop-types';
import { INFO_MESSAGE_TYPE, SUCCESS_MESSAGE_TYPE, ERROR_MESSAGE_TYPE } from '../constants/UserMessages';
import { Alert } from 'react-bootstrap';
import { Panel } from 'react-bootstrap';
/* React component which displays a message to the user */
class UserMessage extends React.Component {
render() {
const { type, message, isTextCentered } = this.props;
function getStyle(isTextCentered) {
if (isTextCentered) {
return { textAlign: 'center', borderRadius: '20px', marginLeft:'10px', marginRight:'10px' };
} else {
return { textAlign: 'left', borderRadius: '20px', marginLeft:'10px', marginRight:'10px' };
}
}
const { type, message } = this.props;
if (type && message && message !== '') {
if (type === INFO_MESSAGE_TYPE) {
return (<Alert bsStyle='info' style={getStyle(isTextCentered)} > {message} </Alert>);
}
if (type === SUCCESS_MESSAGE_TYPE) {
return (
<Alert bsStyle='success' style={getStyle(isTextCentered)} > {message} </Alert>);
}
if (type === ERROR_MESSAGE_TYPE) {
return (
<Alert bsStyle='danger' style={getStyle(isTextCentered)} > {message} </Alert>);
}
} else {
return null;
return (<Panel bsStyle={type === INFO_MESSAGE_TYPE ? 'info' : (type === SUCCESS_MESSAGE_TYPE) ? 'success' : (type === ERROR_MESSAGE_TYPE) ? 'danger' : 'primary'} style={{ marginBottom: '0px' }}>
<Panel.Heading>
{type === INFO_MESSAGE_TYPE ? 'Information message' : (type === SUCCESS_MESSAGE_TYPE) ? 'Information message' : (type === ERROR_MESSAGE_TYPE) ? 'Error message' : 'Message'}
</Panel.Heading>
<Panel.Body>
{message}
</Panel.Body>
</Panel>)
}
return null;
}
}
......@@ -39,8 +27,6 @@ UserMessage.propTypes = {
message: PropTypes.string.isRequired,
/* the type of the message */
type: PropTypes.string.isRequired,
/* whether the text is centered. TRUE when the text is centered. FALSE or NO VALUE aligns the text on the left */
isTextCentered: PropTypes.bool
};
export default UserMessage;
\ No newline at end of file
......@@ -23,7 +23,7 @@ export const READ_MODE = 'event in basic read mode';
export const EDIT_MODE = 'event in edition mode';
export const BASIC_EVENT_CONTEXT = 'basicEventContext';
export const DETAILED_EVENT_CONTEXT = 'detailedEventContext';
//export const DETAILED_EVENT_CONTEXT = 'detailedEventContext';
export const NEW_EVENT_CONTEXT = 'newEventContext';
export const EDIT_EVENT_CONTEXT = 'editEventContext';
export const EVENT_HISTORY_ORIGINAL_VERSION_CONTEXT = 'eventHistoryOriginalVersionContext';
......
......@@ -74,7 +74,9 @@ class LogbookContainer extends React.Component {
if (this.isAppProperlyConfigured()) {
return (
<div style={{ marginBottom: '40px' }}>
<UserMessage type={ERROR_MESSAGE_TYPE} message={this.state.errorMessage} />
<OverlayBox open={this.state.errorMessage} onClose={() => { this.setState({ errorMessage: null }) }} classNames={{ modal: 'userMessageModalClass', closeButton:'userMessageCloseButton' }}>
<UserMessage type={ERROR_MESSAGE_TYPE} message={this.state.errorMessage} />
</OverlayBox>
<EventListMenu
availableTags={this.props.availableTags}
......@@ -173,6 +175,9 @@ class LogbookContainer extends React.Component {
}
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 });
}
......
......@@ -2,9 +2,9 @@ import React, { Component } from 'react';
import ICATPLUS from '../config/icat/icatPlus.js';
import { connect } from 'react-redux';
import { setBreadCrumbs } from '../actions/breadcrumbs.js';
import { ReactiveBase, DateRange, MultiList, SingleRange, CategorySearch, ResultCard } from '@appbaseio/reactivesearch';
import { ReactiveBase, RangeInput, DateRange, MultiList, CategorySearch, ResultCard, SingleDropdownList } from '@appbaseio/reactivesearch';
import moment from 'moment';
import { Label, Badge, Image, Grid, Row, Col, FormControl, ButtonToolbar, ToggleButtonGroup, ToggleButton } from 'react-bootstrap';
import { Label, Grid, Row, Col } from 'react-bootstrap';
import { getFileByEventId } from '../api/icat/icatPlus.js';
import noimage from '../images/noimage.png';
import TECHNIQUES from '../config/techniques/techniques.js';
......@@ -104,38 +104,43 @@ class SearchContainer extends Component {
<Col xs={10}>
<CategorySearch
componentId="searchbox"
dataField={["investigationName", "investigationSummary","name", "definition"]}
dataField={["escompactsearch"]}
categoryField="investigationName.keyword"
queryFormat="or"
placeholder="Search by dataset name, sample name or investigation title" />
</Col>
</Row>
<Row>
<Col sm={2}>
<br />
<Col sm={2}>
<br />
<DateRange
componentId="DateSensor"
dataField="startDate"
title="Filter by date"
/>
<br />
<MultiList
componentId="BeamlineSensor"
dataField="investigationVisitId.keyword"
title="Beamlines"
react={{
and: ["DateSensor", "DefinitionSensor"]
}}
/>
<br />
<MultiList
componentId="DefinitionSensor"
dataField="definition.keyword"
title="Technique"
react={{
and: ["DateSensor", "BeamlineSensor"]
}}
/>
</Col>
<Col sm={10}>
<Col sm={8}>
<ResultCard
componentId="result"
title="Results"
......@@ -147,14 +152,40 @@ class SearchContainer extends Component {
stream={true}
showResultStats={true}
react={{
and: ["searchbox", "DateSensor", "BeamlineSensor", "DefinitionSensor"]
//and: ["SingleDropdownListUsage", "RangeSliderSensorWavelength", "searchbox", "DateSensor", "BeamlineSensor", "DefinitionSensor", "RangeSliderSensor", "SingleDropdownListReflection"]
//and: ["searchbox", "DateSensor", "BeamlineSensor", "DefinitionSensor"]
//and: ["searchbox", "DateSensor", "BeamlineSensor", "DefinitionSensor", "SingleDropdownListUsage", "SingleDropdownListType", "SingleDropdownListReflection", "RangeSliderSensorEnergy", "RangeSliderSensorWavelength"]
and: ["searchbox", "DateSensor", "BeamlineSensor", "DefinitionSensor", "SingleDropdownListUsage", "SingleDropdownListType", "SingleDropdownListReflection"]
}}
onData={(res) => {
return this.renderDataset(res);
}}
/>
</Col>
</Col>
<Col sm={2}>
<br />
<SingleDropdownList
componentId="SingleDropdownListType"
dataField="InstrumentMonochromatorCrystal_type.keyword"
title="Crystal Type"
/>
<br />
<SingleDropdownList
componentId="SingleDropdownListReflection"
dataField="InstrumentMonochromatorCrystal_reflection.keyword"
title="Crystal Reflection"
/>
<br />
<SingleDropdownList
componentId="SingleDropdownListUsage"
dataField="InstrumentMonochromatorCrystal_usage.keyword"
title="Crystal Usage"
/>
</Col>
</Row>
</Grid>
</ReactiveBase>
......
......@@ -6,7 +6,7 @@ import TagList from '../components/Event/Tag/TagList';
import TagEditor from '../components/Event/Tag/TagEditor';
import { getTagsByInvestigationId, createTagsByInvestigationId, updateTagsByInvestigationId } from '../api/icat/icatPlus';
import _ from 'lodash';
import { INFO_MESSAGE_TYPE, ERROR_MESSAGE_TYPE, TAG_MANAGER_CONTEXT, BASIC_EVENT_CONTEXT, TAG_EDITOR_CONTEXT, TAG_CREATOR_CONTEXT, NEW_EVENT_CONTEXT, EDIT_EVENT_CONTEXT, DETAILED_EVENT_CONTEXT, FETCHED_STATUS, FETCHING_STATUS } from '../constants/EventTypes';
import { INFO_MESSAGE_TYPE, ERROR_MESSAGE_TYPE, TAG_MANAGER_CONTEXT, BASIC_EVENT_CONTEXT, TAG_EDITOR_CONTEXT, TAG_CREATOR_CONTEXT, NEW_EVENT_CONTEXT, EDIT_EVENT_CONTEXT, FETCHED_STATUS, FETCHING_STATUS } from '../constants/EventTypes';
import TagActionBar from '../components/Event/Tag/TagActionBar';
import UserMessage from '../components/UserMessage';
import { SUCCESS_MESSAGE_TYPE } from '../constants/UserMessages';
......@@ -52,22 +52,22 @@ class TagContainer extends React.Component {
}
if (this.props.availableTagsReceptionStatus === FETCHED_STATUS) {
if (this.state.context === BASIC_EVENT_CONTEXT) {
return (<div>
{userMessage}
<TagList
selectedTags={this.state.selectedTags}
context={BASIC_EVENT_CONTEXT}
/>
</div>);
}
// if (this.state.context === BASIC_EVENT_CONTEXT) {
// return (<div>
// {userMessage}
// <TagList
// selectedTags={this.state.selectedTags}
// context={BASIC_EVENT_CONTEXT}
// />
// </div>);
// }
if (this.state.context === EDIT_EVENT_CONTEXT || this.state.context === NEW_EVENT_CONTEXT) {
return (
<TagList
availableTags={this.props.availableTags}
addTagToSelection={this.addTagToSelection}
context={DETAILED_EVENT_CONTEXT}
context={EDIT_EVENT_CONTEXT}
createNewTag={this.createNewTag}
investigationId={investigationId}
removeTagFromSelection={this.removeTagFromSelection}
......@@ -134,7 +134,7 @@ class TagContainer extends React.Component {
// Checks whether available tags have been fetched already
if (this.props.availableTagsReceptionStatus === FETCHED_STATUS) {
if (this.props.context === DETAILED_EVENT_CONTEXT || this.props.context === BASIC_EVENT_CONTEXT) {
if (this.props.context === EDIT_EVENT_CONTEXT || this.props.context === NEW_EVENT_CONTEXT) {
this.isGettingSelectedTagsFromEventProp = false;
this.setSelectedTagsFromProps();
};
......@@ -145,7 +145,7 @@ class TagContainer extends React.Component {
}
componentDidUpdate() {
if (this.props.context === DETAILED_EVENT_CONTEXT) {
if (this.props.context === EDIT_EVENT_CONTEXT) {
if (this.props.availableTagsReceptionStatus === FETCHED_STATUS) {
if (this.isGettingSelectedTagsFromEventProp === true) {
this.isGettingSelectedTagsFromEventProp = false;
......@@ -245,7 +245,7 @@ class TagContainer extends React.Component {
console.log('The new tag was created successfully on ICAT+ server.');
let selectedTags = [];
if (this.props.context === DETAILED_EVENT_CONTEXT) {
if (this.props.context === EDIT_EVENT_CONTEXT || this.props.context === NEW_EVENT_CONTEXT) {
// ADD the new tag in the currently selected tags.
selectedTags = _.map(_this.state.selectedTags, _.clone);
selectedTags.push(newlyCreatedTag);
......@@ -256,7 +256,7 @@ class TagContainer extends React.Component {
let onSuccess = (data) => {
if (data.data.tags) {
this.setState({ context: nextContext, selectedTags: selectedTags });
if (this.props.context !== DETAILED_EVENT_CONTEXT) {
if (this.props.context !== NEW_EVENT_CONTEXT || this.props.context !== EDIT_EVENT_CONTEXT) {
this.setMessage(SUCCESS_MESSAGE_TYPE, 'Tag successfully created');
}
this.props.setAvailableTags(data.data.tags);
......
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