Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue 136 #156

Merged
merged 12 commits into from
Nov 6, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Dockerfile.api
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM node:20.11.0-slim
FROM node:20.13.1-bookworm-slim

WORKDIR /app

4 changes: 2 additions & 2 deletions Dockerfile.serv
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
FROM node:20.11.0-slim as frontend
FROM node:20.13.1-bookworm-slim as frontend

WORKDIR /app

COPY ./nomad-front-end/package.json .

RUN npm install --force
RUN npm install

COPY ./nomad-front-end .

4 changes: 2 additions & 2 deletions Dockerfile.serv-tls
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
FROM node:20.11.0-slim as frontend
FROM node:20.13.1-bookworm-slim as frontend

WORKDIR /app

COPY ./nomad-front-end/package.json .

RUN npm install --force
RUN npm install

COPY ./nomad-front-end .

2 changes: 1 addition & 1 deletion nomad-front-end/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM node:20.11.0-slim
FROM node:20.13.1-bookworm-slim

WORKDIR /app

2 changes: 1 addition & 1 deletion nomad-front-end/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "nomad-front-end",
"private": false,
"version": "3.5.3",
"version": "3.5.4-beta",
"type": "module",
"scripts": {
"start": "env-cmd -f ../env/frontend.env vite",
11 changes: 11 additions & 0 deletions nomad-front-end/src/App.jsx
Original file line number Diff line number Diff line change
@@ -22,6 +22,7 @@ import Error404 from './components/Errors/Error404'
import Error403 from './components/Errors/Error403'
import Credits from './components/Credits/Credits'
import Reset from './containers/Reset/Reset'
import Resubmit from './containers/Resubmit/Resubmit'

const { Header, Sider, Content, Footer } = Layout

@@ -184,6 +185,16 @@ const App = props => {
)
}
/>
<Route
path='/resubmit'
element={
import.meta.env.VITE_BATCH_SUBMIT_ON === 'true' ? (
<Resubmit />
) : (
<Navigate to='/dashboard' />
)
}
/>
<Route
path='/search-experiment'
element={
Original file line number Diff line number Diff line change
@@ -16,7 +16,8 @@ const GrantsCostsTable = props => {
},
{
title: 'Description',
dataIndex: 'description'
dataIndex: 'description',
sorter: (a, b) => a.description.localeCompare(b.description)
},
{
title: 'Cost [£]',
Original file line number Diff line number Diff line change
@@ -13,7 +13,8 @@ import {
message,
Modal,
Checkbox,
Tooltip
Tooltip,
Popconfirm
} from 'antd'
import moment from 'moment'

@@ -23,6 +24,7 @@ import EditParamsModal from '../../Modals/EditParamsModal/EditPramsModal'
import nightIcon from '../../../assets/night-mode.svg'

import classes from './BookExperimentsForm.module.css'
import { all } from 'axios'

const { Option } = Select

@@ -45,9 +47,22 @@ const BookExperimentsForm = props => {
const [exptState, setExptState] = useState({})
const [totalExptState, setTotalExptState] = useState({})

const { inputData, allowanceData, fetchAllowance, token, accessLevel } = props
const { inputData, allowanceData, fetchAllowance, token, accessLevel, formValues } = props

const priorityAccess = accessLevel === 'user-a' || accessLevel === 'admin'
const resubmit = formValues

//This hook is used to cancel booked holders on the form component dismount
// It uses deleteHolders function in submit controller at the backend which has
// 120s timeout to allow for iconNMR to pickup submit file
useEffect(() => {
return () => {
props.cancelHolders(
token,
inputData.map(i => i.key)
)
}
}, [])

//Hook to create state for dynamic ExpNo part of form from inputData
//InputData gets updated every time new holder is booked
@@ -62,7 +77,7 @@ const BookExperimentsForm = props => {
} else {
newFormState.push({
key: i.key,
expCount: 1
expCount: resubmit ? i.expCount : 1
})
}
})
@@ -72,23 +87,56 @@ const BookExperimentsForm = props => {
if (instrIds.size !== 0) {
fetchAllowance(token, Array.from(instrIds))
}

//setting up form values and expTime if form used for resubmit
if (resubmit) {
form.setFieldsValue(formValues)
}

// formState can't be dependency as it gets updated in the hook. That would trigger loop.
// eslint-disable-next-line
}, [inputData])
}, [inputData, formValues])

