@@ -187,7 +236,8 @@ export const ProjectDetailDrawer = memo(({ showHistory, setShowHistory }) => {
email: (currentSnapshotTree.author && currentSnapshotTree.author.email) || '',
hash: currentSnapshotTree.id,
isSelected: currentSnapshotID === currentSnapshotTree.id,
- created: currentSnapshotTree.created
+ created: currentSnapshotTree.created,
+ images
})
);
diff --git a/js/components/projects/redux/dispatchActions.js b/js/components/projects/redux/dispatchActions.js
index bb1eb5133..34ed6b19d 100644
--- a/js/components/projects/redux/dispatchActions.js
+++ b/js/components/projects/redux/dispatchActions.js
@@ -393,10 +393,9 @@ export const createProjectFromScratch = ({ title, description, target, author, t
});
};
-export const createProjectWithoutStateModification = data => dispatch => {
- return api({ url: `${base_url}/api/session-projects/`, method: METHOD.POST, data }).then(response => {
- return response.data.id;
- });
+export const createProjectWithoutStateModification = data => async () => {
+ const response = await api({ url: `${base_url}/api/session-projects/`, method: METHOD.POST, data });
+ return response.data.id;
};
export const createInitSnapshotToProjectWitActions = (session_project, author, parent, target) => (
diff --git a/js/components/snapshot/redux/dispatchActions.js b/js/components/snapshot/redux/dispatchActions.js
index e0fe26056..cc1641922 100644
--- a/js/components/snapshot/redux/dispatchActions.js
+++ b/js/components/snapshot/redux/dispatchActions.js
@@ -27,6 +27,7 @@ import { selectFirstMolGroup } from '../../preview/moleculeGroups/redux/dispatch
import { reloadDatasetsReducer } from '../../datasets/redux/actions';
import { saveCurrentActionsList } from '../../../reducers/tracking/dispatchActions';
import { sendTrackingActionsByProjectId, manageSendTrackingActions } from '../../../reducers/tracking/dispatchActions';
+import { captureScreenOfSnapshot } from '../../userFeedback/browserApi';
export const getListOfSnapshots = () => (dispatch, getState) => {
const userID = DJANGO_CONTEXT['pk'] || null;
@@ -215,7 +216,10 @@ export const createNewSnapshot = ({ title, description, type, author, parent, se
}).then(res => {
// redirect to project with newest created snapshot /:projectID/:snapshotID
if (res.data.id && session_project) {
- Promise.resolve(dispatch(saveCurrentActionsList(res.data.id, session_project, nglViewList))).then(() => {
+ let snapshot = { id: res.data.id, title: title };
+ let project = { projectID: session_project, authorID: author };
+
+ Promise.resolve(dispatch(saveCurrentActionsList(snapshot, project, nglViewList))).then(() => {
if (disableRedirect === false) {
// Really bad usage or redirection. Hint for everybody in this line ignore it, but in other parts of code
// use react-router !
@@ -251,6 +255,7 @@ export const activateSnapshotDialog = (loggedInUserID = undefined, finallyShareS
const projectID = state.projectReducers.currentProject.projectID;
const currentSnapshotAuthor = state.projectReducers.currentSnapshot.author;
+ dispatch(captureScreenOfSnapshot());
dispatch(manageSendTrackingActions());
dispatch(setDisableRedirect(finallyShareSnapshot));
@@ -321,13 +326,16 @@ export const createNewSnapshotWithoutStateModification = ({
disableRedirect: true
})
);
- dispatch(saveCurrentActionsList(res.data.id, session_project, nglViewList));
+
+ let snapshot = { id: res.data.id, title: title };
+ let project = { projectID: session_project, authorID: author };
+ dispatch(saveCurrentActionsList(snapshot, project, nglViewList));
}
});
});
};
-export const saveAndShareSnapshot = nglViewList => (dispatch, getState) => {
+export const saveAndShareSnapshot = nglViewList => async (dispatch, getState) => {
const state = getState();
const targetId = state.apiReducers.target_on;
const loggedInUserID = DJANGO_CONTEXT['pk'];
@@ -335,6 +343,7 @@ export const saveAndShareSnapshot = nglViewList => (dispatch, getState) => {
dispatch(setDisableRedirect(true));
if (targetId) {
+ dispatch(captureScreenOfSnapshot());
dispatch(setIsLoadingSnapshotDialog(true));
const data = {
title: ProjectCreationType.READ_ONLY,
@@ -344,36 +353,34 @@ export const saveAndShareSnapshot = nglViewList => (dispatch, getState) => {
tags: '[]'
};
- dispatch(createProjectWithoutStateModification(data))
- .then(projectID => {
- const username = DJANGO_CONTEXT['username'];
- const title = moment().format('-- YYYY-MM-DD -- HH:mm:ss');
- const description =
- loggedInUserID === undefined ? 'Snapshot generated by anonymous user' : `snapshot generated by ${username}`;
- const type = SnapshotType.MANUAL;
- const author = loggedInUserID || null;
- const parent = null;
- const session_project = projectID;
-
- dispatch(sendTrackingActionsByProjectId(projectID, author));
-
- return dispatch(
- createNewSnapshotWithoutStateModification({
- title,
- description,
- type,
- author,
- parent,
- session_project,
- nglViewList
- })
- );
- })
- .catch(error => {
- throw new Error(error);
- })
- .finally(() => {
- dispatch(setIsLoadingSnapshotDialog(false));
- });
+ try {
+ let projectID = await dispatch(createProjectWithoutStateModification(data));
+ const username = DJANGO_CONTEXT['username'];
+ const title = moment().format('-- YYYY-MM-DD -- HH:mm:ss');
+ const description =
+ loggedInUserID === undefined ? 'Snapshot generated by anonymous user' : `snapshot generated by ${username}`;
+ const type = SnapshotType.MANUAL;
+ const author = loggedInUserID || null;
+ const parent = null;
+ const session_project = projectID;
+
+ await dispatch(sendTrackingActionsByProjectId(projectID, author));
+
+ await dispatch(
+ createNewSnapshotWithoutStateModification({
+ title,
+ description,
+ type,
+ author,
+ parent,
+ session_project,
+ nglViewList
+ })
+ );
+
+ dispatch(setIsLoadingSnapshotDialog(false));
+ } catch (error) {
+ throw new Error(error);
+ }
}
};
diff --git a/js/components/tracking/EditableText.js b/js/components/tracking/EditableText.js
new file mode 100644
index 000000000..91549d9de
--- /dev/null
+++ b/js/components/tracking/EditableText.js
@@ -0,0 +1,68 @@
+import React, { useState, useRef, useEffect } from 'react';
+import { makeStyles, TextField, IconButton, Tooltip, Grid } from '@material-ui/core';
+import { Edit } from '@material-ui/icons';
+
+const useStyles = makeStyles(theme => ({
+ search: {
+ width: '100%'
+ },
+ fontSizeSmall: {
+ fontSize: '0.82rem'
+ }
+}));
+
+const EditableInput = ({ dataText, index, updateText }) => {
+ const inputRef = useRef(null);
+ const [inputVisible, setInputVisible] = useState(false);
+ const [text, setText] = useState(dataText);
+ const classes = useStyles();
+
+ const onClickOutSide = e => {
+ if (inputRef.current && !inputRef.current.contains(e.target)) {
+ setInputVisible(false);
+ if (updateText && text !== dataText) {
+ updateText(text);
+ }
+ }
+ };
+
+ useEffect(() => {
+ // Handle outside clicks on mounted state
+ if (inputVisible) {
+ document.addEventListener('mousedown', onClickOutSide);
+ }
+
+ // This is a necessary step to "dismount" unnecessary events when we destroy the component
+ return () => {
+ document.removeEventListener('mousedown', onClickOutSide);
+ };
+ });
+
+ return (
+
+ {inputVisible ? (
+ {
+ setText(e.target.value);
+ }}
+ />
+ ) : (
+
+ { setInputVisible(true)}>{text}}
+ {
+ setInputVisible(true)}>
+
+
+
+
+ }
+
+ )}
+
+ );
+};
+
+export default EditableInput;
diff --git a/js/components/tracking/timelineView.js b/js/components/tracking/timelineView.js
new file mode 100644
index 000000000..18036eed2
--- /dev/null
+++ b/js/components/tracking/timelineView.js
@@ -0,0 +1,228 @@
+import React, { useState, useRef, memo } from 'react';
+import { useDispatch, useSelector } from 'react-redux';
+import { makeStyles, IconButton, Tooltip, Grid, Box, Chip } from '@material-ui/core';
+import { Check, Clear, Warning, Favorite, Star } from '@material-ui/icons';
+import { actionAnnotation } from '../../reducers/tracking/constants';
+import { TimelineEvent } from 'react-event-timeline';
+import EditableText from './editableText';
+import palette from '../../theme/palette';
+import { updateTrackingActions } from '../../reducers/tracking/dispatchActions';
+import { actionType } from '../../reducers/tracking/constants';
+import Gallery from 'react-grid-gallery';
+
+const useStyles = makeStyles(theme => ({
+ headerGrid: {
+ height: '15px'
+ },
+ grid: {
+ height: 'inherit'
+ },
+ iconButton: {
+ padding: '6px',
+ paddingTop: '0px'
+ },
+ timelineEvent: {
+ borderBottom: '1px dashed ' + palette.divider,
+ paddingBottom: '10px'
+ },
+ title: {
+ position: 'relative',
+ paddingLeft: '45px',
+ textAlign: 'left',
+ fontWeight: 'bold'
+ },
+ titleMargin: {
+ marginRight: '5px'
+ }
+}));
+
+const TimelineView = memo(({ data, index }) => {
+ const dispatch = useDispatch();
+ const classes = useStyles();
+
+ const currentSnapshotID = useSelector(state => state.projectReducers.currentSnapshot.id);
+ let isSelected = currentSnapshotID === data.object_id;
+
+ const ref = useRef(null);
+ const [isHovering, setIsHovering] = useState(false);
+ const [updatedIcon, setUpdatedIcon] = useState(null);
+
+ const getActionIcon = annotation => {
+ if (annotation) {
+ switch (annotation) {
+ case actionAnnotation.CHECK:
+ return ;
+ case actionAnnotation.CLEAR:
+ return ;
+ case actionAnnotation.WARNING:
+ return ;
+ case actionAnnotation.FAVORITE:
+ return ;
+ case actionAnnotation.STAR:
+ return ;
+ default:
+ return ;
+ }
+ } else {
+ return ;
+ }
+ };
+
+ const annotationActions = [
+ {
+ setUpdatedIcon(actionAnnotation.CHECK);
+ updateDataAnnotation(actionAnnotation.CHECK);
+ }}
+ >
+
+
+
+ ,
+ {
+ setUpdatedIcon(actionAnnotation.CLEAR);
+ updateDataAnnotation(actionAnnotation.CLEAR);
+ }}
+ >
+
+
+
+ ,
+ {
+ setUpdatedIcon(actionAnnotation.WARNING);
+ updateDataAnnotation(actionAnnotation.WARNING);
+ }}
+ >
+
+
+
+ ,
+ {
+ setUpdatedIcon(actionAnnotation.FAVORITE);
+ updateDataAnnotation(actionAnnotation.FAVORITE);
+ }}
+ >
+
+
+
+ ,
+ {
+ setUpdatedIcon(actionAnnotation.STAR);
+ updateDataAnnotation(actionAnnotation.STAR);
+ }}
+ >
+
+
+
+
+ ];
+
+ const updateDataText = text => {
+ data.text = text;
+ dispatch(updateTrackingActions(data));
+ };
+
+ const updateDataAnnotation = annotation => {
+ data.annotation = annotation;
+ dispatch(updateTrackingActions(data));
+ };
+
+ const images = [
+ {
+ src: data.image,
+ thumbnail: data.image,
+ thumbnailWidth: 0,
+ thumbnailHeight: 0,
+ caption: data.object_name
+ }
+ ];
+
+ return (
+ setIsHovering(true)} onMouseLeave={() => setIsHovering(false)}>
+ {data.type && data.type === actionType.SNAPSHOT ? (
+ <>
+
+ {isSelected && (
+
+
+
+ )}
+ {
+
+ {`${data.text}`}
+
+ }
+ {
+
+
+
+ }
+
+ >
+ ) : (
+ <>
+
+
+ {
+
+
+
+ }
+ {isHovering && (
+
+ {annotationActions &&
+ annotationActions.map((action, index) => (
+
+ {action}
+
+ ))}
+
+ )}
+
+
+ }
+ createdAt={new Date(data.timestamp).toLocaleString()}
+ icon={updatedIcon && updatedIcon != null ? getActionIcon(updatedIcon) : getActionIcon(data.annotation)}
+ iconColor={palette.primary.main}
+ className={classes.timelineEvent}
+ >
+ >
+ )}
+
+ );
+});
+
+TimelineView.displayName = 'TimelineView';
+export default TimelineView;
diff --git a/js/components/tracking/trackingModal.js b/js/components/tracking/trackingModal.js
index d47761e84..09cb10118 100644
--- a/js/components/tracking/trackingModal.js
+++ b/js/components/tracking/trackingModal.js
@@ -2,10 +2,10 @@ import React, { memo, useCallback, useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import Modal from '../common/Modal';
import { Grid, makeStyles, IconButton, Tooltip } from '@material-ui/core';
-import { Timeline, TimelineEvent } from 'react-event-timeline';
-import { Check, Clear, Close } from '@material-ui/icons';
-import palette from '../../theme/palette';
+import { Timeline } from 'react-event-timeline';
+import { Close } from '@material-ui/icons';
import { Panel } from '../common';
+import TimelineView from './timelineView';
import { setProjectTrackingActions } from '../../reducers/tracking/dispatchActions';
const useStyles = makeStyles(theme => ({
@@ -16,10 +16,7 @@ const useStyles = makeStyles(theme => ({
customContentModal: {
height: '100%'
},
- timelineEvent: {
- borderBottom: '1px dashed ' + palette.divider,
- paddingBottom: '10px'
- },
+
divContainer: {
height: '100%',
width: '100%',
@@ -78,24 +75,7 @@ export const TrackingModal = memo(({ openModal, onModalClose }) => {
{orderedActionList &&
orderedActionList.map((data, index) => {
if (data && data != null) {
- return (
-
- ) : (
-
- )
- }
- iconColor={palette.primary.main}
- className={classes.timelineEvent}
- >
- );
+ return ;
}
})}
diff --git a/js/components/userFeedback/browserApi.js b/js/components/userFeedback/browserApi.js
index 3a40b14ea..f14b006eb 100644
--- a/js/components/userFeedback/browserApi.js
+++ b/js/components/userFeedback/browserApi.js
@@ -1,5 +1,6 @@
import { setImageSource, setIsOpenForm } from './redux/actions';
-
+import { setTrackingImageSource } from '../../reducers/tracking/actions';
+import html2canvas from 'html2canvas';
/* Getting image from screen capture or */
// https://stackoverflow.com/questions/9847580/how-to-detect-safari-chrome-ie-firefox-and-opera-browser
@@ -81,3 +82,9 @@ export const captureScreen = () => async dispatch => {
dispatch(setImageSource(image));
dispatch(setIsOpenForm(true));
};
+
+export const captureScreenOfSnapshot = () => async dispatch => {
+ html2canvas(document.body).then(canvas => {
+ dispatch(setTrackingImageSource(canvas.toDataURL()));
+ });
+};
diff --git a/js/reducers/tracking/actions.js b/js/reducers/tracking/actions.js
index d3efec7a2..6dc0fd75a 100644
--- a/js/reducers/tracking/actions.js
+++ b/js/reducers/tracking/actions.js
@@ -84,6 +84,13 @@ export const setProjectActionList = function(project_actions_list) {
};
};
+export const setSnapshotImageActionList = function(snapshotActionImageList) {
+ return {
+ type: constants.SET_SNAPSOT_IMAGE_ACTIONS_LIST,
+ snapshotActionImageList: snapshotActionImageList
+ };
+};
+
export const setIsActionsSaving = function(isActionSaving) {
return {
type: constants.SET_IS_ACTIONS_SAVING,
@@ -104,3 +111,8 @@ export const resetTrackingState = function() {
type: constants.RESET_TRACKING_STATE
};
};
+
+export const setTrackingImageSource = imageSource => ({
+ type: constants.SET_TRACKING_IMAGE_SOURCE,
+ payload: imageSource
+});
diff --git a/js/reducers/tracking/constants.js b/js/reducers/tracking/constants.js
index b1576102b..b95b41327 100644
--- a/js/reducers/tracking/constants.js
+++ b/js/reducers/tracking/constants.js
@@ -15,7 +15,9 @@ export const constants = {
SET_PROJECT_ACTIONS_LIST: prefix + 'SET_PROJECT_ACTIONS_LIST',
SET_IS_ACTIONS_SAVING: prefix + 'SET_IS_ACTIONS_SAVING',
SET_IS_ACTIONS_RESTORING: prefix + 'SET_IS_ACTIONS_RESTORING',
- RESET_TRACKING_STATE: prefix + 'RESET_TRACKING_STATE'
+ RESET_TRACKING_STATE: prefix + 'RESET_TRACKING_STATE',
+ SET_TRACKING_IMAGE_SOURCE: prefix + 'SET_TRACKING_IMAGE_SOURCE',
+ SET_SNAPSOT_IMAGE_ACTIONS_LIST: prefix + 'SET_SNAPSOT_IMAGE_ACTIONS_LIST'
};
export const actionType = {
@@ -44,6 +46,7 @@ export const actionType = {
NGL_STATE: 'NGL_STATE',
UNDO: 'UNDO',
REDO: 'REDO',
+ SNAPSHOT: 'SNAPSHOT',
ALL_HIDE: 'ALL_HIDE',
ALL_TURNED_ON: 'ALL_TURNED_ON',
ALL_TURNED_OFF: 'ALL_TURNED_OFF',
@@ -86,3 +89,11 @@ export const actionObjectType = {
CROSS_REFERENCE: 'CROSS_REFERENCE',
REPRESENTATION: 'REPRESENTATION'
};
+
+export const actionAnnotation = {
+ CHECK: 'CHECK',
+ CLEAR: 'CLEAR',
+ WARNING: 'WARNING',
+ FAVORITE: 'FAVORITE',
+ STAR: 'STAR'
+};
diff --git a/js/reducers/tracking/dispatchActions.js b/js/reducers/tracking/dispatchActions.js
index 93b2b353e..27b5b3d7b 100644
--- a/js/reducers/tracking/dispatchActions.js
+++ b/js/reducers/tracking/dispatchActions.js
@@ -61,7 +61,13 @@ import {
import * as listType from '../../constants/listTypes';
import { assignRepresentationToComp } from '../../components/nglView/generatingObjects';
import { deleteObject, setOrientation } from '../../../js/reducers/ngl/dispatchActions';
-import { setSendActionsList, setIsActionsSending, setIsActionsLoading, setActionsList } from './actions';
+import {
+ setSendActionsList,
+ setIsActionsSending,
+ setIsActionsLoading,
+ setActionsList,
+ setSnapshotImageActionList
+} from './actions';
import { api, METHOD } from '../../../js/utils/api';
import { base_url } from '../../components/routes/constants';
import { CONSTANTS } from '../../../js/constants/constants';
@@ -88,12 +94,15 @@ import {
setDeselectedAllByType as setDeselectedAllByTypeOfDataset
} from '../../components/datasets/redux/actions';
-export const saveCurrentActionsList = (snapshotID, projectID, nglViewList) => async (dispatch, getState) => {
+export const saveCurrentActionsList = (snapshot, project, nglViewList) => async (dispatch, getState) => {
+ let projectID = project && project.projectID;
let actionList = await dispatch(getTrackingActions(projectID));
- dispatch(saveActionsList(snapshotID, actionList, nglViewList));
+
+ dispatch(setSnapshotToActions(actionList, snapshot, projectID));
+ await dispatch(saveActionsList(project, snapshot, actionList, nglViewList));
};
-export const saveActionsList = (snapshotID, actionList, nglViewList) => (dispatch, getState) => {
+const saveActionsList = (project, snapshot, actionList, nglViewList) => async (dispatch, getState) => {
const state = getState();
const currentTargetOn = state.apiReducers.target_on;
@@ -201,97 +210,188 @@ export const saveActionsList = (snapshotID, actionList, nglViewList) => (dispatc
getCollection(currentProteins),
currentActions
);
+ const snapshotID = snapshot && snapshot.id;
+ if (snapshotID) {
+ const currentTargetOn = state.apiReducers.target_on;
+ const currentSites = state.selectionReducers.mol_group_selection;
+ const currentLigands = state.selectionReducers.fragmentDisplayList;
+ const currentProteins = state.selectionReducers.proteinList;
+ const currentComplexes = state.selectionReducers.complexList;
+ const currentSurfaces = state.selectionReducers.surfaceList;
+ const currentVectors = state.selectionReducers.vectorOnList;
+ const currentBuyList = state.selectionReducers.to_buy_list;
+ const currentVector = state.selectionReducers.currentVector;
+ const currentSelectionAll = state.selectionReducers.moleculeAllSelection;
+
+ const currentDatasetLigands = state.datasetsReducers.ligandLists;
+ const currentDatasetProteins = state.datasetsReducers.proteinLists;
+ const currentDatasetComplexes = state.datasetsReducers.complexLists;
+ const currentDatasetSurfaces = state.datasetsReducers.surfaceLists;
+ const currentDatasetSelectionAll = state.datasetsReducers.moleculeAllSelection;
+
+ const currentDatasetBuyList = state.datasetsReducers.compoundsToBuyDatasetMap;
+ const currentobjectsInView = state.nglReducers.objectsInView;
+
+ const currentTargets = (currentTargetOn && [currentTargetOn]) || [];
+ const currentVectorSmiles = (currentVector && [currentVector]) || [];
+
+ let orderedActionList = actionList.reverse((a, b) => a.timestamp - b.timestamp);
+
+ let currentActions = [];
+
+ getCurrentActionList(orderedActionList, actionType.TARGET_LOADED, getCollection(currentTargets), currentActions);
+ getCurrentActionList(orderedActionList, actionType.SITE_TURNED_ON, getCollection(currentSites), currentActions);
+ getCurrentActionList(orderedActionList, actionType.LIGAND_TURNED_ON, getCollection(currentLigands), currentActions);
+
+ getCurrentActionList(
+ orderedActionList,
+ actionType.ALL_TURNED_ON,
+ getCollection(currentSelectionAll),
+ currentActions
+ );
+ getCurrentActionList(
+ orderedActionList,
+ actionType.ALL_TURNED_ON,
+ getCollectionOfDataset(currentDatasetSelectionAll),
+ currentActions
+ );
- getCurrentActionList(
- orderedActionList,
- actionType.INTERACTIONS_TURNED_ON,
- getCollection(currentComplexes),
- currentActions
- );
- getCurrentActionList(orderedActionList, actionType.SURFACE_TURNED_ON, getCollection(currentSurfaces), currentActions);
- getCurrentActionList(orderedActionList, actionType.VECTORS_TURNED_ON, getCollection(currentVectors), currentActions);
- getCurrentActionList(
- orderedActionList,
- actionType.VECTOR_SELECTED,
- getCollection(currentVectorSmiles),
- currentActions
- );
+ getCurrentActionList(
+ orderedActionList,
+ actionType.SIDECHAINS_TURNED_ON,
+ getCollection(currentProteins),
+ currentActions
+ );
- getCurrentActionList(
- orderedActionList,
- actionType.MOLECULE_ADDED_TO_SHOPPING_CART,
- getCollectionOfShoppingCart(currentBuyList),
- currentActions
- );
+ getCurrentActionList(
+ orderedActionList,
+ actionType.INTERACTIONS_TURNED_ON,
+ getCollection(currentComplexes),
+ currentActions
+ );
+ getCurrentActionList(
+ orderedActionList,
+ actionType.SURFACE_TURNED_ON,
+ getCollection(currentSurfaces),
+ currentActions
+ );
+ getCurrentActionList(
+ orderedActionList,
+ actionType.VECTORS_TURNED_ON,
+ getCollection(currentVectors),
+ currentActions
+ );
+ getCurrentActionList(
+ orderedActionList,
+ actionType.VECTOR_SELECTED,
+ getCollection(currentVectorSmiles),
+ currentActions
+ );
- getCurrentActionList(
- orderedActionList,
- actionType.LIGAND_TURNED_ON,
- getCollectionOfDataset(currentDatasetLigands),
- currentActions
- );
+ getCurrentActionList(
+ orderedActionList,
+ actionType.MOLECULE_ADDED_TO_SHOPPING_CART,
+ getCollectionOfShoppingCart(currentBuyList),
+ currentActions
+ );
- getCurrentActionList(
- orderedActionList,
- actionType.SIDECHAINS_TURNED_ON,
- getCollectionOfDataset(currentDatasetProteins),
- currentActions
- );
+ getCurrentActionList(
+ orderedActionList,
+ actionType.LIGAND_TURNED_ON,
+ getCollectionOfDataset(currentDatasetLigands),
+ currentActions
+ );
- getCurrentActionList(
- orderedActionList,
- actionType.INTERACTIONS_TURNED_ON,
- getCollectionOfDataset(currentDatasetComplexes),
- currentActions
- );
+ getCurrentActionList(
+ orderedActionList,
+ actionType.SIDECHAINS_TURNED_ON,
+ getCollectionOfDataset(currentDatasetProteins),
+ currentActions
+ );
- getCurrentActionList(
- orderedActionList,
- actionType.SURFACE_TURNED_ON,
- getCollectionOfDataset(currentDatasetSurfaces),
- currentActions
- );
+ getCurrentActionList(
+ orderedActionList,
+ actionType.INTERACTIONS_TURNED_ON,
+ getCollectionOfDataset(currentDatasetComplexes),
+ currentActions
+ );
- getCurrentActionList(
- orderedActionList,
- actionType.COMPOUND_SELECTED,
- getCollectionOfDataset(currentDatasetBuyList),
- currentActions
- );
+ getCurrentActionList(
+ orderedActionList,
+ actionType.SURFACE_TURNED_ON,
+ getCollectionOfDataset(currentDatasetSurfaces),
+ currentActions
+ );
- getCurrentActionList(
- orderedActionList,
- actionType.REPRESENTATION_ADDED,
- getCollectionOfDatasetOfRepresentation(currentobjectsInView),
- currentActions
- );
+ getCurrentActionList(
+ orderedActionList,
+ actionType.COMPOUND_SELECTED,
+ getCollectionOfDataset(currentDatasetBuyList),
+ currentActions
+ );
- getCurrentActionList(
- orderedActionList,
- actionType.REPRESENTATION_CHANGED,
- getCollectionOfDatasetOfRepresentation(currentobjectsInView),
- currentActions
- );
+ getCurrentActionList(
+ orderedActionList,
+ actionType.REPRESENTATION_ADDED,
+ getCollectionOfDatasetOfRepresentation(currentobjectsInView),
+ currentActions
+ );
- if (nglViewList) {
- let nglStateList = nglViewList.map(nglView => {
- return { id: nglView.id, orientation: nglView.stage.viewerControls.getOrientation() };
- });
+ getCurrentActionList(
+ orderedActionList,
+ actionType.REPRESENTATION_CHANGED,
+ getCollectionOfDatasetOfRepresentation(currentobjectsInView),
+ currentActions
+ );
- let trackAction = {
- type: actionType.NGL_STATE,
- timestamp: Date.now(),
- nglStateList: nglStateList
- };
+ if (nglViewList) {
+ let nglStateList = nglViewList.map(nglView => {
+ return { id: nglView.id, orientation: nglView.stage.viewerControls.getOrientation() };
+ });
+
+ let trackAction = {
+ type: actionType.NGL_STATE,
+ timestamp: Date.now(),
+ nglStateList: nglStateList
+ };
- currentActions.push(Object.assign({ ...trackAction }));
+ currentActions.push(Object.assign({ ...trackAction }));
+ }
+
+ await dispatch(saveSnapshotAction(snapshot, project, currentActions));
+ await dispatch(saveTrackingActions(currentActions, snapshotID));
+ dispatch(setCurrentActionsList(currentActions));
}
+};
- dispatch(setCurrentActionsList(currentActions));
- dispatch(saveTrackingActions(currentActions, snapshotID));
+const saveSnapshotAction = (snapshot, project, currentActions) => async (dispatch, getState) => {
+ const state = getState();
+ const trackingImageSource = state.trackingReducers.trackingImageSource;
+
+ let sendActions = [];
+ let snapshotAction = {
+ type: actionType.SNAPSHOT,
+ timestamp: Date.now(),
+ object_name: snapshot.title,
+ object_id: snapshot.id,
+ snapshotId: snapshot.id,
+ text: `Snapshot: ${snapshot.id} - ${snapshot.title}`,
+ image: trackingImageSource
+ };
+ sendActions.push(snapshotAction);
+ currentActions.push(snapshotAction);
+ await dispatch(sendTrackingActions(sendActions, project));
};
-export const saveTrackingActions = (currentActions, snapshotID) => (dispatch, getState) => {
+const setSnapshotToActions = (actionList, snapshot, projectID) => (dispatch, getState) => {
+ if (actionList && snapshot) {
+ let actionsWithoutSnapshot = actionList.filter(a => a.snapshotId === null || a.snapshotId === undefined);
+ let updatedActions = actionsWithoutSnapshot.map(obj => ({ ...obj, snapshotId: snapshot.id }));
+ dispatch(setAndUpdateTrackingActions(updatedActions, projectID));
+ }
+};
+
+export const saveTrackingActions = (currentActions, snapshotID) => async (dispatch, getState) => {
const state = getState();
const project = state.projectReducers.currentProject;
const projectID = project && project.projectID;
@@ -578,7 +678,8 @@ export const restoreAfterTargetActions = (stages, projectId) => async (dispatch,
await dispatch(restoreActions(orderedActionList, majorView.stage));
await dispatch(restoreRepresentationActions(orderedActionList, stages));
await dispatch(restoreProject(projectId));
- await dispatch(restoreNglStateAction(orderedActionList, stages));
+ dispatch(restoreSnapshotImageActions(projectId));
+ dispatch(restoreNglStateAction(orderedActionList, stages));
dispatch(setIsActionsRestoring(false, true));
}
};
@@ -825,6 +926,18 @@ const restoreRepresentationActions = (moleculesAction, stages) => (dispatch, get
}
};
+const restoreSnapshotImageActions = projectID => async (dispatch, getState) => {
+ let actionList = await dispatch(getTrackingActions(projectID));
+
+ let snapshotActions = actionList.filter(action => action.type === actionType.SNAPSHOT);
+ if (snapshotActions) {
+ let actions = snapshotActions.map(s => {
+ return { id: s.object_id, image: s.image, title: s.object_name };
+ });
+ dispatch(setSnapshotImageActionList(actions));
+ }
+};
+
const restoreProject = projectId => (dispatch, getState) => {
if (projectId !== undefined) {
return api({ url: `${base_url}/api/session-projects/${projectId}/` }).then(response => {
@@ -1627,7 +1740,7 @@ export const checkSendTrackingActions = (save = false) => (dispatch, getState) =
}
};
-const sendTrackingActions = (sendActions, project, clear = true) => (dispatch, getState) => {
+const sendTrackingActions = (sendActions, project, clear = true) => async (dispatch, getState) => {
if (project) {
const projectID = project && project.projectID;
@@ -1668,11 +1781,11 @@ export const setProjectTrackingActions = () => (dispatch, getState) => {
const state = getState();
const currentProject = state.projectReducers.currentProject;
const projectID = currentProject && currentProject.projectID;
-
- dispatch(getTrackingActions(projectID));
+ dispatch(setProjectActionList([]));
+ dispatch(getTrackingActions(projectID, true));
};
-const getTrackingActions = projectID => (dispatch, getState) => {
+const getTrackingActions = (projectID, withTreeSeparation) => (dispatch, getState) => {
const state = getState();
const sendActions = state.trackingReducers.send_actions_list;
@@ -1686,9 +1799,14 @@ const getTrackingActions = projectID => (dispatch, getState) => {
let listToSet = [];
results.forEach(r => {
let resultActions = JSON.parse(r.actions);
- listToSet.push(...resultActions);
+ let actions = resultActions.map(obj => ({ ...obj, actionId: r.id }));
+ listToSet.push(...actions);
});
+ if (withTreeSeparation === true) {
+ listToSet = dispatch(separateTrackkingActionBySnapshotTree(listToSet));
+ }
+
let projectActions = [...listToSet, ...sendActions];
dispatch(setProjectActionList(projectActions));
return Promise.resolve(projectActions);
@@ -1706,17 +1824,52 @@ const getTrackingActions = projectID => (dispatch, getState) => {
}
};
-const checkActionsProject = projectID => (dispatch, getState) => {
+const separateTrackkingActionBySnapshotTree = actionList => (dispatch, getState) => {
+ const state = getState();
+ const snapshotID = state.projectReducers.currentSnapshot && state.projectReducers.currentSnapshot.id;
+ const currentSnapshotTree = state.projectReducers.currentSnapshotTree;
+ const currentSnapshotList = state.projectReducers.currentSnapshotList;
+
+ if (snapshotID && currentSnapshotTree != null) {
+ let treeActionList = [];
+ let snapshotIdList = [];
+ snapshotIdList.push(currentSnapshotTree.id);
+
+ if (currentSnapshotList != null) {
+ for (const id in currentSnapshotList) {
+ let snapshot = currentSnapshotList[id];
+ let snapshotChildren = snapshot.children;
+
+ if (
+ (snapshotChildren && snapshotChildren !== null && snapshotChildren.includes(snapshotID)) ||
+ snapshot.id === snapshotID
+ ) {
+ snapshotIdList.push(snapshot.id);
+ }
+ }
+ }
+
+ treeActionList = actionList.filter(
+ a => snapshotIdList.includes(a.snapshotId) || a.snapshotId === null || a.snapshotId === undefined
+ );
+ return treeActionList;
+ } else {
+ return actionList;
+ }
+};
+
+const checkActionsProject = projectID => async (dispatch, getState) => {
const state = getState();
const currentProject = state.projectReducers.currentProject;
const currentProjectID = currentProject && currentProject.projectID;
- Promise.resolve(dispatch(getTrackingActions(projectID))).then(() => {
- dispatch(copyActionsToProject(currentProject, true, currentProjectID && currentProjectID != null ? true : false));
- });
+ await dispatch(getTrackingActions(projectID));
+ await dispatch(
+ copyActionsToProject(currentProject, true, currentProjectID && currentProjectID != null ? true : false)
+ );
};
-const copyActionsToProject = (toProject, setActionList = true, clearSendList = true) => (dispatch, getState) => {
+const copyActionsToProject = (toProject, setActionList = true, clearSendList = true) => async (dispatch, getState) => {
const state = getState();
const actionList = state.trackingReducers.project_actions_list;
@@ -1730,20 +1883,19 @@ const copyActionsToProject = (toProject, setActionList = true, clearSendList = t
if (setActionList === true) {
dispatch(setActionsList(newActionsList));
}
- dispatch(sendTrackingActions(newActionsList, toProject, clearSendList));
+ await dispatch(sendTrackingActions(newActionsList, toProject, clearSendList));
}
};
-export const sendTrackingActionsByProjectId = (projectID, authorID) => (dispatch, getState) => {
+export const sendTrackingActionsByProjectId = (projectID, authorID) => async (dispatch, getState) => {
const state = getState();
const currentProject = state.projectReducers.currentProject;
const currentProjectID = currentProject && currentProject.projectID;
const project = { projectID, authorID };
- Promise.resolve(dispatch(getTrackingActions(currentProjectID))).then(() => {
- dispatch(copyActionsToProject(project, false, currentProjectID && currentProjectID != null ? true : false));
- });
+ await dispatch(getTrackingActions(currentProjectID));
+ await dispatch(copyActionsToProject(project, false, currentProjectID && currentProjectID != null ? true : false));
};
export const sendInitTrackingActionByProjectId = target_on => (dispatch, getState) => {
@@ -1759,3 +1911,79 @@ export const sendInitTrackingActionByProjectId = target_on => (dispatch, getStat
dispatch(saveTrackingActions(actions, snapshotID));
}
};
+
+export const updateTrackingActions = action => (dispatch, getState) => {
+ const state = getState();
+ const project = state.projectReducers.currentProject;
+ const projectActions = state.trackingReducers.project_actions_list;
+ const projectID = project && project.projectID;
+ let actionID = action && action.actionId;
+
+ if (projectID && actionID && projectActions) {
+ let actions = projectActions.filter(a => a.actionId === actionID);
+
+ if (actions && actions.length > 0) {
+ const dataToSend = {
+ session_action_id: actionID,
+ session_project: projectID,
+ author: project.authorID,
+ last_update_date: moment().format(),
+ actions: JSON.stringify(actions)
+ };
+ return api({
+ url: `${base_url}/api/session-actions/${actionID}`,
+ method: METHOD.PUT,
+ data: JSON.stringify(dataToSend)
+ })
+ .then(() => {})
+ .catch(error => {
+ throw new Error(error);
+ })
+ .finally(() => {});
+ } else {
+ return Promise.resolve();
+ }
+ } else {
+ return Promise.resolve();
+ }
+};
+
+function groupArrayOfObjects(list, key) {
+ return list.reduce(function(rv, x) {
+ (rv[x[key]] = rv[x[key]] || []).push(x);
+ return rv;
+ }, {});
+}
+
+export const setAndUpdateTrackingActions = (actionList, projectID) => (dispatch, getState) => {
+ if (projectID) {
+ const groupBy = groupArrayOfObjects(actionList, 'actionId');
+
+ for (const group in groupBy) {
+ let actionID = group;
+ let actions = groupBy[group];
+ if (actionID && actions && actions.length > 0) {
+ const dataToSend = {
+ session_action_id: actionID,
+ session_project: projectID,
+ last_update_date: moment().format(),
+ actions: JSON.stringify(actions)
+ };
+ return api({
+ url: `${base_url}/api/session-actions/${actionID}`,
+ method: METHOD.PUT,
+ data: JSON.stringify(dataToSend)
+ })
+ .then(() => {})
+ .catch(error => {
+ throw new Error(error);
+ })
+ .finally(() => {});
+ } else {
+ return Promise.resolve();
+ }
+ }
+ } else {
+ return Promise.resolve();
+ }
+};
diff --git a/js/reducers/tracking/trackingActions.js b/js/reducers/tracking/trackingActions.js
index 963671514..88eede735 100644
--- a/js/reducers/tracking/trackingActions.js
+++ b/js/reducers/tracking/trackingActions.js
@@ -1,4 +1,4 @@
-import { actionType, actionObjectType, actionDescription } from './constants';
+import { actionType, actionObjectType, actionDescription, actionAnnotation } from './constants';
import { constants as apiConstants } from '../api/constants';
import { CONSTANTS as nglConstants } from '../ngl/constants';
import { constants as selectionConstants } from '../selection/constants';
@@ -17,6 +17,7 @@ export const findTrackAction = (action, state) => {
let targetName = getTargetName(action.target_on, state);
trackAction = {
type: actionType.TARGET_LOADED,
+ annotation: actionAnnotation.CHECK,
timestamp: Date.now(),
username: username,
object_type: actionObjectType.TARGET,
@@ -33,6 +34,7 @@ export const findTrackAction = (action, state) => {
let molGroupName = getMolGroupName(action.mol_group_on, state);
trackAction = {
type: actionType.SITE_TURNED_ON,
+ annotation: actionAnnotation.CHECK,
timestamp: Date.now(),
username: username,
object_type: actionObjectType.SITE,
@@ -48,6 +50,7 @@ export const findTrackAction = (action, state) => {
let molGroupName = getMolGroupName(objectId, state);
trackAction = {
type: actionType.SITE_TURNED_OFF,
+ annotation: actionAnnotation.CHECK,
timestamp: Date.now(),
username: username,
object_type: actionObjectType.SITE,
@@ -63,6 +66,7 @@ export const findTrackAction = (action, state) => {
trackAction = {
type: actionType.ALL_HIDE,
+ annotation: actionAnnotation.CLEAR,
timestamp: Date.now(),
username: username,
object_type: objectType,
@@ -77,6 +81,7 @@ export const findTrackAction = (action, state) => {
trackAction = {
type: actionType.ALL_TURNED_ON,
+ annotation: actionAnnotation.CHECK,
timestamp: Date.now(),
username: username,
object_type: objectType,
@@ -99,6 +104,7 @@ export const findTrackAction = (action, state) => {
trackAction = {
type: actionType.ALL_TURNED_OFF,
+ annotation: actionAnnotation.CLEAR,
timestamp: Date.now(),
username: username,
object_type: objectType,
@@ -122,6 +128,7 @@ export const findTrackAction = (action, state) => {
trackAction = {
type: actionType.ALL_TURNED_ON_BY_TYPE,
+ annotation: actionAnnotation.CHECK,
timestamp: Date.now(),
username: username,
object_type: objectType,
@@ -138,6 +145,7 @@ export const findTrackAction = (action, state) => {
trackAction = {
type: actionType.ALL_TURNED_OFF_BY_TYPE,
+ annotation: actionAnnotation.CLEAR,
timestamp: Date.now(),
username: username,
object_type: objectType,
@@ -153,6 +161,7 @@ export const findTrackAction = (action, state) => {
trackAction = {
type: actionType.LIGAND_TURNED_ON,
+ annotation: actionAnnotation.CHECK,
timestamp: Date.now(),
username: username,
object_type: objectType,
@@ -171,6 +180,7 @@ export const findTrackAction = (action, state) => {
trackAction = {
type: actionType.LIGAND_TURNED_OFF,
+ annotation: actionAnnotation.CLEAR,
timestamp: Date.now(),
username: username,
object_type: objectType,
@@ -189,6 +199,7 @@ export const findTrackAction = (action, state) => {
trackAction = {
type: actionType.SIDECHAINS_TURNED_ON,
+ annotation: actionAnnotation.CHECK,
timestamp: Date.now(),
username: username,
object_type: objectType,
@@ -207,6 +218,7 @@ export const findTrackAction = (action, state) => {
trackAction = {
type: actionType.SIDECHAINS_TURNED_OFF,
+ annotation: actionAnnotation.CLEAR,
timestamp: Date.now(),
username: username,
object_type: objectType,
@@ -225,6 +237,7 @@ export const findTrackAction = (action, state) => {
trackAction = {
type: actionType.INTERACTIONS_TURNED_ON,
+ annotation: actionAnnotation.CHECK,
timestamp: Date.now(),
username: username,
object_type: objectType,
@@ -243,6 +256,7 @@ export const findTrackAction = (action, state) => {
trackAction = {
type: actionType.INTERACTIONS_TURNED_OFF,
+ annotation: actionAnnotation.CLEAR,
timestamp: Date.now(),
username: username,
object_type: objectType,
@@ -261,6 +275,7 @@ export const findTrackAction = (action, state) => {
trackAction = {
type: actionType.SURFACE_TURNED_ON,
+ annotation: actionAnnotation.CHECK,
timestamp: Date.now(),
username: username,
object_type: objectType,
@@ -279,6 +294,7 @@ export const findTrackAction = (action, state) => {
trackAction = {
type: actionType.SURFACE_TURNED_OFF,
+ annotation: actionAnnotation.CLEAR,
timestamp: Date.now(),
username: username,
object_type: objectType,
@@ -297,6 +313,7 @@ export const findTrackAction = (action, state) => {
trackAction = {
type: actionType.VECTORS_TURNED_ON,
+ annotation: actionAnnotation.CHECK,
timestamp: Date.now(),
username: username,
object_type: objectType,
@@ -315,6 +332,7 @@ export const findTrackAction = (action, state) => {
trackAction = {
type: actionType.VECTORS_TURNED_OFF,
+ annotation: actionAnnotation.CLEAR,
timestamp: Date.now(),
username: username,
object_type: objectType,
@@ -333,6 +351,7 @@ export const findTrackAction = (action, state) => {
trackAction = {
type: actionType.MOLECULE_ADDED_TO_SHOPPING_CART,
+ annotation: actionAnnotation.CHECK,
timestamp: Date.now(),
username: username,
object_type: actionObjectType.MOLECULE,
@@ -349,6 +368,7 @@ export const findTrackAction = (action, state) => {
trackAction = {
type: actionType.MOLECULE_REMOVED_FROM_SHOPPING_CART,
+ annotation: actionAnnotation.CLEAR,
timestamp: Date.now(),
username: username,
object_type: objectType,
@@ -365,6 +385,7 @@ export const findTrackAction = (action, state) => {
trackAction = {
type: actionType.VECTOR_SELECTED,
+ annotation: actionAnnotation.CHECK,
timestamp: Date.now(),
username: username,
object_type: objectType,
@@ -380,6 +401,7 @@ export const findTrackAction = (action, state) => {
trackAction = {
type: actionType.COMPOUND_SELECTED,
+ annotation: actionAnnotation.CHECK,
timestamp: Date.now(),
username: username,
object_type: objectType,
@@ -396,6 +418,7 @@ export const findTrackAction = (action, state) => {
trackAction = {
type: actionType.COMPOUND_DESELECTED,
+ annotation: actionAnnotation.CLEAR,
timestamp: Date.now(),
username: username,
object_type: objectType,
@@ -413,6 +436,7 @@ export const findTrackAction = (action, state) => {
trackAction = {
type: actionType.ALL_TURNED_ON,
+ annotation: actionAnnotation.CHECK,
timestamp: Date.now(),
username: username,
object_type: objectType,
@@ -434,6 +458,7 @@ export const findTrackAction = (action, state) => {
trackAction = {
type: actionType.ALL_TURNED_OFF,
+ annotation: actionAnnotation.CLEAR,
timestamp: Date.now(),
username: username,
object_type: objectType,
@@ -457,6 +482,7 @@ export const findTrackAction = (action, state) => {
trackAction = {
type: actionType.ALL_TURNED_ON_BY_TYPE,
+ annotation: actionAnnotation.CHECK,
timestamp: Date.now(),
username: username,
object_type: objectType,
@@ -475,6 +501,7 @@ export const findTrackAction = (action, state) => {
trackAction = {
type: actionType.ALL_TURNED_OFF_BY_TYPE,
+ annotation: actionAnnotation.CLEAR,
timestamp: Date.now(),
username: username,
object_type: objectType,
@@ -491,6 +518,7 @@ export const findTrackAction = (action, state) => {
trackAction = {
type: actionType.LIGAND_TURNED_ON,
+ annotation: actionAnnotation.CHECK,
timestamp: Date.now(),
username: username,
object_type: objectType,
@@ -508,6 +536,7 @@ export const findTrackAction = (action, state) => {
trackAction = {
type: actionType.LIGAND_TURNED_OFF,
+ annotation: actionAnnotation.CLEAR,
timestamp: Date.now(),
username: username,
object_type: objectType,
@@ -525,6 +554,7 @@ export const findTrackAction = (action, state) => {
trackAction = {
type: actionType.SIDECHAINS_TURNED_ON,
+ annotation: actionAnnotation.CHECK,
timestamp: Date.now(),
username: username,
object_type: objectType,
@@ -542,6 +572,7 @@ export const findTrackAction = (action, state) => {
trackAction = {
type: actionType.SIDECHAINS_TURNED_OFF,
+ annotation: actionAnnotation.CLEAR,
timestamp: Date.now(),
username: username,
object_type: objectType,
@@ -559,6 +590,7 @@ export const findTrackAction = (action, state) => {
trackAction = {
type: actionType.INTERACTIONS_TURNED_ON,
+ annotation: actionAnnotation.CHECK,
timestamp: Date.now(),
username: username,
object_type: objectType,
@@ -576,6 +608,7 @@ export const findTrackAction = (action, state) => {
trackAction = {
type: actionType.INTERACTIONS_TURNED_OFF,
+ annotation: actionAnnotation.CLEAR,
timestamp: Date.now(),
username: username,
object_type: objectType,
@@ -593,6 +626,7 @@ export const findTrackAction = (action, state) => {
trackAction = {
type: actionType.SURFACE_TURNED_ON,
+ annotation: actionAnnotation.CHECK,
timestamp: Date.now(),
username: username,
object_type: objectType,
@@ -610,6 +644,7 @@ export const findTrackAction = (action, state) => {
trackAction = {
type: actionType.SURFACE_TURNED_OFF,
+ annotation: actionAnnotation.CLEAR,
timestamp: Date.now(),
username: username,
object_type: objectType,
@@ -624,6 +659,7 @@ export const findTrackAction = (action, state) => {
trackAction = {
type: actionType.REPRESENTATION_CHANGED,
+ annotation: actionAnnotation.CHECK,
timestamp: Date.now(),
username: username,
object_type: actionObjectType.REPRESENTATION,
@@ -640,6 +676,7 @@ export const findTrackAction = (action, state) => {
trackAction = {
type: actionType.REPRESENTATION_ADDED,
+ annotation: actionAnnotation.CHECK,
timestamp: Date.now(),
username: username,
object_type: actionObjectType.REPRESENTATION,
@@ -654,6 +691,7 @@ export const findTrackAction = (action, state) => {
trackAction = {
type: actionType.REPRESENTATION_REMOVED,
+ annotation: actionAnnotation.CLEAR,
timestamp: Date.now(),
username: username,
object_type: objectType,
diff --git a/js/reducers/tracking/trackingReducers.js b/js/reducers/tracking/trackingReducers.js
index bf8f5c569..1724a8e91 100644
--- a/js/reducers/tracking/trackingReducers.js
+++ b/js/reducers/tracking/trackingReducers.js
@@ -13,8 +13,10 @@ export const INITIAL_STATE = {
isActionSaving: false,
send_actions_list: [],
project_actions_list: [],
+ snapshotActionImageList: [],
isActionRestoring: false,
- isActionRestored: false
+ isActionRestored: false,
+ trackingImageSource: ''
};
export function trackingReducers(state = INITIAL_STATE, action = {}) {
@@ -79,6 +81,11 @@ export function trackingReducers(state = INITIAL_STATE, action = {}) {
project_actions_list: action.project_actions_list
});
+ case constants.SET_SNAPSOT_IMAGE_ACTIONS_LIST:
+ return Object.assign({}, state, {
+ snapshotActionImageList: action.snapshotActionImageList
+ });
+
case constants.SET_IS_ACTIONS_SAVING:
return Object.assign({}, state, {
isActionSaving: action.isActionSaving
@@ -90,6 +97,11 @@ export function trackingReducers(state = INITIAL_STATE, action = {}) {
isActionRestored: action.isActionRestored
});
+ case constants.SET_TRACKING_IMAGE_SOURCE:
+ return Object.assign({}, state, {
+ trackingImageSource: action.payload
+ });
+
case constants.RESET_TRACKING_STATE:
return INITIAL_STATE;
diff --git a/package.json b/package.json
index 71c338464..241561634 100755
--- a/package.json
+++ b/package.json
@@ -50,6 +50,7 @@
"formik": "^2.1.4",
"formik-material-ui": "^2.0.0-beta.1",
"formik-material-ui-pickers": "^0.0.8",
+ "html2canvas": "^1.0.0-rc.7",
"js-base64": "^2.5.2",
"jszip": "^3.2.2",
"lodash": "^4.17.15",
@@ -61,6 +62,7 @@
"react-color": "^2.17.3",
"react-dom": "^16.12.0",
"react-event-timeline": "^1.6.3",
+ "react-grid-gallery": "^0.5.5",
"react-hot-loader": "^4.12.18",
"react-infinite-scroller": "^1.2.4",
"react-redux": "^7.1.3",