diff --git a/docker-compose.dev.vector.yml b/docker-compose.dev.vector.yml index 9e7f7c8c2..f776976b7 100644 --- a/docker-compose.dev.vector.yml +++ b/docker-compose.dev.vector.yml @@ -91,14 +91,11 @@ services: OIDC_RP_CLIENT_SECRET: ${OIDC_RP_CLIENT_SECRET} OIDC_RP_CLIENT_ID: 'fragalysis-local' OIDC_RENEW_ID_TOKEN_EXPIRY_MINUTES: 210 - ISPYB_HOST: ispybdbproxy.diamond.ac.uk + # ISPYB_HOST: ispybdbproxy.diamond.ac.uk ISPYB_PORT: 4306 ISPYB_USER: ${ISPYB_USER} ISPYB_PASSWORD: ${ISPYB_PASSWORD} SECURITY_CONNECTOR: ssh_ispyb - SSH_HOST: ssh.diamond.ac.uk - SSH_USER: ${SSH_USER} - SSH_PASSWORD: ${SSH_PASSWORD} LOGGING_FRAMEWORK_ROOT_LEVEL: DEBUG AUTHENTICATE_UPLOAD: 'False' CELERY_TASK_ALWAYS_EAGER: 'True' diff --git a/js/components/datasets/redux/actions.js b/js/components/datasets/redux/actions.js index 0b7a79f33..fea6b7ff3 100644 --- a/js/components/datasets/redux/actions.js +++ b/js/components/datasets/redux/actions.js @@ -655,3 +655,10 @@ export const updateInToBeDisplayedListForDataset = (datasetID, item) => { datasetID: datasetID }; }; + +export const setToBeDisplayedLists = toBeDisplayedLists => { + return { + type: constants.SET_TO_BE_DISPLAYED_LISTS, + toBeDisplayedLists: toBeDisplayedLists + }; +}; diff --git a/js/components/datasets/redux/constants.js b/js/components/datasets/redux/constants.js index b355e07be..8a740d779 100644 --- a/js/components/datasets/redux/constants.js +++ b/js/components/datasets/redux/constants.js @@ -127,7 +127,8 @@ export const constants = { SET_TO_BE_DISPLAYED_LIST_DATASET: prefix + 'SET_TO_BE_DISPLAYED_LIST_DATASET', APPEND_TO_BE_DISPLAYED_LIST_DATASET: prefix + 'APPEND_TO_BE_DISPLAYED_LIST_DATASET', REMOVE_FROM_TO_BE_DISPLAYED_LIST_DATASET: prefix + 'REMOVE_FROM_TO_BE_DISPLAYED_LIST_DATASET', - UPDATE_IN_TO_BE_DISPLAYED_LIST_DATASET: prefix + 'UPDATE_IN_TO_BE_DISPLAYED_LIST_DATASET' + UPDATE_IN_TO_BE_DISPLAYED_LIST_DATASET: prefix + 'UPDATE_IN_TO_BE_DISPLAYED_LIST_DATASET', + SET_TO_BE_DISPLAYED_LISTS: prefix + 'SET_TO_BE_DISPLAYED_LISTS' }; export const COUNT_OF_VISIBLE_SCORES = 7; diff --git a/js/components/datasets/redux/reducer.js b/js/components/datasets/redux/reducer.js index b14225986..4a493e499 100644 --- a/js/components/datasets/redux/reducer.js +++ b/js/components/datasets/redux/reducer.js @@ -132,7 +132,9 @@ const setList = (state, listsName, datasetId, list) => { const appendToList = (state, listsName, datasetId, itemId) => { const newState = Object.assign({}, state); - newState[listsName][datasetId] = [...new Set([...newState[listsName][datasetId], itemId])]; + newState[listsName][datasetId] + ? (newState[listsName][datasetId] = [...new Set([...newState[listsName][datasetId], itemId])]) + : (newState[listsName][datasetId] = [itemId]); return newState; }; @@ -204,6 +206,8 @@ const removeDatasetFromState = (state, datasetId) => { export const datasetsReducers = (state = INITIAL_STATE, action = {}) => { switch (action.type) { + case constants.SET_TO_BE_DISPLAYED_LISTS: + return { ...state, toBeDisplayedList: action.toBeDisplayedLists }; case constants.SET_TO_BE_DISPLAYED_LIST_DATASET: { return setList(state, 'toBeDisplayedList', action.datasetID, action.list); } diff --git a/js/components/preview/projectHistoryPanel/ProjectHistory.js b/js/components/preview/projectHistoryPanel/ProjectHistory.js index 14fdd6013..e76f194f0 100644 --- a/js/components/preview/projectHistoryPanel/ProjectHistory.js +++ b/js/components/preview/projectHistoryPanel/ProjectHistory.js @@ -118,9 +118,9 @@ export const ProjectHistory = memo(({ showFullHistory, graphKey, expanded, onExp dispatch(setSelectedSnapshotToSwitch(transitionToSnapshot.hash)); dispatch(setIsOpenModalBeforeExit(true)); setTryToOpen(false); - dispatch(changeSnapshot(sessionProjectID, transitionToSnapshot.hash)); + dispatch(changeSnapshot(sessionProjectID, transitionToSnapshot.hash, stage)); } else if (!isSnapshotDirty && tryToOpen && transitionToSnapshot) { - dispatch(changeSnapshot(sessionProjectID, transitionToSnapshot.hash)); + dispatch(changeSnapshot(sessionProjectID, transitionToSnapshot.hash, stage)); setTryToOpen(false); } }, [dispatch, isSnapshotDirty, nglViewList, sessionProjectID, stage, transitionToSnapshot, tryToOpen]); diff --git a/js/components/snapshot/redux/dispatchActions.js b/js/components/snapshot/redux/dispatchActions.js index b98232200..5f5fcb509 100644 --- a/js/components/snapshot/redux/dispatchActions.js +++ b/js/components/snapshot/redux/dispatchActions.js @@ -4,7 +4,11 @@ import { setSessionTitle, setSnapshotLoadingInProgress } from '../../../reducers/api/actions'; -import { reloadSelectionReducer } from '../../../reducers/selection/actions'; +import { + reloadSelectionReducer, + setToBeDisplayedList, + updateInToBeDisplayedList +} from '../../../reducers/selection/actions'; import { api, METHOD } from '../../../utils/api'; import { setDisableRedirect, @@ -36,16 +40,29 @@ import { setForceProjectCreated } from '../../projects/redux/actions'; import { selectFirstMolGroup } from '../../preview/moleculeGroups/redux/dispatchActions'; -import { reloadDatasetsReducer } from '../../datasets/redux/actions'; +import { + reloadDatasetsReducer, + setToBeDisplayedListForDataset, + setToBeDisplayedLists, + updateInToBeDisplayedListForDataset +} from '../../datasets/redux/actions'; import { captureScreenOfSnapshot } from '../../userFeedback/browserApi'; import { setCurrentProject } from '../../projects/redux/actions'; import { createProjectPost } from '../../../utils/discourse'; -import { deepClone, deepMergeWithPriority, deepMergeWithPriorityAndWhiteList } from '../../../utils/objectUtils'; import { + deepClone, + deepMergeWithPriority, + deepMergeWithPriorityAndBlackList, + deepMergeWithPriorityAndWhiteList +} from '../../../utils/objectUtils'; +import { + SNAPSHOT_VALUES_NOT_TO_BE_DELETED_SWITCHING_TARGETS, SNAPSHOT_VALUES_TO_BE_DELETED, SNAPSHOT_VALUES_TO_BE_DELETED_SWITCHING_SNAPSHOTS } from './utilitySnapshotShapes'; import { setEntireState } from '../../../reducers/actions'; +import { VIEWS } from '../../../constants/constants'; +// import { display } from 'html2canvas/dist/types/css/property-descriptors/display'; export const getListOfSnapshots = () => (dispatch, getState) => { const userID = DJANGO_CONTEXT['pk'] || null; @@ -595,14 +612,23 @@ export const getCleanStateForSnapshot = () => (dispatch, getState) => { //this is inefficient and it might cause problems with huge targets so //having a custom deepClone function that only clones the necessary data would be better //for now I'm skipping this to implement complete end to end functionality and then I'll optimize - let snapshotData = deepClone(state); + // let snapshotData = deepClone(state); + // snapshotData = deepMergeWithPriority({ ...snapshotData }, SNAPSHOT_VALUES_TO_BE_DELETED); + // snapshotData.nglReducers.snapshotNglOrientation = { ...snapshotData.nglReducers.nglOrientations }; + + let snapshotData = {}; + + snapshotData = deepMergeWithPriorityAndBlackList({}, state, SNAPSHOT_VALUES_NOT_TO_BE_DELETED_SWITCHING_TARGETS); + snapshotData = deepClone(snapshotData); + snapshotData = deepMergeWithPriority({ ...snapshotData }, SNAPSHOT_VALUES_NOT_TO_BE_DELETED_SWITCHING_TARGETS); + // snapshotData = deepClone(snapshotData); snapshotData = deepMergeWithPriority({ ...snapshotData }, SNAPSHOT_VALUES_TO_BE_DELETED); snapshotData.nglReducers.snapshotNglOrientation = { ...snapshotData.nglReducers.nglOrientations }; return snapshotData; }; -export const changeSnapshot = (projectID, snapshotID) => async (dispatch, getState) => { +export const changeSnapshot = (projectID, snapshotID, stage) => async (dispatch, getState) => { dispatch(setSnapshotLoadingInProgress(true)); dispatch(setIsSnapshot(true)); // A hacky way of changing the URL without triggering react-router @@ -627,12 +653,60 @@ export const changeSnapshot = (projectID, snapshotID) => async (dispatch, getSta }) ); - const currentState = getState(); - const newState = deepMergeWithPriorityAndWhiteList( + //orientation animation + const newOrientation = snapshotState.nglReducers.nglOrientations[VIEWS.MAJOR_VIEW]; + await stage.animationControls.orient(newOrientation.elements, 2000); //.then(() => { + let currentState = getState(); + const toBeDisplayedLHSCurrent = currentState.selectionReducers.toBeDisplayedList; + const toBeDisplayedRHSCurrent = currentState.datasetsReducers.toBeDisplayedList; + const toBeDisplayedLHSNew = snapshotState.selectionReducers.toBeDisplayedList; + const toBeDisplayedRHSNew = snapshotState.datasetsReducers.toBeDisplayedList; + + //remove LHS stuff that is not in the new snapshot + const toBeNoLongerDisplayedLHS = toBeDisplayedLHSCurrent.filter( + currentStruct => + !toBeDisplayedLHSNew.find(newStruct => newStruct.id === currentStruct.id && newStruct.type === currentStruct.type) + ); + toBeNoLongerDisplayedLHS.forEach(notToBeDisplayed => + toBeDisplayedLHSNew.push({ ...notToBeDisplayed, display: false }) + ); + + //remove RHS stuff that is not in the new snapshot + const toBeNoLongerDisplayedRHS = []; + Object.keys(toBeDisplayedRHSCurrent).forEach(datasetID => { + const currentDataset = toBeDisplayedRHSCurrent[datasetID]; + const newDataset = toBeDisplayedRHSNew[datasetID]; + if (newDataset) { + const toBeNoLongerDisplayed = currentDataset.filter( + currentStruct => + !newDataset.find(newStruct => newStruct.id === currentStruct.id && newStruct.type === currentStruct.type) + ); + toBeNoLongerDisplayedRHS.push(...toBeNoLongerDisplayed); + } + }); + toBeNoLongerDisplayedRHS.forEach(notToBeDisplayed => + toBeDisplayedRHSNew[notToBeDisplayed.datasetID] + ? toBeDisplayedRHSNew[notToBeDisplayed.datasetID].push({ ...notToBeDisplayed, display: false }) + : (toBeDisplayedRHSNew[notToBeDisplayed.datasetID] = [{ ...notToBeDisplayed, display: false }]) + ); + + const toBeDisplayedLHSNewDeepCopy = deepClone(toBeDisplayedLHSNew); + const toBeDisplayedRHSNewDeepCopy = deepClone(toBeDisplayedRHSNew) || {}; + + currentState = getState(); + // const copyOfCurrentState = deepClone(currentState); + const newState = deepMergeWithPriorityAndBlackList( + // copyOfCurrentState, currentState, snapshotState, - SNAPSHOT_VALUES_TO_BE_DELETED_SWITCHING_SNAPSHOTS + SNAPSHOT_VALUES_NOT_TO_BE_DELETED_SWITCHING_TARGETS ); + dispatch(setToBeDisplayedList(toBeDisplayedLHSNewDeepCopy)); + dispatch(setToBeDisplayedLists(toBeDisplayedRHSNewDeepCopy)); + // }); + // await new Promise(r => setTimeout(r, 2000)); + // dispatch(setEntireState(newState)); + // console.log('msg'); }; diff --git a/js/components/snapshot/redux/utilitySnapshotShapes.js b/js/components/snapshot/redux/utilitySnapshotShapes.js index 1731a4752..ad04aac03 100644 --- a/js/components/snapshot/redux/utilitySnapshotShapes.js +++ b/js/components/snapshot/redux/utilitySnapshotShapes.js @@ -1,3 +1,6 @@ +import { setCurrentSnapshotTree } from '../../projects/redux/actions'; +import { snapshotReducers } from './reducer'; + export const SNAPSHOT_VALUES_TO_BE_DELETED = { apiReducers: { // target_id_list: [], @@ -12,7 +15,7 @@ export const SNAPSHOT_VALUES_TO_BE_DELETED = { rhsDataIsLoading: true, rhsDataIsLoaded: false, proteinIsLoading: false, - proteinsIsLoaded: false + proteinIsLoaded: false }, nglReducers: { objectsInView: {}, @@ -33,6 +36,9 @@ export const SNAPSHOT_VALUES_TO_BE_DELETED = { vectorOnList: [], isScrollFiredForLHS: false }, + snapshotReducers: { + openSavingDialog: false + }, previewReducers: { molecule: { imageCache: {} @@ -55,43 +61,67 @@ export const SNAPSHOT_VALUES_TO_BE_DELETED = { } }; -export const SNAPSHOT_VALUES_TO_BE_DELETED_SWITCHING_SNAPSHOTS = { +// export const SNAPSHOT_VALUES_TO_BE_DELETED_SWITCHING_SNAPSHOTS = { +// apiReducers: { +// // target_id_list: [], +// }, +// nglReducers: { +// objectsInView: {}, +// pdbCache: {}, +// qualityCache: {}, +// nglViewFromSnapshotRendered: false, +// snapshotOrientationApplied: false +// }, +// selectionReducers: { +// fragmentDisplayList: [], +// proteinList: [], +// complexList: [], +// surfaceList: [], +// densityList: [], +// densityListCustom: [], +// densityListType: [], +// qualityList: [], +// vectorOnList: [], +// isScrollFiredForLHS: false +// }, +// previewReducers: { +// molecule: { +// imageCache: {} +// } +// }, +// datasetsReducers: { +// ligandLists: {}, +// proteinLists: {}, +// complexLists: {}, +// surfaceLists: {}, +// datasetScrolledMap: {}, +// isSelectedDatasetScrolled: false +// }, +// projectReducers: { +// isProjectModalLoading: false +// } +// }; + +export const SNAPSHOT_VALUES_NOT_TO_BE_DELETED_SWITCHING_TARGETS = { apiReducers: { - // target_id_list: [], - }, - nglReducers: { - objectsInView: {}, - pdbCache: {}, - qualityCache: {}, - nglViewFromSnapshotRendered: false, - snapshotOrientationApplied: false - }, - selectionReducers: { - fragmentDisplayList: [], - proteinList: [], - complexList: [], - surfaceList: [], - densityList: [], - densityListCustom: [], - densityListType: [], - qualityList: [], - vectorOnList: [], - isScrollFiredForLHS: false - }, - previewReducers: { - molecule: { - imageCache: {} - } + target_id_list: [], + legacy_target_id_list: [], + all_mol_lists: [], + moleculeTags: [], + tagList: [], + categoryList: [], + lhs_compounds_list: [] }, datasetsReducers: { - ligandLists: {}, - proteinLists: {}, - complexLists: {}, - surfaceLists: {}, - datasetScrolledMap: {}, - isSelectedDatasetScrolled: false + datasets: [], + moleculeLists: {}, + scoreDatasetMap: {}, + allInspirations: {} }, projectReducers: { - isProjectModalLoading: false + currentSnapshot: {}, + currentSnapshotList: [], + currentSnapshotTree: {}, + currentProject: {} } }; diff --git a/js/utils/objectUtils.js b/js/utils/objectUtils.js index 92cd588a2..2ca7b5043 100644 --- a/js/utils/objectUtils.js +++ b/js/utils/objectUtils.js @@ -52,31 +52,85 @@ export const deepClone = obj => { return JSON.parse(JSON.stringify(obj)); }; -export const deepMergeWithPriorityAndWhiteList = (a, b, whiteList) => { - const isPathPresentInTheWhiteList = (path, whiteList) => { - console.log(`isPathPresentInTheWhiteList - path: ${JSON.stringify(path)}`); - const result = !!path.reduce((obj, key) => obj[key], whiteList); - console.log(`isPathPresentInTheWhiteList - result: ${result}`); - return result; +// export const deepMergeWithPriorityAndWhiteList = (a, b, whiteList) => { +// const isPathPresentInTheWhiteList = (path, whiteList) => { +// console.log(`isPathPresentInTheWhiteList - path: ${JSON.stringify(path)}`); +// const result = !!path.reduce((obj, key) => obj[key], whiteList); +// console.log(`isPathPresentInTheWhiteList - result: ${result}`); +// return result; +// }; +// const merge = (a, b, path) => { +// const keys = Object.keys(b); + +// keys.forEach(key => { +// const currentPath = [...path, key]; +// if (isPathPresentInTheWhiteList(currentPath, whiteList)) { +// if (a[key] && typeof a[key] === 'object' && b[key] && typeof b[key] === 'object') { +// if (Array.isArray(a[key]) && Array.isArray(b[key]) && isPathPresentInTheWhiteList(currentPath, whiteList)) { +// a[key] = [...b[key]]; +// } else { +// if (Object.keys(b[key]).length === 0 && isPathPresentInTheWhiteList(currentPath, whiteList)) { +// a[key] = b[key]; +// } else { +// a[key] = merge(a[key], b[key], currentPath); +// } +// } +// } else { +// if (isPathPresentInTheWhiteList(currentPath, whiteList)) { +// a[key] = b[key]; +// } +// } +// } +// }); + +// // currentPath.pop(); +// return a; +// }; + +// return merge({ ...a }, b, []); +// }; + +export const deepMergeWithPriorityAndBlackList = (a, b, blackList) => { + const isWholePathPresentIntoBlackList = (path, blackList) => { + let partOfBlackList = blackList; + for (let i = 0; i < path.length; i++) { + const pathToCheck = path[i]; + if (partOfBlackList[pathToCheck]) { + partOfBlackList = partOfBlackList[pathToCheck]; + if (i === path.length - 1 && Object.keys(partOfBlackList).length > 0) { + // console.log(`isWholePathPresentIntoBlackList - path: ${JSON.stringify(path)} - false - not entire path`); + return false; + } + } else { + // console.log(`isWholePathPresentIntoBlackList - path: ${JSON.stringify(path)} - false`); + return false; + } + } + // console.log(`isWholePathPresentIntoBlackList - path: ${JSON.stringify(path)} - true`); + return true; }; const merge = (a, b, path) => { const keys = Object.keys(b); keys.forEach(key => { const currentPath = [...path, key]; - if (isPathPresentInTheWhiteList(currentPath, whiteList)) { + if (!isWholePathPresentIntoBlackList(currentPath, blackList)) { if (a[key] && typeof a[key] === 'object' && b[key] && typeof b[key] === 'object') { - if (Array.isArray(a[key]) && Array.isArray(b[key]) && isPathPresentInTheWhiteList(currentPath, whiteList)) { + if ( + Array.isArray(a[key]) && + Array.isArray(b[key]) && + !isWholePathPresentIntoBlackList(currentPath, blackList) + ) { a[key] = [...b[key]]; } else { - if (Object.keys(b[key]).length === 0 && isPathPresentInTheWhiteList(currentPath, whiteList)) { + if (Object.keys(b[key]).length === 0 && !isWholePathPresentIntoBlackList(currentPath, blackList)) { a[key] = b[key]; } else { a[key] = merge(a[key], b[key], currentPath); } } } else { - if (isPathPresentInTheWhiteList(currentPath, whiteList)) { + if (!isWholePathPresentIntoBlackList(currentPath, blackList)) { a[key] = b[key]; } }