{
{cancelButton}
+ {resubmitButton}
{accessLvl === 'admin' && resetButton}
{accessLvl === 'admin' && switchElement}
@@ -124,7 +172,9 @@ const mapDispatchToProps = dispatch => {
toggleAvailable: (instrId, token) => dispatch(toggleAvailableOnDash(instrId, token)),
deleteHoldersHandler: (token, instrId, holders) =>
dispatch(deleteExperiments(token, instrId, holders)),
- resetInstr: (token, instrId) => dispatch(resetQueue(token, instrId))
+ resetInstr: (token, instrId) => dispatch(resetQueue(token, instrId)),
+ resetChecked: () => dispatch(resetCheckedHolders()),
+ resubmitHandler: (token, data) => dispatch(resubmitHolders(token, data))
}
}
diff --git a/nomad-front-end/src/containers/Dashboard/Dashboard.jsx b/nomad-front-end/src/containers/Dashboard/Dashboard.jsx
index 81985c9..6ece7f2 100644
--- a/nomad-front-end/src/containers/Dashboard/Dashboard.jsx
+++ b/nomad-front-end/src/containers/Dashboard/Dashboard.jsx
@@ -2,11 +2,12 @@ import React, { Fragment, useState, useEffect, useRef } from 'react'
import { connect } from 'react-redux'
import {
- fetchStatusSummary,
- fetchStatusTable,
- closeDashDrawer,
- statusUpdate,
- toggleAvailableSwitchSuccess
+ fetchStatusSummary,
+ fetchStatusTable,
+ closeDashDrawer,
+ statusUpdate,
+ toggleAvailableSwitchSuccess,
+ resetCheckedHolders
} from '../../store/actions'
import socket from '../../socketConnection'
@@ -17,102 +18,104 @@ import StatusDrawer from '../../components/StatusDrawer/StatusDrawer'
import './Dashboard.css'
const Dashboard = props => {
- const [activeTab, setActiveTab] = useState('0')
- const { fetchStatusSum, fetchStatusTable, statusSummary } = props
+ const [activeTab, setActiveTab] = useState('0')
+ const { fetchStatusSum, fetchStatusTable, statusSummary } = props
- const activeTabIdRef = useRef(null)
+ const activeTabIdRef = useRef(null)
- useEffect(() => {
- window.scrollTo(0, 0)
- fetchStatusSum()
- fetchStatusTable('0')
- }, [fetchStatusSum, fetchStatusTable])
+ useEffect(() => {
+ window.scrollTo(0, 0)
+ fetchStatusSum()
+ fetchStatusTable('0')
+ }, [fetchStatusSum, fetchStatusTable])
- //Hook sets active tab to 1st instrument in the array when the page get reloaded
- useEffect(() => {
- if (activeTab === '0' && statusSummary.length > 0) {
- setActiveTab(statusSummary[0].key)
- }
- }, [activeTab, statusSummary])
+ //Hook sets active tab to 1st instrument in the array when the page get reloaded
+ useEffect(() => {
+ if (activeTab === '0' && statusSummary.length > 0) {
+ setActiveTab(statusSummary[0].key)
+ }
+ }, [activeTab, statusSummary])
- //Hook creates reference to instrument ID in activeTab and activeTab index value that is used in subsequent hook to reload the active tab if it gets updated.
- useEffect(() => {
- if (props.statusSummary.length > 0) {
- activeTabIdRef.current = {
- // instrId: props.statusSummary[activeTab]._id,
- instrId: activeTab,
- activeTab
- }
- }
- }, [props.statusSummary, activeTab])
+ //Hook creates reference to instrument ID in activeTab and activeTab index value that is used in subsequent hook to reload the active tab if it gets updated.
+ useEffect(() => {
+ if (props.statusSummary.length > 0) {
+ activeTabIdRef.current = {
+ // instrId: props.statusSummary[activeTab]._id,
+ instrId: activeTab,
+ activeTab
+ }
+ }
+ }, [props.statusSummary, activeTab])
- //Hook for socket.io that gets triggered when status of an instrument is updated by tracker at the backend
- useEffect(() => {
- socket.on('statusUpdate', data => {
- props.statUpdate(data)
- const { instrId, activeTab } = activeTabIdRef.current
- if (instrId === data.instrId) {
- fetchStatusTable(activeTab)
- }
- })
+ //Hook for socket.io that gets triggered when status of an instrument is updated by tracker at the backend
+ useEffect(() => {
+ socket.on('statusUpdate', data => {
+ props.statUpdate(data)
+ const { instrId, activeTab } = activeTabIdRef.current
+ if (instrId === data.instrId) {
+ fetchStatusTable(activeTab)
+ }
+ })
- socket.on('availableUpdate', data => {
- props.toggleAvailableSuccess(data)
- })
- return () => {
- socket.removeAllListeners('statusUpdate')
- }
- // useEffect for socket.io function must have empty dependency array otherwise the triggers infinite loop!!!
- // eslint-disable-next-line
- }, [])
+ socket.on('availableUpdate', data => {
+ props.toggleAvailableSuccess(data)
+ })
+ return () => {
+ socket.removeAllListeners('statusUpdate')
+ }
+ // useEffect for socket.io function must have empty dependency array otherwise the triggers infinite loop!!!
+ // eslint-disable-next-line
+ }, [])
- const tabChangeHandler = key => {
- fetchStatusTable(key)
- setActiveTab(key)
- }
+ const tabChangeHandler = key => {
+ fetchStatusTable(key)
+ setActiveTab(key)
+ props.resetChecked()
+ }
- return (
-
-
- {props.showCards ? (
-
- ) : null}
-
-
-
-
-
-
- )
+ return (
+
+
+ {props.showCards ? (
+
+ ) : null}
+
+
+
+
+
+
+ )
}
const mapStateToProps = state => {
- return {
- showCards: state.dash.showCards,
- statusSummary: state.dash.statusSummaryData,
- statusTable: state.dash.statusTableData,
- tableLoading: state.dash.tableLoading,
- drawerState: state.dash.drawerState,
- accessLevel: state.auth.accessLevel,
- authToken: state.auth.token,
- username: state.auth.username
- }
+ return {
+ showCards: state.dash.showCards,
+ statusSummary: state.dash.statusSummaryData,
+ statusTable: state.dash.statusTableData,
+ tableLoading: state.dash.tableLoading,
+ drawerState: state.dash.drawerState,
+ accessLevel: state.auth.accessLevel,
+ authToken: state.auth.token,
+ username: state.auth.username
+ }
}
const mapDispatchToProps = dispatch => {
- return {
- fetchStatusSum: () => dispatch(fetchStatusSummary()),
- onCloseDrawer: () => dispatch(closeDashDrawer()),
- fetchStatusTable: key => dispatch(fetchStatusTable(key)),
- statUpdate: data => dispatch(statusUpdate(data)),
- toggleAvailableSuccess: payload => dispatch(toggleAvailableSwitchSuccess(payload))
- }
+ return {
+ fetchStatusSum: () => dispatch(fetchStatusSummary()),
+ onCloseDrawer: () => dispatch(closeDashDrawer()),
+ fetchStatusTable: key => dispatch(fetchStatusTable(key)),
+ statUpdate: data => dispatch(statusUpdate(data)),
+ toggleAvailableSuccess: payload => dispatch(toggleAvailableSwitchSuccess(payload)),
+ resetChecked: () => dispatch(resetCheckedHolders())
+ }
}
export default connect(mapStateToProps, mapDispatchToProps)(Dashboard)
diff --git a/nomad-front-end/src/containers/Resubmit/Resubmit.jsx b/nomad-front-end/src/containers/Resubmit/Resubmit.jsx
new file mode 100644
index 0000000..6e42e14
--- /dev/null
+++ b/nomad-front-end/src/containers/Resubmit/Resubmit.jsx
@@ -0,0 +1,74 @@
+import React, { useEffect } from 'react'
+import { connect } from 'react-redux'
+
+import BookExperimentsForm from '../../components/Forms/BookExperimentsForm/BookExperimentsForm'
+
+import {
+ fetchParamSets,
+ fetchAllowance,
+ bookExperiments,
+ resetResubmit,
+ signOutHandler,
+ cancelBookedHolders
+} from '../../store/actions'
+
+const Resubmit = props => {
+ const { reservedHolders, formValues, userId } = props.resubmitData
+ const { fetchParamSets, authToken, allowance, accessLvl, logoutHandler } = props
+
+ useEffect(() => {
+ return () => {
+ props.resetState()
+
+ if (accessLvl !== 'admin' && authToken) {
+ logoutHandler(authToken)
+ }
+ }
+ }, [])
+
+ useEffect(() => {
+ fetchParamSets(authToken, { instrumentId: null, searchValue: '' })
+ }, [fetchParamSets, authToken])
+
+ return (
+
+ {reservedHolders.length !== 0 || props.loading ? (
+
+ ) : null}
+
+ )
+}
+
+const mapStateToProps = state => ({
+ resubmitData: state.submit.resubmitData,
+ loading: state.submit.loading,
+ accessLvl: state.auth.accessLevel,
+ authToken: state.auth.token,
+ paramSets: state.paramSets.paramSetsData,
+ allowance: state.submit.allowance
+})
+
+const mapDispatchToProps = dispatch => {
+ return {
+ fetchParamSets: (token, searchParams) => dispatch(fetchParamSets(token, searchParams)),
+ fetchAllow: (token, instrIds) => dispatch(fetchAllowance(token, instrIds)),
+ bookExpsHandler: (token, data, user) => dispatch(bookExperiments(token, data, user)),
+ resetState: () => dispatch(resetResubmit()),
+ logoutHandler: token => dispatch(signOutHandler(token)),
+ cancelHolders: (token, keys) => dispatch(cancelBookedHolders(token, keys))
+ }
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(Resubmit)
diff --git a/nomad-front-end/src/store/actions/actionTypes.js b/nomad-front-end/src/store/actions/actionTypes.js
index 8029bb9..d8c27d1 100644
--- a/nomad-front-end/src/store/actions/actionTypes.js
+++ b/nomad-front-end/src/store/actions/actionTypes.js
@@ -35,6 +35,7 @@ export const UPDATE_CHECKBOX_STATUS_TAB = 'UPDATE_CHECKBOX_STATUS_TAB'
export const DELETE_HOLDERS_SUCCESS = 'DELETE_HOLDERS_SUCCESS'
export const UPDATE_PENDING_CHECKED = 'UPDATE_PENDING_CHECKED'
export const POST_PENDING_SUCCESS = 'POST_PENDING_SUCCESS'
+export const RESET_CHECKED_HOLDERS = 'RESET_CHECKED_HOLDERS'
//INSTRUMENTS
export const FETCH_INSTRUMENTS_TABLE_START = 'FETCH_INSTRUMENTS_TABLE_START'
@@ -107,6 +108,8 @@ export const CANCEL_HOLDER_SUCCESS = 'CANCEL_HOLDER_SUCCESS'
export const CANCEL_BOOKED_HOLDERS_SUCCESS = 'CANCEL_BOOKED_HOLDERS_SUCCESS'
export const BOOK_EXPERIMENTS_SUCCESS = 'BOOK_EXPERIMENTS_SUCCESS'
export const FETCH_ALLOWANCE_SUCCESS = 'FETCH_ALLOWANCE_SUCCESS'
+export const RESUBMIT_HOLDERS_SUCCESS = 'RESUBMIT_HOLDERS_SUCCESS'
+export const RESET_RESUBMIT_DATA = 'RESET_RESUBMIT_DATA'
//MESSAGE
export const SEND_MESSAGE_START = 'SEND_MESSAGE_START'
diff --git a/nomad-front-end/src/store/actions/dashboard.js b/nomad-front-end/src/store/actions/dashboard.js
index c91510d..90fcb26 100644
--- a/nomad-front-end/src/store/actions/dashboard.js
+++ b/nomad-front-end/src/store/actions/dashboard.js
@@ -3,210 +3,214 @@ import axios from '../../axios-instance'
import errorHandler from './errorHandler'
export const toggleCards = () => {
- return {
- type: actionTypes.TOGGLE_CARDS
- }
+ return {
+ type: actionTypes.TOGGLE_CARDS
+ }
}
export const openDashDrawerStart = payload => ({
- type: actionTypes.OPEN_DASH_DRAWER_START,
- id: payload
+ type: actionTypes.OPEN_DASH_DRAWER_START,
+ id: payload
})
export const openDashDrawerSuccess = payload => ({
- type: actionTypes.FETCH_DASH_DRAWER_SUCCESS,
- data: payload
+ type: actionTypes.FETCH_DASH_DRAWER_SUCCESS,
+ data: payload
})
export const openDashDrawer = id => {
- return dispatch => {
- dispatch(openDashDrawerStart(id))
- axios
- .get('/dash/drawer-table/' + id)
- .then(res => {
- dispatch(openDashDrawerSuccess(res.data))
- dispatch(autoCloseModal())
- })
- .catch(err => {
- dispatch(errorHandler(err))
- })
- }
+ return dispatch => {
+ dispatch(openDashDrawerStart(id))
+ axios
+ .get('/dash/drawer-table/' + id)
+ .then(res => {
+ dispatch(openDashDrawerSuccess(res.data))
+ dispatch(autoCloseModal())
+ })
+ .catch(err => {
+ dispatch(errorHandler(err))
+ })
+ }
}
export const closeDashDrawer = () => ({
- type: actionTypes.CLOSE_DASH_DRAWER
+ type: actionTypes.CLOSE_DASH_DRAWER
})
export const autoCloseModal = () => {
- return dispatch => {
- setTimeout(() => dispatch(closeDashDrawer()), 120000)
- }
+ return dispatch => {
+ setTimeout(() => dispatch(closeDashDrawer()), 120000)
+ }
}
export const fetchStatusSummarySuccess = payload => ({
- type: actionTypes.FETCH_STATUS_SUMMARY_SUCCESS,
- data: payload
+ type: actionTypes.FETCH_STATUS_SUMMARY_SUCCESS,
+ data: payload
})
export const fetchStatusSummary = () => {
- return dispatch => {
- axios
- .get('/dash/status-summary')
- .then(res => dispatch(fetchStatusSummarySuccess(res.data)))
- .catch(err => dispatch(errorHandler(err)))
- }
+ return dispatch => {
+ axios
+ .get('/dash/status-summary')
+ .then(res => dispatch(fetchStatusSummarySuccess(res.data)))
+ .catch(err => dispatch(errorHandler(err)))
+ }
}
export const fetchStatusTableStart = () => ({
- type: actionTypes.FETCH_STATUS_TABLE_START
+ type: actionTypes.FETCH_STATUS_TABLE_START
})
export const fetchStatusTableSuccess = payload => ({
- type: actionTypes.FETCH_STATUS_TABLE_SUCCESS,
- data: payload
+ type: actionTypes.FETCH_STATUS_TABLE_SUCCESS,
+ data: payload
})
export const fetchStatusTable = tab => {
- return dispatch => {
- dispatch(fetchStatusTableStart())
- axios
- .get('/dash/status-table/' + tab)
- .then(res => dispatch(fetchStatusTableSuccess(res.data)))
- .catch(err => {
- dispatch(errorHandler(err))
- })
- }
+ return dispatch => {
+ dispatch(fetchStatusTableStart())
+ axios
+ .get('/dash/status-table/' + tab)
+ .then(res => dispatch(fetchStatusTableSuccess(res.data)))
+ .catch(err => {
+ dispatch(errorHandler(err))
+ })
+ }
}
export const statusUpdate = data => ({
- type: actionTypes.STATUS_UPDATE,
- data
+ type: actionTypes.STATUS_UPDATE,
+ data
})
export const toggleAvailableSwitchSuccess = payload => {
- return {
- type: actionTypes.TOGGLE_AVAILABLE_SUCCESS_DASH,
- data: payload
- }
+ return {
+ type: actionTypes.TOGGLE_AVAILABLE_SUCCESS_DASH,
+ data: payload
+ }
}
export const toggleAvailableOnDash = (id, token) => {
- return dispatch => {
- axios
- .patch(`/admin/instruments/toggle-available/${id}`, null, {
- headers: { Authorization: 'Bearer ' + token }
- })
- .then(res => {
- // dispatch(toggleAvailableSwitchSuccess(res.data))
- //state gets updated through sockets calling toggleAvailableSwitchSuccess
- })
- .catch(err => {
- dispatch(errorHandler(err))
- })
- }
+ return dispatch => {
+ axios
+ .patch(`/admin/instruments/toggle-available/${id}`, null, {
+ headers: { Authorization: 'Bearer ' + token }
+ })
+ .then(res => {
+ // dispatch(toggleAvailableSwitchSuccess(res.data))
+ //state gets updated through sockets calling toggleAvailableSwitchSuccess
+ })
+ .catch(err => {
+ dispatch(errorHandler(err))
+ })
+ }
}
export const updateCheckboxStatusTab = payload => ({
- type: actionTypes.UPDATE_CHECKBOX_STATUS_TAB,
- payload
+ type: actionTypes.UPDATE_CHECKBOX_STATUS_TAB,
+ payload
})
export const deleteHoldersSuccess = payload => ({
- type: actionTypes.DELETE_HOLDERS_SUCCESS,
- payload
+ type: actionTypes.DELETE_HOLDERS_SUCCESS,
+ payload
})
export const deleteExperiments = (token, instrId, holders) => {
- return dispatch => {
- axios
- .delete('/submit/experiments/' + instrId, {
- data: holders,
- headers: { Authorization: 'Bearer ' + token }
- })
- .then(res => {
- if (res.status === 200) {
- dispatch(deleteHoldersSuccess(holders))
- }
- })
- .catch(err => {
- dispatch(errorHandler(err))
- })
- }
+ return dispatch => {
+ axios
+ .delete('/submit/experiments/' + instrId, {
+ data: holders,
+ headers: { Authorization: 'Bearer ' + token }
+ })
+ .then(res => {
+ if (res.status === 200) {
+ dispatch(deleteHoldersSuccess(holders))
+ }
+ })
+ .catch(err => {
+ dispatch(errorHandler(err))
+ })
+ }
}
export const resetQueue = (token, instrId) => {
- return dispatch => {
- axios
- .put('/submit/reset/' + instrId, null, {
- headers: { Authorization: 'Bearer ' + token }
- })
- .then(res => {
- dispatch(deleteHoldersSuccess(res.data))
- })
- .catch(err => {
- dispatch(errorHandler(err))
- })
- }
+ return dispatch => {
+ axios
+ .put('/submit/reset/' + instrId, null, {
+ headers: { Authorization: 'Bearer ' + token }
+ })
+ .then(res => {
+ dispatch(deleteHoldersSuccess(res.data))
+ })
+ .catch(err => {
+ dispatch(errorHandler(err))
+ })
+ }
}
export const updatePendingChecked = payload => ({
- type: actionTypes.UPDATE_PENDING_CHECKED,
- payload
+ type: actionTypes.UPDATE_PENDING_CHECKED,
+ payload
})
export const postPendingSuccess = () => ({
- type: actionTypes.POST_PENDING_SUCCESS
+ type: actionTypes.POST_PENDING_SUCCESS
})
export const postPending = (token, type, data) => {
- return dispatch => {
- axios
- .post(
- '/submit/pending/' + type,
- { data: skimPendingData(data) },
- {
- headers: { Authorization: 'Bearer ' + token }
- }
- )
- .then(res => {
- if (res.status === 200) {
- dispatch(postPendingSuccess())
- }
- })
- .catch(err => {
- dispatch(errorHandler(err))
- })
- }
+ return dispatch => {
+ axios
+ .post(
+ '/submit/pending/' + type,
+ { data: skimPendingData(data) },
+ {
+ headers: { Authorization: 'Bearer ' + token }
+ }
+ )
+ .then(res => {
+ if (res.status === 200) {
+ dispatch(postPendingSuccess())
+ }
+ })
+ .catch(err => {
+ dispatch(errorHandler(err))
+ })
+ }
}
export const postPendingAuth = (type, inputData) => {
- return dispatch => {
- axios
- .post('/submit/pending-auth/' + type, {
- username: inputData.username,
- password: inputData.password,
- data: skimPendingData(inputData.holders)
- })
- .then(res => {
- if (res.status === 200) {
- dispatch(postPendingSuccess())
- }
- })
- .catch(err => {
- dispatch(errorHandler(err))
- })
- }
+ return dispatch => {
+ axios
+ .post('/submit/pending-auth/' + type, {
+ username: inputData.username,
+ password: inputData.password,
+ data: skimPendingData(inputData.holders)
+ })
+ .then(res => {
+ if (res.status === 200) {
+ dispatch(postPendingSuccess())
+ }
+ })
+ .catch(err => {
+ dispatch(errorHandler(err))
+ })
+ }
}
+export const resetCheckedHolders = () => ({
+ type: actionTypes.RESET_CHECKED_HOLDERS
+})
+
//Helper function for restructuring pending data object
const skimPendingData = data => {
- const result = {}
- data.forEach(i => {
- if (!result[i.instrId]) {
- result[i.instrId] = [i.holder]
- } else {
- result[i.instrId].push(i.holder)
- }
- })
- return result
+ const result = {}
+ data.forEach(i => {
+ if (!result[i.instrId]) {
+ result[i.instrId] = [i.holder]
+ } else {
+ result[i.instrId].push(i.holder)
+ }
+ })
+ return result
}
diff --git a/nomad-front-end/src/store/actions/index.js b/nomad-front-end/src/store/actions/index.js
index 4f032f2..caf2237 100644
--- a/nomad-front-end/src/store/actions/index.js
+++ b/nomad-front-end/src/store/actions/index.js
@@ -25,7 +25,8 @@ export {
postPendingAuth,
toggleAvailableSwitchSuccess,
deleteExperiments,
- resetQueue
+ resetQueue,
+ resetCheckedHolders
} from './dashboard'
export {
@@ -93,7 +94,9 @@ export {
cancelBookedHolders,
bookExperiments,
cancelBookedHoldersSuccess,
- fetchAllowance
+ fetchAllowance,
+ resubmitHolders,
+ resetResubmit
} from './submit'
export { sendMessage } from './message'
diff --git a/nomad-front-end/src/store/actions/submit.js b/nomad-front-end/src/store/actions/submit.js
index 86145d9..eeb4c35 100644
--- a/nomad-front-end/src/store/actions/submit.js
+++ b/nomad-front-end/src/store/actions/submit.js
@@ -121,3 +121,30 @@ export const fetchAllowance = (token, instrIds) => {
})
}
}
+
+export const resubmitHoldersSuccess = payload => ({
+ type: actionTypes.RESUBMIT_HOLDERS_SUCCESS,
+ payload
+})
+
+export const resubmitHolders = (token, dataObj) => {
+ return dispatch => {
+ axios
+ .post('/submit/resubmit', dataObj, {
+ headers: { Authorization: 'Bearer ' + token }
+ })
+ .then(res => {
+ if (res.status === 200) {
+ dispatch(resubmitHoldersSuccess(res.data))
+ }
+ })
+ .catch(err => {
+ console.log(err)
+ dispatch(errorHandler(err))
+ })
+ }
+}
+
+export const resetResubmit = () => ({
+ type: actionTypes.RESET_RESUBMIT_DATA
+})
diff --git a/nomad-front-end/src/store/reducers/dashboard.js b/nomad-front-end/src/store/reducers/dashboard.js
index 5a97c14..c2ae24f 100644
--- a/nomad-front-end/src/store/reducers/dashboard.js
+++ b/nomad-front-end/src/store/reducers/dashboard.js
@@ -157,6 +157,12 @@ const reducer = (state = initialState, action) => {
drawerState: { ...state.drawerState, visible: false, pendingChecked: [] }
}
+ case actionTypes.RESET_CHECKED_HOLDERS:
+ return { ...state, statusTabChecked: [] }
+
+ case actionTypes.RESET_RESUBMIT_DATA:
+ return { ...state, drawerState: { ...state.drawerState, visible: false, pendingChecked: [] } }
+
default:
return state
}
diff --git a/nomad-front-end/src/store/reducers/submit.js b/nomad-front-end/src/store/reducers/submit.js
index 74fd909..0ee03c4 100644
--- a/nomad-front-end/src/store/reducers/submit.js
+++ b/nomad-front-end/src/store/reducers/submit.js
@@ -4,7 +4,8 @@ import * as actionTypes from '../actions/actionTypes'
const initialState = {
loading: false,
bookedHolders: [],
- allowance: []
+ allowance: [],
+ resubmitData: { reservedHolders: [], formValues: {}, userId: undefined }
}
const reducer = (state = initialState, { type, payload }) => {
@@ -52,12 +53,54 @@ const reducer = (state = initialState, { type, payload }) => {
bookedHolders: []
}
- // case actionTypes.CLEAR_BOOKED_HOLDERS:
- // return { ...state, bookedHolders: [] }
-
case actionTypes.FETCH_ALLOWANCE_SUCCESS:
return { ...state, allowance: payload }
+ case actionTypes.RESUBMIT_HOLDERS_SUCCESS:
+ const { experimentData } = payload
+ const reservedHoldersSet = new Set()
+ experimentData.forEach(exp => {
+ reservedHoldersSet.add(exp.holder)
+ })
+ const reservedHolders = Array.from(reservedHoldersSet).map(holder => ({
+ holder: +holder,
+ instId: payload.instrument._id,
+ instrument: payload.instrument.name,
+ key: payload.instrument._id + '-' + holder,
+ paramsEditing: payload.instrument.paramsEditing,
+ expCount: experimentData.filter(i => i.holder === holder).length
+ }))
+
+ let formValues = {}
+ reservedHolders.forEach(entry => {
+ const exps = experimentData.filter(i => i.holder === entry.holder.toString())
+
+ const expsEntries = exps.map(exp => [
+ exp.expNo,
+ {
+ paramSet: exp.parameterSet,
+ params: exp.parameters,
+ expTime: exp.time
+ }
+ ])
+
+ formValues[entry.key] = {
+ title: exps[0].title,
+ solvent: exps[0].solvent,
+ night: exps[0].night,
+ priority: exps[0].priority,
+ exps: Object.fromEntries(expsEntries)
+ }
+ })
+
+ return {
+ ...state,
+ resubmitData: { reservedHolders, formValues, userId: payload.userId }
+ }
+
+ case actionTypes.RESET_RESUBMIT_DATA:
+ return { ...state, resubmitData: { reservedHolders: [], formValues: {}, userId: undefined } }
+
default:
return state
}
diff --git a/nomad-rest-api/Dockerfile b/nomad-rest-api/Dockerfile
index 44a53c7..f5e0770 100644
--- a/nomad-rest-api/Dockerfile
+++ b/nomad-rest-api/Dockerfile
@@ -1,4 +1,4 @@
-FROM node:20.11.0-slim
+FROM node:20.13.1-bookworm-slim
WORKDIR /app
diff --git a/nomad-rest-api/controllers/auth.js b/nomad-rest-api/controllers/auth.js
index 6fac0bf..8655d8a 100644
--- a/nomad-rest-api/controllers/auth.js
+++ b/nomad-rest-api/controllers/auth.js
@@ -26,7 +26,6 @@ export async function postLogin(req, res) {
}
const token = await user.generateAuthToken()
-
return res.send({
username: user.username,
accessLevel: user.accessLevel,
diff --git a/nomad-rest-api/controllers/submit.js b/nomad-rest-api/controllers/submit.js
index 0893f30..45eb461 100644
--- a/nomad-rest-api/controllers/submit.js
+++ b/nomad-rest-api/controllers/submit.js
@@ -207,7 +207,11 @@ export const deleteExps = (req, res) => {
res.send()
} catch (error) {
console.log(error)
- res.status(500).send()
+ if (error.toString().includes('Client disconnected')) {
+ res.status(503).send('Client disconnected')
+ } else {
+ res.sendStatus(500)
+ }
}
}
@@ -245,7 +249,11 @@ export const putReset = async (req, res) => {
res.status(200).json(holdersToDelete)
} catch (error) {
console.log(error)
- res.status(500).send()
+ if (error.toString().includes('Client disconnected')) {
+ res.status(503).send('Client disconnected')
+ } else {
+ res.sendStatus(500)
+ }
}
}
@@ -335,14 +343,55 @@ export const getAllowance = async (req, res) => {
}
}
+export async function postResubmit(req, res) {
+ try {
+ const { instrId, checkedHolders, username } = req.body
+ const submitter = getSubmitter()
+
+ const { status } = await Instrument.findById(req.body.instrId, 'status')
+
+ const experimentData = status.statusTable
+ .filter(entry => checkedHolders.find(holder => holder === entry.holder))
+ .map(entry => ({ ...entry, title: entry.title.split('||')[0] }))
+
+ if (experimentData.length === 0) {
+ return res.status(422).send({ errors: [{ msg: 'Experiments not found in status table' }] })
+ }
+
+ emitDeleteExps(instrId, checkedHolders, res)
+ submitter.updateBookedHolders(
+ instrId,
+ checkedHolders.map(i => +i)
+ )
+
+ const user = await User.findOne({ username })
+ const instrument = await Instrument.findById(instrId, 'name paramsEditing')
+ if (!user) {
+ return res.status(404).send({ message: 'User not found' })
+ }
+ if (!instrument) {
+ return res.status(404).send({ message: 'Instrument not found' })
+ }
+
+ res.status(200).json({ userId: user._id, instrument, experimentData })
+ } catch (error) {
+ console.log(error)
+ if (error.toString().includes('Client disconnected')) {
+ res.status(503).send('Client disconnected')
+ } else {
+ res.sendStatus(500)
+ }
+ }
+}
+
//Helper function that sends array of holders to be deleted to the client
const emitDeleteExps = (instrId, holders, res) => {
const submitter = getSubmitter()
const { socketId } = submitter.state.get(instrId)
if (!socketId) {
- console.log('Error: Client disconnected')
- return res.status(503).send('Client disconnected')
+ throw new Error('Client disconnected')
+ // return res.status(503).send('Client disconnected')
}
getIO().to(socketId).emit('delete', JSON.stringify(holders))
diff --git a/nomad-rest-api/package.json b/nomad-rest-api/package.json
index 5cd8a87..03c97c5 100644
--- a/nomad-rest-api/package.json
+++ b/nomad-rest-api/package.json
@@ -1,6 +1,6 @@
{
"name": "nomad-rest-api",
- "version": "3.5.3",
+ "version": "3.5.4-beta",
"description": "REST API back-end for NOMAD system",
"main": "server.js",
"type": "module",
@@ -44,4 +44,4 @@
"supertest": "^7.0.0",
"vitest": "^1.3.1"
}
-}
+}
\ No newline at end of file
diff --git a/nomad-rest-api/routes/submit.js b/nomad-rest-api/routes/submit.js
index c6846cd..4f2557b 100644
--- a/nomad-rest-api/routes/submit.js
+++ b/nomad-rest-api/routes/submit.js
@@ -10,7 +10,8 @@ import {
deleteExps,
putReset,
postPending,
- getAllowance
+ getAllowance,
+ postResubmit
} from '../controllers/submit.js'
const router = Router()
@@ -33,4 +34,6 @@ router.post('/pending-auth/:type', postPending)
router.get('/allowance/', auth, getAllowance)
+router.post('/resubmit', auth, postResubmit)
+
export default router