diff --git a/frontend/components/newProduct/Step3.js b/frontend/components/newProduct/Step3.js
index 933b02b..8d9b29b 100644
--- a/frontend/components/newProduct/Step3.js
+++ b/frontend/components/newProduct/Step3.js
@@ -5,71 +5,202 @@ import {
Box,
Button,
FormControl,
+ MenuItem,
Stack,
TextField,
Typography
} from '@mui/material'
import IconButton from '@mui/material/IconButton'
import InputAdornment from '@mui/material/InputAdornment'
-import MenuItem from '@mui/material/MenuItem'
+import debounce from 'lodash/debounce'
import PropTypes from 'prop-types'
-import React, { useEffect, useRef, useState } from 'react'
+import React, { useCallback, useEffect, useState } from 'react'
import { contentAssociation, getProductContents } from '../../services/product'
import Loading from '../Loading'
-import axios from 'axios'
+
+const ucds = [
+ {
+ name: 'ID',
+ value: 'meta.id;meta.main'
+ },
+ {
+ name: 'RA',
+ value: 'pos.eq.ra;meta.main'
+ },
+ {
+ name: 'Dec',
+ value: 'pos.eq.dec;meta.main'
+ },
+ {
+ name: 'z',
+ value: 'src.redshift'
+ },
+ {
+ name: 'z_err',
+ value: 'stat.error;src.redshift'
+ },
+ {
+ name: 'z_flag',
+ value: 'stat.rank'
+ },
+ {
+ name: 'survey',
+ value: 'meta.curation'
+ }
+]
+export function InputReadOnly({ name, value, onClear }) {
+
+ return (
+
+
+
+
+
+
+ )
+ } : null}
+ />
+
+ )
+}
+InputReadOnly.propTypes = {
+ value: PropTypes.string.isRequired,
+ name: PropTypes.string,
+ onClear: PropTypes.func
+}
+
+export function InputUcd({ pc, options, onChange, onChangeInputType }) {
+ const [value, setValue] = useState('')
+
+ const handleChange = (e) => {
+ setValue(e.target.value)
+ onChange(pc, e.target.value)
+ }
+ const handleChangeType = () => {
+ onChangeInputType(pc.column_name)
+ }
+ return (
+
+
+
+ {options.map(ucd => (
+
+ ))}
+
+
+
+
+
+
+ )
+}
+InputUcd.propTypes = {
+ pc: PropTypes.object.isRequired,
+ onChange: PropTypes.func.isRequired,
+ onChangeInputType: PropTypes.func.isRequired,
+ options: PropTypes.array.isRequired
+}
+
+export function InputAlias({ pc, onChange, onChangeInputType }) {
+
+ const [value, setValue] = useState('')
+
+ // Using lodash debounce to Delay search by 600ms
+ // Exemplo: https://www.upbeatcode.com/react/how-to-use-lodash-in-react/
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ const delayedEdit = useCallback(
+ debounce((pc, alias) => onChange(pc, alias), 600),
+ []
+ )
+
+ const handleChange = (e) => {
+ setValue(e.target.value)
+ delayedEdit(pc, e.target.value)
+ }
+
+ const handleClear = () => {
+ setValue('')
+ onChange(pc, null)
+ }
+
+ const handleChangeType = () => {
+ onChangeInputType(pc.column_name)
+ }
+
+ return (
+
+
+
+
+
+
+
+ )
+ }}
+ >
+
+
+
+
+
+
+ )
+}
+InputAlias.propTypes = {
+ pc: PropTypes.object.isRequired,
+ onChange: PropTypes.func.isRequired,
+ onChangeInputType: PropTypes.func.isRequired,
+}
+
export default function NewProductStep3({ productId, onNext, onPrev }) {
- const ucds = [
- {
- name: 'ID',
- value: 'meta.id;meta.main'
- },
- {
- name: 'RA',
- value: 'pos.eq.ra;meta.main'
- },
- {
- name: 'Dec',
- value: 'pos.eq.dec;meta.main'
- },
- {
- name: 'z',
- value: 'src.redshift'
- },
- {
- name: 'z_err',
- value: 'stat.error;src.redshift'
- },
- {
- name: 'z_flag',
- value: 'stat.rank'
- },
- {
- name: 'survey',
- value: 'meta.curation'
- }
- ]
const [productColumns, setProductColumns] = React.useState([])
const [usedUcds, setUsedUcds] = React.useState([])
const [isLoading, setLoading] = useState(false)
const [formError, setFormError] = React.useState('')
- const [editableFields, setEditableFields] = useState({})
- const editFieldRefs = useRef({})
+ const [inputsType, setInputsType] = useState([])
+
const loadContents = React.useCallback(async () => {
setLoading(true)
try {
const response = await getProductContents(productId)
+
setProductColumns(response.results)
- const aliases = {}
- response.results.forEach(row => {
- if (row.alias) {
- aliases[row.column_name] = row.alias
- }
- })
- setEditableFields(aliases)
setLoading(false)
} catch (error) {
setLoading(false)
@@ -79,6 +210,24 @@ export default function NewProductStep3({ productId, onNext, onPrev }) {
}
}, [productId])
+ const changeProductContent = (pc, ucd, alias) => {
+ if (pc.ucd === ucd && pc.alias === alias) {
+ return
+ }
+ // setLoading(true)
+ contentAssociation(pc.id, ucd, alias)
+ .then(() => {
+ // setLoading(false)
+ loadContents(productId)
+ })
+ .catch(res => {
+ setLoading(false)
+ if (res.response.status === 500) {
+ catchFormError(res.response.data)
+ }
+ })
+ }
+
useEffect(() => {
loadContents()
}, [loadContents])
@@ -99,157 +248,89 @@ export default function NewProductStep3({ productId, onNext, onPrev }) {
const handlePrev = () => {
onPrev(productId)
}
- const onChangeUcd = (pc, value) => {
- if (pc.ucd === value) {
- return
- }
- // setLoading(true)
- contentAssociation(pc.id, value)
- .then(() => {
- // setLoading(false)
- loadContents(productId)
- })
- .catch(res => {
- setLoading(false)
- if (res.response.status === 500) {
- catchFormError(res.response.data)
- }
- })
- }
- const handleMouseDownPassword = event => {
- event.preventDefault()
+ const onClear = (pc) => {
+ console.log("onClear: ", pc)
+ changeProductContent(pc, null, null)
}
- const handleAlias = (pc, value) => {
- setEditableFields(prevState => ({
- ...prevState,
- [pc.column_name]: value
- }))
+ const onSelectUcd = (pc, ucd) => {
+ console.log("onSelectUcd: ", pc, ucd)
+ changeProductContent(pc, ucd, getAliasByUcd(ucd))
+ }
- axios.patch(`/api/product-contents/${pc.id}/`, { alias: value })
- .then(response => {
- })
- .catch(error => {
- })
+ const onChangeAlias = (pc, alias) => {
+ console.log("onChangeAlias: ", pc, alias)
+ changeProductContent(pc, null, alias)
}
- const handleCancelEdit = pc => {
- const updatedEditableFields = { ...editableFields }
- delete updatedEditableFields[pc.column_name]
- setEditableFields(updatedEditableFields)
+ const getAliasByUcd = (ucd) => {
+ const result = ucds.find(o => o.value === ucd);
+ return result ? result.name : null
}
- const createSelect = pc => {
- // Check Available Ucds and Current UCD when pc.ucd is not null
+ const getAvailableUcds = () => {
const avoptions = []
- let currentUcd = null
ucds.forEach(ucd => {
- if (usedUcds.indexOf(ucd.value) === -1 || ucd.value === pc.ucd) {
+ if (usedUcds.indexOf(ucd.value) === -1) {
avoptions.push(ucd)
}
- if (ucd.value === pc.ucd) {
- currentUcd = ucd
- }
})
+ return avoptions
+ }
- const isOptionSelected = pc.ucd !== null
+ const isInputTypeAlias = name => {
+ // Se name estiver no array de input type
+ // Entao Input é do tipo Alias.
+ if (inputsType.indexOf(name) === -1) {
+ return false
+ }
+ return true
+ }
- return (
-
- {isOptionSelected ? (
-
- onChangeUcd(pc, null)}>
-
-
-
- ),
- }}
- />
- ) : (
- <>
- {pc.column_name in editableFields ? (
-
- handleAlias(pc, e.target.value)}
- onBlur={() => {
- // console.log(`${pc.column_name}: ${editableFields[pc.column_name]}`)
- handleAlias(pc, editableFields[pc.column_name])
- }}
- onKeyPress={event => {
- if (event.key === 'Enter' || event.key === 'Tab') {
- handleAlias(pc, editableFields[pc.column_name])
- // console.log(`${pc.column_name}: ${editableFields[pc.column_name]}`)
- editFieldRefs.current[pc.column_name].blur()
- }
- }}
- InputProps={{
- endAdornment: (
-
- handleCancelEdit(pc)}>
-
-
-
- )
- }}
- inputRef={ref => {
- editFieldRefs.current[pc.column_name] = ref
- }}
- autoFocus
- />
-
- ) : (
-
- onChangeUcd(pc, e.target.value)}
- >
- {avoptions.map(ucd => (
-
- ))}
-
- handleAlias(pc, '')}
- onMouseDown={handleMouseDownPassword}
- >
-
-
-
- )}
- >
- )}
-
- )
+ const handleChangeInputType = column_name => {
+ if (inputsType.indexOf(column_name) === -1) {
+ inputsType.push(column_name)
+ } else {
+ inputsType.splice(inputsType.indexOf(column_name), 1);
+ }
+ loadContents(productId)
}
const createFields = pc => {
+
+ const avoptions = getAvailableUcds()
+
+ if (pc.ucd !== null || pc.alias !== null) {
+ return (
+ onClear(pc)} />
+ )
+ }
+
+ // Campo de Texto para Alias
+ if (isInputTypeAlias(pc.column_name) === true) {
+ return (
+
+ )
+ }
+
+ // Select para UCD
return (
-
-
-
-
- {createSelect(pc)}
-
+
)
}
+
const catchFormError = data => {
let msg =
'There was a failure, please try again later, if the problem persists, please contact support.'
@@ -289,7 +370,18 @@ export default function NewProductStep3({ productId, onNext, onPrev }) {
autoComplete="off"
>
{productColumns.map(pc => {
- return createFields(pc)
+
+ return (
+
+
+ {createFields(pc)}
+
+ )
})}
{formError !== '' && handleFormError()}
diff --git a/frontend/components/newProduct/Step3_copy.js b/frontend/components/newProduct/Step3_copy.js
new file mode 100644
index 0000000..a6227e6
--- /dev/null
+++ b/frontend/components/newProduct/Step3_copy.js
@@ -0,0 +1,362 @@
+import CloseIcon from '@mui/icons-material/Close'
+import EditIcon from '@mui/icons-material/Edit'
+import {
+ Alert,
+ Box,
+ Button,
+ FormControl,
+ Stack,
+ TextField,
+ Typography
+} from '@mui/material'
+import IconButton from '@mui/material/IconButton'
+import InputAdornment from '@mui/material/InputAdornment'
+import MenuItem from '@mui/material/MenuItem'
+import debounce from 'lodash/debounce'
+import PropTypes from 'prop-types'
+import React, { useCallback, useEffect, useState } from 'react'
+import { contentAssociation, getProductContents } from '../../services/product'
+import Loading from '../Loading'
+
+
+export default function InputUcd({ isLoading }) {
+
+ return (
+ theme.zIndex.drawer + 1 }}
+ open={isLoading}
+ >
+
+
+ )
+}
+InputUcd.propTypes = {
+ isLoading: PropTypes.bool.isRequired
+}
+
+export default function InputAlias({ }) {
+
+ return (
+ theme.zIndex.drawer + 1 }}
+ open={isLoading}
+ >
+
+
+ )
+}
+InputAlias.propTypes = {
+ isLoading: PropTypes.bool.isRequired
+}
+
+
+export default function NewProductStep3({ productId, onNext, onPrev }) {
+ const ucds = [
+ {
+ name: 'ID',
+ value: 'meta.id;meta.main'
+ },
+ {
+ name: 'RA',
+ value: 'pos.eq.ra;meta.main'
+ },
+ {
+ name: 'Dec',
+ value: 'pos.eq.dec;meta.main'
+ },
+ {
+ name: 'z',
+ value: 'src.redshift'
+ },
+ {
+ name: 'z_err',
+ value: 'stat.error;src.redshift'
+ },
+ {
+ name: 'z_flag',
+ value: 'stat.rank'
+ },
+ {
+ name: 'survey',
+ value: 'meta.curation'
+ }
+ ]
+
+ const [productColumns, setProductColumns] = React.useState([])
+ const [usedUcds, setUsedUcds] = React.useState([])
+ const [isLoading, setLoading] = useState(false)
+ const [formError, setFormError] = React.useState('')
+ const [editableFields, setEditableFields] = useState({})
+ // const editFieldRefs = useRef({})
+
+ const loadContents = React.useCallback(async () => {
+ setLoading(true)
+ try {
+ const response = await getProductContents(productId)
+ setProductColumns(response.results)
+
+ // const aliases = {}
+ // response.results.forEach(row => {
+ // if (row.alias) {
+ // aliases[row.column_name] = row.alias
+ // }
+ // })
+ // setEditableFields(aliases)
+
+ setLoading(false)
+ } catch (error) {
+ setLoading(false)
+ if (error.response && error.response.status === 500) {
+ catchFormError(error.response.data)
+ }
+ }
+ }, [productId])
+
+ useEffect(() => {
+ loadContents()
+ }, [loadContents])
+
+ useEffect(() => {
+ const useducds = []
+ productColumns.forEach(row => {
+ if (row.ucd !== null) {
+ useducds.push(row.ucd)
+ }
+ })
+ setUsedUcds(useducds)
+ }, [productColumns])
+
+ const handleSubmit = () => {
+ onNext(productId)
+ }
+ const handlePrev = () => {
+ onPrev(productId)
+ }
+
+ const onSelectUcd = (pc, value) => {
+ const ucd = ucds.find(o => o.value === value);
+ onChangeProductContent(pc, ucd.value, ucd.name)
+ }
+
+ // Using lodash debounce to Delay search by 600ms
+ // Exemplo: https://www.upbeatcode.com/react/how-to-use-lodash-in-react/
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ const delayedEdit = useCallback(
+ debounce((pc, alias) => onChangeProductContent(pc, null, alias), 600),
+ []
+ )
+
+ const onChangeAlias = (pc, alias) => {
+ // console.log('onChangeAlias: ', pc.column_name, value)
+ delayedEdit(pc, alias)
+ }
+
+ const onChangeProductContent = (pc, ucd, alias) => {
+ if (pc.ucd === ucd && pc.alias === alias) {
+ return
+ }
+ // setLoading(true)
+ contentAssociation(pc.id, ucd, alias)
+ .then(() => {
+ // setLoading(false)
+ loadContents(productId)
+ })
+ .catch(res => {
+ setLoading(false)
+ if (res.response.status === 500) {
+ catchFormError(res.response.data)
+ }
+ })
+ }
+
+ const handleEdit = (pc) => {
+ setEditableFields(prevState => ({
+ ...prevState,
+ [pc.column_name]: pc.value
+ }))
+ }
+
+ const handleCancelEdit = pc => {
+ console.log("handleCancelEdit: ", pc.column_name)
+ // const updatedEditableFields = { ...editableFields }
+ // delete updatedEditableFields[pc.column_name]
+ // setEditableFields(updatedEditableFields)
+ onChangeProductContent(pc, null, null)
+ }
+
+ const createSelect = pc => {
+ // Check Available Ucds and Current UCD when pc.ucd is not null
+ const avoptions = []
+ let currentUcd = null
+ ucds.forEach(ucd => {
+ if (usedUcds.indexOf(ucd.value) === -1 || ucd.value === pc.ucd) {
+ avoptions.push(ucd)
+ }
+ if (ucd.value === pc.ucd) {
+ currentUcd = ucd
+ }
+ })
+
+ const isOptionSelected = pc.ucd !== null
+
+ return (
+
+ {isOptionSelected ? (
+
+ onChangeProductContent(pc, null, null)}>
+
+
+
+ ),
+ }}
+ />
+ ) : (
+ <>
+ {pc.column_name in editableFields ? (
+
+ onChangeAlias(pc, e.target.value)}
+ // onBlur={(e) => {
+ // console.log("onBlur: ", `${pc.column_name}:${e.target.value}`)
+ // // console.log(`${pc.column_name}: ${editableFields[pc.column_name]}`)
+ // // onChangeAlias(pc, editableFields[pc.column_name])
+ // }}
+ // onKeyPress={event => {
+ // if (event.key === 'Enter') {
+ // console.log("onKeyPress Enter: ", `${pc.column_name}: ${editableFields[pc.column_name]}`)
+ // editFieldRefs.current[pc.column_name].blur()
+ // }
+ // }}
+ InputProps={{
+ endAdornment: (
+
+ handleCancelEdit(pc)}>
+
+
+
+ )
+ }}
+ // inputRef={ref => {
+ // editFieldRefs.current[pc.column_name] = ref
+ // }}
+ autoFocus
+ />
+
+ ) : (
+
+ onSelectUcd(pc, e.target.value)}
+ // onChange={e => onChangeProductContent(pc, e.target.value)}
+ >
+ {avoptions.map(ucd => (
+
+ ))}
+
+ handleEdit(pc)}
+ >
+
+
+
+ )}
+ >
+ )}
+
+ )
+ }
+
+ const createFields = pc => {
+ return (
+
+
+
+
+ {createSelect(pc)}
+
+ )
+ }
+
+ const catchFormError = data => {
+ let msg =
+ 'There was a failure, please try again later, if the problem persists, please contact support.'
+ if (data.error) {
+ msg = data.error
+ }
+ setFormError(msg)
+ }
+
+ const handleFormError = () => {
+ return (
+
+ {formError}
+
+ )
+ }
+
+ return (
+
+ {isLoading && }
+
+ Please associate the column names of your file with those expected by
+ the tool.
+
+
+ It is okay to leave columns unassociated.
+
+
+ Skip this step if the data is not tabular.
+
+
+
+ {productColumns.map(pc => {
+ return createFields(pc)
+ })}
+
+ {formError !== '' && handleFormError()}
+
+
+
+
+
+
+ )
+}
+
+NewProductStep3.propTypes = {
+ productId: PropTypes.number,
+ onNext: PropTypes.func.isRequired,
+ onPrev: PropTypes.func.isRequired
+}
diff --git a/frontend/services/product.js b/frontend/services/product.js
index 03ba81c..fdef827 100644
--- a/frontend/services/product.js
+++ b/frontend/services/product.js
@@ -162,10 +162,11 @@ export const getProductContents = product_id => {
.then(res => res.data)
}
-export const contentAssociation = (pc_id, ucd) => {
+export const contentAssociation = (pc_id, ucd, alias) => {
return api
.patch(`/api/product-contents/${pc_id}/`, {
- ucd: ucd === '' ? null : ucd
+ ucd: ucd === '' ? null : ucd,
+ alias: alias === '' ? null : alias
})
.then(res => res.data)
}