//This hook creates initial totalExpT state with overhead time for each entry
useEffect(() => {
const newTotalExptState = { ...totalExptState }
if (allowanceData.length !== 0) {
formState.forEach(entry => {
const instrId = entry.key.split('-')[0]
const { overheadTime } = allowanceData.find(i => i.instrId === instrId)
if (!newTotalExptState[entry.key]) {
newTotalExptState[entry.key] = overheadTime
if (resubmit) {
const expTimeStateEntries = []
const totalExpTimeStateEntries = []

if (allowanceData.length > 0) {
for (let sampleKey in formValues) {
let expTimeSum = allowanceData[0].overheadTime
//selecting first element of allowanceData array works as
//only holders on one instrument can be selected for resubmit
for (let expNo in formValues[sampleKey].exps) {
expTimeStateEntries.push([
sampleKey + '#' + expNo,
formValues[sampleKey].exps[expNo].expTime
])
expTimeSum += moment
.duration(formValues[sampleKey].exps[expNo].expTime, 'HH:mm:ss')
.asSeconds()
}
totalExpTimeStateEntries.push([sampleKey, expTimeSum])
}
})
}

setExptState(Object.fromEntries(expTimeStateEntries))
setTotalExptState(Object.fromEntries(totalExpTimeStateEntries))
} else {
const newTotalExptState = { ...totalExptState }
if (allowanceData.length !== 0 && !resubmit) {
formState.forEach(entry => {
const instrId = entry.key.split('-')[0]
const { overheadTime } = allowanceData.find(i => i.instrId === instrId)
if (!newTotalExptState[entry.key]) {
newTotalExptState[entry.key] = overheadTime
}
})
}
setTotalExptState(newTotalExptState)
}
setTotalExptState(newTotalExptState)

// eslint-disable-next-line
}, [allowanceData])

@@ -129,7 +177,6 @@ const BookExperimentsForm = props => {
const onParamSetChange = (sampleKey, expNo, paramSetName) => {
form.resetFields([[sampleKey, 'exps', expNo, 'params']])
const key = sampleKey + '#' + expNo

const paramSet = props.paramSetsData.find(paramSet => paramSet.name === paramSetName)

if (paramSet.defaultParams.length < 4) {
@@ -453,19 +500,22 @@ const BookExperimentsForm = props => {
))}
</Col>
{priorityAccess && checkBoxes}
<Col span={1}>
<button
className={classes.CancelButton}
value={key}
onClick={e => {
e.preventDefault()
props.onCancelHolder(props.token, e.target.value)
form.resetFields([e.target.value])
}}
>
Cancel
</button>
</Col>
{!resubmit && (
<Col span={1}>
<button
className={classes.CancelButton}
disabled={resubmit}
value={key}
onClick={e => {
e.preventDefault()
props.onCancelHolder(props.token, e.target.value)
form.resetFields([e.target.value])
}}
>
Cancel
</button>
</Col>
)}
</Row>
<Row gutter={16}>
<Col
@@ -523,11 +573,25 @@ const BookExperimentsForm = props => {
) : (
<Form form={form} ref={props.formRef} size='small' onFinish={onFinishHandler}>
{formItems}
<Form.Item>
<Button type='primary' size='middle' htmlType='submit'>
Continue
</Button>
</Form.Item>
<Space>
<Form.Item>
<Button type='primary' size='middle' htmlType='submit'>
Continue
</Button>
</Form.Item>
{resubmit && (
<Form.Item>
<Popconfirm
title='Cancel holders'
description='Booked holders will be canceled '
onConfirm={() => navigate('/dashboard')}
>
<Button size='middle'>Cancel</Button>
</Popconfirm>
</Form.Item>
)}
</Space>

<EditParamsModal
visible={modalVisible}
closeModal={closeModalHandler}
Original file line number Diff line number Diff line change
@@ -206,6 +206,11 @@ const PageHeaderEl = props => {
avatarSrc = submitIcon
break

case location.pathname === '/resubmit':
headerTitle = 'Resubmit Experiments'
avatarSrc = submitIcon
break

case location.pathname === '/batch-submit':
headerTitle = 'Batch Submit'
avatarSrc = batchSubmitIcon
63 changes: 47 additions & 16 deletions nomad-front-end/src/components/StatusDrawer/StatusDrawer.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import React, { useState } from 'react'
import { Drawer, Button, Row, Col, message } from 'antd'
import { Drawer, Button, Space, message } from 'antd'
import { connect } from 'react-redux'
import { useNavigate } from 'react-router-dom'

import DrawerTable from './DrawerTable/DrawerTable'
import SubmitModal from '../Modals/SubmitModal/SubmitModal'
import { postPending, signOutHandler, postPendingAuth } from '../../store/actions'
import { postPending, signOutHandler, postPendingAuth, resubmitHolders } from '../../store/actions'

const StatusDrawer = props => {
const { id, visible, tableData, dataLoading } = props.status
@@ -13,6 +14,8 @@ const StatusDrawer = props => {
const [modalVisible, setModalVisible] = useState(false)
const [modalData, setModalData] = useState({})

const navigate = useNavigate()

let title = ''
let buttons = null
const headerClass = {
@@ -22,9 +25,6 @@ const StatusDrawer = props => {
}

const btnClickHandler = type => {
if (selectedHolders.length === 0) {
return message.warning('No holders selected!')
}
if (authToken) {
pendingHandler(authToken, type, selectedHolders)
if (accessLvl !== 'admin') {
@@ -42,6 +42,28 @@ const StatusDrawer = props => {
}
}

const editHandler = () => {
console.log(selectedHolders)
const usernames = new Set()
const instrIds = new Set()
selectedHolders.map(row => {
usernames.add(row.username)
instrIds.add(row).instrIds
})

if (usernames.size !== 1 || instrIds.size !== 1) {
return message.error('Holders for multiple users or instruments selected!')
}

props.resubmitHandler(authToken, {
username: selectedHolders[0].username,
checkedHolders: selectedHolders.map(i => i.holder),
instrId: selectedHolders[0].instrId
})

navigate('/resubmit')
}

switch (id) {
case 'errors':
title = 'Errors'
@@ -58,16 +80,24 @@ const StatusDrawer = props => {
headerClass.backgroundColor = '#ffffb8'
headerClass.borderBottom += '#fadb14'
buttons = (
<Row>
<Col span={2} style={{ textAlign: 'left' }}>
<Button onClick={() => btnClickHandler('delete')}>Cancel Selected</Button>
</Col>
<Col span={20} style={{ textAlign: 'center' }}>
<Button type='primary' onClick={() => btnClickHandler('submit')}>
Submit
</Button>
</Col>
</Row>
<Space size={'large'}>
<Button disabled={selectedHolders.length === 0} onClick={() => btnClickHandler('delete')}>
Cancel Selected
</Button>
<Button
disabled={selectedHolders.length === 0 || !authToken}
onClick={() => editHandler()}
>
Edit Selected
</Button>
<Button
type='primary'
disabled={selectedHolders.length === 0}
onClick={() => btnClickHandler('submit')}
>
Submit
</Button>
</Space>
)
break
default:
@@ -116,7 +146,8 @@ const mapDispatchToProps = dispatch => {
return {
pendingHandler: (token, type, data) => dispatch(postPending(token, type, data)),
pendingAuthHandler: (type, data) => dispatch(postPendingAuth(type, data)),
logoutHandler: token => dispatch(signOutHandler(token))
logoutHandler: token => dispatch(signOutHandler(token)),
resubmitHandler: (token, data) => dispatch(resubmitHolders(token, data))
}
}

Loading