Skip to content

Commit

Permalink
multiple custom imaging columns
Browse files Browse the repository at this point in the history
  • Loading branch information
nmcardoso committed Feb 29, 2024
1 parent 45d420a commit 9ed133f
Show file tree
Hide file tree
Showing 5 changed files with 196 additions and 88 deletions.
2 changes: 2 additions & 0 deletions components/xtable/ClassTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,8 @@ export default function ClassTab() {

<CategoricalControl />

<hr className='my-4' />

<Form
className="mt-3"
onSubmit={handleDownload}>
Expand Down
191 changes: 122 additions & 69 deletions components/xtable/CustomImagingTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,111 @@ import Row from 'react-bootstrap/Row'
import InputGroup from 'react-bootstrap/InputGroup'
import { useContext } from 'react'
import { useXTableConfig } from '../../contexts/XTableConfigContext'
import { Button } from 'react-bootstrap'
import { BiPlus } from 'react-icons/bi'
import { HiMinusSm } from 'react-icons/hi'
import Help from '../common/Help'

const CustomImagingColumnGroup = ({ index }: { index: number }) => {
const { tcState, tcDispatch } = useXTableConfig()
const custom = tcState.customImaging.columns[index]

return (
<>
<Row>
<Col sm={8}>
<div className="d-flex align-items-center">
<InputGroup className="mb-2" size="sm">
<InputGroup.Text>
Base URL
</InputGroup.Text>
<Form.Control
value={custom.url}
onChange={e => tcDispatch({
type: 'updateCustomImaging',
payload: { index, url: e.target.value }
})}
/>
</InputGroup>
<Help title="Base Resource URL" className="mb-2 ms-1">
The <b>base resource url</b> is the first (static) part of the URL.
This value must starts with <code>http://</code>{" "}
or <code>https://</code><br />
The final url for each row is:<br />
<kbd>Base URL</kbd> + <kbd>RI Column</kbd> + <kbd>suffix</kbd>
</Help>
</div>
</Col>

<Col sm={4}>
<div className="d-flex align-items-center">
<InputGroup size="sm">
<InputGroup.Text>Suffix</InputGroup.Text>
<Form.Control
value={custom.fileExtension}
onChange={e => tcDispatch({
type: 'updateCustomImaging',
payload: { index, fileExtension: e.target.value }
})}
/>
</InputGroup>
<Help title="URL Suffix" className="ms-1">
The <b>url suffix</b> is the last (static) part of the URL and {" "}
is used to specify the file extension, for example.<br />
The final url for each row is:<br />
<kbd>Base URL</kbd> + <kbd>RI Column</kbd> + <kbd>suffix</kbd>
</Help>
</div>
</Col>
</Row>

<Row>
<Col sm={8}>
<div className="d-flex align-items-center">
<InputGroup className="" size="sm">
<InputGroup.Text>RI Column</InputGroup.Text>
<Form.Select
defaultValue={-1}
onChange={e => tcDispatch({
type: 'updateCustomImaging',
payload: { index, columnIndex: (parseInt(e.target.value)) }
})}>
<option value={-1}>Select a column</option>
{tcState.table.columns.map((colName, idx) => (
<option
value={idx}
key={idx}>
{colName}
</option>
))}
</Form.Select>
</InputGroup>
<Help title="Resource Identification Column" className=" ms-1">
The <b>resource identification column</b> (RI column) is the {" "}
only variable part of the url. This field must specify the {" "}
column to use to make a specific url for each row.<br />
The final url for each row is:<br />
<kbd>Base URL</kbd> + <kbd>RI Column</kbd> + <kbd>suffix</kbd>
</Help>
</div>
</Col>

<Col sm={4}>
<Button
variant="outline-danger"
size="sm"
onClick={() => tcDispatch({
type: 'removeCustomImaging',
payload: { index, prevColumns: tcState.customImaging.columns }
})}
>
<HiMinusSm /> Remove Column
</Button>
</Col>
</Row>
</>
)
}

export default function CustomImagingTab() {
const { tcState, tcDispatch } = useXTableConfig()
Expand All @@ -21,85 +126,33 @@ export default function CustomImagingTab() {
label="Show Custom Images Column"
checked={custom.enabled}
onChange={e => tcDispatch({
type: 'setCustomImaging',
type: 'enableCustomImaging',
payload: { enabled: e.target.checked }
})}
/>
</Col>
</Form.Group>

<Row>
<Col sm={6}>
<InputGroup className="mb-3">
<InputGroup.Text id="customImagingUrl">
URL
</InputGroup.Text>
<Form.Control
aria-label="URL"
aria-describedby="customImagingUrl"
value={custom.url}
onChange={e => tcDispatch({
type: 'setCustomImaging',
payload: { url: e.target.value }
})}
/>
</InputGroup>
</Col>
</Row>
{custom.columns.map((_, i) => (
<>
<CustomImagingColumnGroup index={i} />
<hr className="my-4" />
</>
))}

<Row>
<Col sm={6}>
<InputGroup className="mb-3">
<InputGroup.Text>Column</InputGroup.Text>
<Form.Select
defaultValue={-1}
onChange={e => tcDispatch({
type: 'setCustomImaging',
payload: { columnIndex: (parseInt(e.target.value)) }
})}>
<option value={-1}>Select a column</option>
{tcState.table.columns.map((colName, index) => (
<option
value={index}
key={index}>
{colName}
</option>
))}
</Form.Select>
</InputGroup>
</Col>
</Row>

<Row>
<Col sm={4}>
<InputGroup>
<InputGroup.Text>File Extension</InputGroup.Text>
<Form.Select
value={custom.fileExtension}
onChange={e => tcDispatch({
type: 'setCustomImaging',
payload: { fileExtension: e.target.value }
})}>
<option value="">None</option>
<option value=".jpg">.jpg</option>
<option value=".jpeg">.jpeg</option>
<option value=".png">.png</option>
<option value=".gif">.gif</option>
<option value=".svg">.svg</option>
<option value=".webp">.webp</option>
<option value=".bmp">.bmp</option>
<option value=".tif">.tif</option>
<option value=".tiff">.tiff</option>
<option value=".apng">.apng</option>
<option value=".avif">.avif</option>
<option value=".jfif">.jfif</option>
<option value=".pjpeg">.pjpeg</option>
<option value=".pjp">.pjp</option>
</Form.Select>
</InputGroup>
<Col>
<Button
size="sm"
onClick={() => tcDispatch({
type: 'addCustomImaging',
payload: { prevColumns: tcState.customImaging.columns }
})}
>
<BiPlus size={16} /> Add Custom Imaging Column
</Button>
</Col>
</Row>

</>
)
}
25 changes: 18 additions & 7 deletions components/xtable/XTableBody.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ const columnsAccessors = {
zoomHeight={460} />,
header: 'S-PLUS'
}),
customImaging: () => columnHelper.accessor('customImaging', {
customImaging: (i: number) => columnHelper.accessor(`customImaging:${i}`, {
cell: info =>
<ImageCell
src={info.getValue()}
Expand Down Expand Up @@ -113,8 +113,8 @@ export default function XTableBody() {
[columnsAccessors.legacyImaging(tdState.schema.legacyImaging.pixelScale)] : []
const splusImagingCol = tdState.schema.splusImaging ?
[columnsAccessors.splusImaging()] : []
const customImagingCol = tdState.schema.customImaging ?
[columnsAccessors.customImaging()] : []
// const customImagingCol = tdState.schema.customImaging ?
// [columnsAccessors.customImaging()] : []
const classificationCol = tdState.schema.classification ?
[columnsAccessors.classification()] : []
const sdssSpectraCol = tdState.schema.sdssSpectra ?
Expand All @@ -126,6 +126,12 @@ export default function XTableBody() {
[columnsAccessors.splusPhotoSpectra()] : []
const nearbyRedshiftsCol = tdState.schema.nearbyRedshifts ?
[columnsAccessors.nearbyRedshifts()] : []
const customImagingCol = []
if (tdState.schema.customImaging.enabled) {
for (let i = 0; i < tdState.schema.customImaging.nCols; i++) {
customImagingCol.push(columnsAccessors.customImaging(i))
}
}
return [
...classificationCol, ...sourceTableCol, ...sdssCatalog,
...nearbyRedshiftsCol, ...splusPhotoSpectraCol, ...sdssSpectraCol,
Expand Down Expand Up @@ -169,7 +175,11 @@ export default function XTableBody() {
pixelScale: tcState.legacyImaging.pixelScale
},
splusImaging: !!tcState.splusImaging.enabled,
customImaging: !!tcState.customImaging.enabled,
// customImaging: !!tcState.customImaging.enabled,
customImaging: {
enabled: !!tcState.customImaging.enabled,
nCols: tcState.customImaging.columns.length
},
classification: tcState.classification.enabled,
sdssSpectra: tcState.sdssSpectra.enabled,
splusPhotoSpectra: tcState.splusPhotoSpectra.enabled,
Expand Down Expand Up @@ -214,9 +224,10 @@ export default function XTableBody() {

// custom imaging column
if (schema.customImaging) {
const refRow = src[i + 1][tcState.customImaging.columnIndex]
const filePath = `${refRow}${tcState.customImaging.fileExtension}`
row.customImaging = new URL(filePath, tcState.customImaging.url)
tcState.customImaging.columns.forEach((col, colId) => {
const refRow = src[i + 1][col.columnIndex]
row[`customImaging:${colId}`] = `${col.url}${refRow}${col.fileExtension}`
})
}

// classification column
Expand Down
62 changes: 52 additions & 10 deletions contexts/XTableConfigContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,17 @@ interface IStampModal extends IterableInterface {
showPetroFluxRadius: boolean,
}

interface ICustomImaging extends IterableInterface {
enabled: boolean,
interface ICustomImagingColumn extends IterableInterface {
url: string,
fileExtension: string,
columnIndex: number,
}

interface ICustomImaging extends IterableInterface {
enabled: boolean,
columns: ICustomImagingColumn[],
}

export interface IState {
schemaVersion: number,
table: ITableConfig,
Expand All @@ -103,7 +107,7 @@ export interface IState {
customImaging: ICustomImaging,
}

export const SCHEMA_VERSION: number = 6
export const SCHEMA_VERSION: number = 7

const getInitialState = (): IState => ({
schemaVersion: SCHEMA_VERSION,
Expand Down Expand Up @@ -172,9 +176,13 @@ const getInitialState = (): IState => ({
},
customImaging: {
enabled: false,
url: '',
fileExtension: '',
columnIndex: -1,
columns: [
{
url: '',
fileExtension: '',
columnIndex: -1,
}
]
}
})
const initialState = getInitialState()
Expand Down Expand Up @@ -294,15 +302,43 @@ const setStampModal = (state: IState, action: IAction<IStampModal>) => {
return s
}

const setCustomImaging = (state: IState, action: IAction<ICustomImaging>) => {
const addCustomImaging = (state: IState, action: IAction<{ prevColumns: ICustomImagingColumn[] }>) => {
const s = { ...state }
s.customImaging.columns = [
...action.payload.prevColumns,
{
url: '',
fileExtension: '',
columnIndex: -1
}
]
persistStateAsync(s)
return s
}

const updateCustomImaging = (state: IState, action: IAction<ICustomImagingColumn & { index: number }>) => {
const s = { ...state }
for (const k in action.payload) {
s.customImaging[k] = action.payload[k]
s.customImaging.columns[action.payload.index][k] = action.payload[k]
}
persistStateAsync(s)
return s
}

const removeCustomImaging = (state: IState, action: IAction<{ index: number, prevColumns: ICustomImagingColumn[] }>) => {
const s = { ...state }
s.customImaging.columns = action.payload.prevColumns.filter((_, i) => i != action.payload.index)
persistStateAsync(s)
return s
}

const enableCustomImaging = (state: IState, action: IAction<{ enabled: boolean }>) => {
const s = { ...state }
s.customImaging.enabled = action.payload.enabled
persistStateAsync(s)
return s
}

type PayloadType = IState | ITrilogyConfig | ISplusImaging | ILuptonConfig
| ITableConfig | IClassification | ILegacyImaging | ISdssSpectra
| ISdssCatalog | ISplusPhotoSpectra
Expand Down Expand Up @@ -333,8 +369,14 @@ const reducer = (state: IState, action: IAction<any>) => {
return setNearbyRedshifts(state, action)
case 'setStampModal':
return setStampModal(state, action)
case 'setCustomImaging':
return setCustomImaging(state, action)
case 'addCustomImaging':
return addCustomImaging(state, action)
case 'updateCustomImaging':
return updateCustomImaging(state, action)
case 'removeCustomImaging':
return removeCustomImaging(state, action)
case 'enableCustomImaging':
return enableCustomImaging(state, action)
default:
console.log(`Action ${action.type} not found`)
return { ...state }
Expand Down
Loading

0 comments on commit 9ed133f

Please sign in to comment.