diff --git a/frontend/components/EmailField.js b/frontend/components/EmailField.js
new file mode 100644
index 0000000..7575be1
--- /dev/null
+++ b/frontend/components/EmailField.js
@@ -0,0 +1,53 @@
+import React, { useState, useEffect } from 'react'
+import TextField from '@mui/material/TextField'
+import PropTypes from 'prop-types'
+
+function EmailField({ initialValue = '', onEmailChange, onClearForm }) {
+ const [email, setEmail] = useState(initialValue)
+ const [isValidEmail, setIsValidEmail] = useState(true)
+
+ const handleEmailChange = event => {
+ const newEmail = event.target.value
+ setEmail(newEmail)
+ onEmailChange(newEmail)
+ }
+
+ const handleBlur = () => {
+ if (email.trim() !== '') {
+ validateEmail(email)
+ }
+ }
+
+ const validateEmail = value => {
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
+ const isValid = emailRegex.test(value)
+ setIsValidEmail(isValid)
+ }
+
+ useEffect(() => {
+ setEmail(initialValue)
+ setIsValidEmail(true)
+ }, [onClearForm, initialValue])
+
+ return (
+
+
+
+ )
+}
+
+EmailField.propTypes = {
+ initialValue: PropTypes.string,
+ onEmailChange: PropTypes.func,
+ onClearForm: PropTypes.func
+}
+
+export default EmailField
diff --git a/frontend/components/SearchRadius.js b/frontend/components/SearchRadius.js
new file mode 100644
index 0000000..ee635af
--- /dev/null
+++ b/frontend/components/SearchRadius.js
@@ -0,0 +1,47 @@
+import React, { useState, useEffect } from 'react'
+import TextField from '@mui/material/TextField'
+import PropTypes from 'prop-types'
+
+const SearchRadius = ({ searchRadius, onChange, reset }) => {
+ const formatSearchRadius = value => {
+ if (/^\d+\.\d*$/.test(value)) {
+ return value
+ } else {
+ return value.replace(/[^\d.]/g, '')
+ }
+ }
+
+ const [localSearchRadius, setLocalSearchRadius] = useState(
+ formatSearchRadius(searchRadius)
+ )
+
+ useEffect(() => {
+ setLocalSearchRadius(formatSearchRadius(searchRadius))
+ }, [reset, searchRadius])
+
+ const handleRadiusChange = event => {
+ const inputValue = event.target.value
+
+ if (/^\d+(\.\d*)?$/.test(inputValue)) {
+ setLocalSearchRadius(inputValue)
+ onChange(event)
+ }
+ }
+
+ return (
+
+ )
+}
+
+SearchRadius.propTypes = {
+ searchRadius: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
+ onChange: PropTypes.func,
+ reset: PropTypes.bool
+}
+
+export default SearchRadius
diff --git a/frontend/components/SpeczData.js b/frontend/components/SpeczData.js
index 9a23f24..905983d 100644
--- a/frontend/components/SpeczData.js
+++ b/frontend/components/SpeczData.js
@@ -1,3 +1,5 @@
+import * as React from 'react'
+import { getProducts } from '../services/product'
import { DataGrid } from '@mui/x-data-grid'
import moment from 'moment'
import { Box } from '@mui/material'
@@ -30,13 +32,29 @@ const columns = [
}
]
+async function fetchData(filters, query) {
+ try {
+ const response = await getProducts({
+ filters,
+ page: 0,
+ page_size: 25,
+ sort: [{ field: 'created_at', sort: 'desc' }],
+ search: query
+ })
+
+ return response.results
+ } catch (error) {
+ console.error(error)
+ throw error
+ }
+}
+
function DataTable({ rows }) {
return (
-
+
row.id}
pageSizeOptions={[5, 10]}
checkboxSelection
/>
@@ -48,39 +66,33 @@ DataTable.propTypes = {
rows: PropTypes.arrayOf(PropTypes.object).isRequired
}
-const rows = [
- {
- id: 1,
- display_name: 'Jandson 1',
- uploaded_by: 'User1',
- created_at: '2023-01-01'
- },
- {
- id: 2,
- display_name: 'Jandson 2',
- uploaded_by: 'User2',
- created_at: '2023-02-15'
- },
- {
- id: 3,
- display_name: 'Jandson 3',
- uploaded_by: 'User3',
- created_at: '2023-03-22'
- },
- {
- id: 4,
- display_name: 'Jandson V',
- uploaded_by: 'User1',
- created_at: '2023-04-10'
- },
- {
- id: 5,
- display_name: 'Jandson Try',
- uploaded_by: 'User2',
- created_at: '2023-05-05'
- }
-]
+function DataTableWrapper({ filters, query }) {
+ const [rows, setRows] = React.useState([])
+
+ React.useEffect(() => {
+ const fetchAndSetData = async () => {
+ try {
+ const data = await fetchData(filters, query)
+ setRows(data)
+ } catch (error) {
+ console.error(error)
+ }
+ }
+
+ fetchAndSetData()
+ }, [filters, query])
-export default function App() {
return
}
+
+DataTableWrapper.propTypes = {
+ filters: PropTypes.object,
+ query: PropTypes.string
+}
+
+DataTableWrapper.defaultProps = {
+ filters: {},
+ query: ''
+}
+
+export default DataTableWrapper
diff --git a/frontend/components/TsmData.js b/frontend/components/TsmData.js
index eceffca..8a4acfe 100644
--- a/frontend/components/TsmData.js
+++ b/frontend/components/TsmData.js
@@ -1,3 +1,5 @@
+import * as React from 'react'
+import { getProducts } from '../services/product'
import { DataGrid } from '@mui/x-data-grid'
import moment from 'moment'
import { Box } from '@mui/material'
@@ -30,15 +32,27 @@ const columns = [
}
]
+async function fetchData(filters, query) {
+ try {
+ const response = await getProducts({
+ filters,
+ page: 0,
+ page_size: 25,
+ sort: [{ field: 'created_at', sort: 'desc' }],
+ search: query
+ })
+
+ return response.results
+ } catch (error) {
+ console.error(error)
+ throw error
+ }
+}
+
function DataTable({ rows }) {
return (
-
- row.id}
- pageSizeOptions={[5, 10]}
- />
+
+
)
}
@@ -47,39 +61,33 @@ DataTable.propTypes = {
rows: PropTypes.arrayOf(PropTypes.object).isRequired
}
-const rows = [
- {
- id: 1,
- display_name: 'Jandson 1',
- uploaded_by: 'User1',
- created_at: '2023-01-01'
- },
- {
- id: 2,
- display_name: 'Jandson 2',
- uploaded_by: 'User2',
- created_at: '2023-02-15'
- },
- {
- id: 3,
- display_name: 'Jandson 3',
- uploaded_by: 'User3',
- created_at: '2023-03-22'
- },
- {
- id: 4,
- display_name: 'Jandson V',
- uploaded_by: 'User1',
- created_at: '2023-04-10'
- },
- {
- id: 5,
- display_name: 'Jandson Try',
- uploaded_by: 'User2',
- created_at: '2023-05-05'
- }
-]
+function DataTableWrapper({ filters, query }) {
+ const [rows, setRows] = React.useState([])
+
+ React.useEffect(() => {
+ const fetchAndSetData = async () => {
+ try {
+ const data = await fetchData(filters, query)
+ setRows(data)
+ } catch (error) {
+ console.error(error)
+ }
+ }
+
+ fetchAndSetData()
+ }, [filters, query])
-export default function App() {
return
}
+
+DataTableWrapper.propTypes = {
+ filters: PropTypes.object,
+ query: PropTypes.string
+}
+
+DataTableWrapper.defaultProps = {
+ filters: {},
+ query: ''
+}
+
+export default DataTableWrapper
diff --git a/frontend/pages/specz_catalogs.js b/frontend/pages/specz_catalogs.js
index b24392f..48b14d4 100644
--- a/frontend/pages/specz_catalogs.js
+++ b/frontend/pages/specz_catalogs.js
@@ -1,47 +1,204 @@
-import React from 'react'
-import { Typography, Box } from '@mui/material'
-import Breadcrumbs from '@mui/material/Breadcrumbs'
-import Link from '@mui/material/Link'
+import InfoIcon from '@mui/icons-material/Info'
+import Box from '@mui/material/Box'
+import Button from '@mui/material/Button'
+import Card from '@mui/material/Card'
+import CardContent from '@mui/material/CardContent'
import Grid from '@mui/material/Grid'
import IconButton from '@mui/material/IconButton'
-import InfoIcon from '@mui/icons-material/Info'
-import ArrowBackIos from '@mui/icons-material/ArrowBackIos'
+import Link from '@mui/material/Link'
+import Breadcrumbs from '@mui/material/Breadcrumbs'
+import MenuItem from '@mui/material/MenuItem'
+import Paper from '@mui/material/Paper'
+import Select from '@mui/material/Select'
+import Snackbar from '@mui/material/Snackbar'
+import SnackbarContent from '@mui/material/SnackbarContent'
+import TextField from '@mui/material/TextField'
+import Typography from '@mui/material/Typography'
+import React, { useState } from 'react'
+import EmailField from '../components/EmailField'
+import SearchField from '../components/SearchField'
+import SearchRadius from '../components/SearchRadius'
+import SpeczData from '../components/SpeczData'
+import { useTheme } from '@mui/system'
function SpeczCatalogs() {
+ const theme = useTheme()
+
+ const [combinedCatalogName, setCombinedCatalogName] = useState('')
+ const [search, setSearch] = React.useState('')
+ const filters = React.useState()
+ const [searchRadius, setSearchRadius] = useState('1.0')
+ const [selectedOption, setSelectedOption] = useState('keepAll')
+ const [email, setEmail] = useState('')
+ const [snackbarOpen, setSnackbarOpen] = useState(false)
+
+ const handleCatalogNameChange = event => {
+ setCombinedCatalogName(event.target.value)
+ }
+
+ const handleSearchRadiusChange = event => {
+ const newValue = parseFloat(event.target.value)
+ setSearchRadius(isNaN(newValue) ? '' : newValue.toString())
+ }
+
+ const handleEmailChange = newEmail => {
+ setEmail(newEmail)
+ }
+
+ const handleClearForm = () => {
+ setCombinedCatalogName('')
+ setSearchRadius('1.0')
+ setSelectedOption('keepAll')
+ setEmail('')
+ }
+
+ const handleRun = () => {
+ setSnackbarOpen(true)
+ }
+
+ const handleSnackbarClose = () => {
+ setSnackbarOpen(false)
+ }
+
+ const styles = {
+ root: {
+ transition: 'box-shadow 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms',
+ borderRadius: '4px',
+ padding: theme.spacing(3),
+ flex: '1 1 0%'
+ }
+ }
+
return (
-
-
-
- Home
-
-
- Pipelines
-
- Combine Spec-z Catalogs
-
-
-
- window.history.back()}
- >
-
-
- Combine Spec-z Catalogs
-
-
-
-
-
-
- Coming soon...
-
-
+
+
+
+
+
+ Home
+
+
+ Pipelines
+
+ Combine Spec-z Catalogs
+
+
+
+ Combine Spec-z Catalogs
+
+
+
+
+
+
+
+
+ 1. Combined catalog name:
+
+
+
+
+
+
+
+
+
+
+ 2. Select the Spec-z Catalogs to include in your sample:
+
+ setSearch(query)} />
+
+
+
+
+
+
+
+
+
+
+
+
+ 3. Select the cross-matching configuration choices:
+
+
+
+
+ Search Radius (arcsec):{' '}
+
+
+
+
+
+ In case of multiple spec-z measurements for the same object:
+ {' '}
+
+
+
+
+
+ 4. Enter an email address to be notified when the process is
+ complete (opcional):
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
)
}
diff --git a/frontend/pages/training_set_maker.js b/frontend/pages/training_set_maker.js
index c261d08..eca29d7 100644
--- a/frontend/pages/training_set_maker.js
+++ b/frontend/pages/training_set_maker.js
@@ -1,47 +1,241 @@
-import React from 'react'
-import { Typography, Box } from '@mui/material'
+import InfoIcon from '@mui/icons-material/Info'
+import Box from '@mui/material/Box'
+import Button from '@mui/material/Button'
+import Card from '@mui/material/Card'
+import CardContent from '@mui/material/CardContent'
+import Grid from '@mui/material/Grid'
import Breadcrumbs from '@mui/material/Breadcrumbs'
import Link from '@mui/material/Link'
-import Grid from '@mui/material/Grid'
import IconButton from '@mui/material/IconButton'
-import InfoIcon from '@mui/icons-material/Info'
-import ArrowBackIos from '@mui/icons-material/ArrowBackIos'
+import MenuItem from '@mui/material/MenuItem'
+import Paper from '@mui/material/Paper'
+import Select from '@mui/material/Select'
+import Snackbar from '@mui/material/Snackbar'
+import SnackbarContent from '@mui/material/SnackbarContent'
+import TextField from '@mui/material/TextField'
+import Typography from '@mui/material/Typography'
+import React, { useState } from 'react'
+import EmailField from '../components/EmailField'
+import SearchField from '../components/SearchField'
+import SearchRadius from '../components/SearchRadius'
+import TsmData from '../components/TsmData'
+import { useTheme } from '@mui/system'
function TrainingSetMaker() {
+ const theme = useTheme()
+
+ const [combinedCatalogName, setCombinedCatalogName] = useState('')
+ const [search, setSearch] = React.useState('')
+ const filters = React.useState()
+ const [searchRadius, setSearchRadius] = useState('1.0')
+ const [selectedOption, setSelectedOption] = useState('pickOne')
+ const [email, setEmail] = useState('')
+ const [snackbarOpen, setSnackbarOpen] = useState(false)
+ const [selectedLsstCatalog, setSelectedLsstCatalog] = useState('DP0.2')
+
+ const handleCatalogNameChange = event => {
+ setCombinedCatalogName(event.target.value)
+ }
+
+ const handleSearchRadiusChange = event => {
+ const newValue = parseFloat(event.target.value)
+ setSearchRadius(isNaN(newValue) ? '' : newValue.toString())
+ }
+
+ const handleLsstCatalogChange = event => {
+ setSelectedLsstCatalog(event.target.value)
+ }
+
+ const handleEmailChange = newEmail => {
+ setEmail(newEmail)
+ }
+
+ const handleClearForm = () => {
+ setCombinedCatalogName('')
+ setSearchRadius('1.0')
+ setSelectedOption('pickOne')
+ setEmail('')
+ setSelectedLsstCatalog('DP0.2')
+ }
+
+ const handleRun = () => {
+ setSnackbarOpen(true)
+ }
+
+ const handleSnackbarClose = () => {
+ setSnackbarOpen(false)
+ }
+
+ const styles = {
+ root: {
+ transition: 'box-shadow 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms',
+ borderRadius: '4px',
+ padding: theme.spacing(3),
+ flex: '1 1 0%'
+ }
+ }
+
return (
-
-
-
- Home
-
-
- Pipelines
-
- Training Set Maker
-
-
-
- window.history.back()}
- >
-
-
- Training Set Maker
-
-
-
-
-
-
- Coming soon...
-
-
+
+
+
+
+
+ Home
+
+
+ Pipelines
+
+ Training Set Maker
+
+
+
+ Training Set Maker
+
+
+
+
+
+
+
+
+
+ 1. Combined catalog name:
+
+
+
+
+
+
+
+
+
+
+
+ 2. Select the Spec-z Catalogs to include in your sample:
+
+ setSearch(query)} />
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 3. Select the LSST objects catalog:
+
+
+
+
+
+
+ 4. Select the cross-matching configuration choices:
+
+ Search Radius (arcsec):{' '}
+
+
+
+ n neighbors:{' '}
+
+
+
+
+ In case of multiple spec-z measurements for the same object:
+ {' '}
+
+
+
+
+
+
+
+ 5. Enter an email address to be notified when the process is
+ complete (opcional):
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
)
}