US-RSE Tutorial
October 9, 2024
This is a follow along guide to the US-RSE tutorial conducted over Zoom. Use this guide to follow along with all of the code edits made live during the tutorial demonstration.
Helpful Links
- StackBlitz Code Starter
- StackBlitz Code Live In Progress
- Slides
- GBIF API Documentation
- GBIF Occurrence Endpoint Example
- Material UI Documentation
- React Cheatsheet
Configuring a STRUDEL Task Flow
Each Task Flow is configured inside of its own taskflow.config.ts
file. We will be configuring the Explore Data Task Flow which has already been included in this project.
You can find the configuration file at src/pages/explore-data/_config/taskflow.config.ts
1. Update the data.list
object
list: {
source: "https://api.gbif.org/v1/occurrence/search",
staticParams: null,
idField: "key",
queryMode: "server",
}
2. Update the data.detail
object
detail: {
source: "https://api.gbif.org/v1/occurrence",
staticParams: null,
idField: "key",
queryMode: "server",
}
3. Update page titles in the pages.index
object
{
pages: {
index: {
title: "Biodiversity Explorer",
description: "Explore species observations around the world.",
...
}
}
}
4. Update the column definitions in pages.index.tableColumns
tableColumns: [
{
field: "scientificName",
headerName: "Name",
width: 200
},
{
field: "year",
headerName: "Year",
width: 150
},
{
field: "basisOfRecord",
headerName: "Basis of Record",
width: 150
},
{
field: "elevation",
headerName: "Elevation",
width: 150,
type: 'number'
}
],
5. Update the filter definitions in pages.index.tableFilters
tableFilters: [
{
field: "elevation",
label: "Elevation",
paramType: "array-string",
filterComponent: "RangeSlider",
filterProps: {
min: 0,
max: 100
}
},
{
field: "basisOfRecord",
label: "Basis of Record",
paramType: 'repeated',
filterComponent: "CheckboxList",
filterProps: {
options: [
{
label: "Preserved Specimen",
value: "PRESERVED_SPECIMEN"
},
{
label: "Fossil Specimen",
value: "FOSSIL_SPECIMEN"
},
{
label: "Living Specimen",
value: "LIVING_SPECIMEN"
},
{
label: "Observation",
value: "OBSERVATION"
},
{
label: "Human Observation",
value: "HUMAN_OBSERVATION"
},
{
label: "Machine Observation",
value: "MACHINE_OBSERVATION"
}
]
}
},
]
Customizing the Theme
Theming is handled by Material UI's theme object.
You can modify global theme variables in src/theme.tsx
.
1. Change palette.mode
to dark
mode: 'dark',
2. Change the palette.background
colors
background: {
default: '#222',
paper: '#333',
},
3. Change the palette.primary
colors
primary: {
main: '#5dffe2',
// Exclude light, dark, or contrastText to have them
// calculated automatically based on the main color.
light: '#99ffec',
dark: '#00e0b7',
// contrastText: '#fff',
},
4. Change the shape.borderRadius
borderRadius: 0,
5. Change the primary font in typography.fontFamily
fontFamily: `"Avenir", "Verdana", "Arial", sans-serif`,
React Basics
Before we start customizing the Explore Data template, we will cover some basics of React and Material UI components.
You may find it helpful to reference the React syntax cheatsheet during this section.
1. Make a new folder and file
Create a new folder inside of src/pages
called hello-world
.
Then, create a file inside hello-world
called index.tsx
src
├── pages
│ ├── hello-world
│ │ ├── index.tsx
2. Create a HelloWorldPage
component
const HelloWorldPage: React.FC = () => {
return (
<div>
Hello World!
</div>
);
};
export default HelloWorldPage;
3. Make a new _components
folder and component file
Create a new folder inside of hello-world
called _components
.
Then, create a file inside _components
called TagList.tsx
.
src
├── pages
│ ├── hello-world
│ │ ├── _components
│ │ │ ├── TagList.tsx
│ │ ├── index.tsx
4. Create a TagList
component
export const TagList: React.FC = () => {
return (
<ul>
<li>Animalia</li>
<li>Chordata</li>
<li>Mammalia</li>
</ul>
)
}
5. Import and use the TagList
component in HelloWorldPage
import { TagList } from './_components/TagList';
const HelloWorldPage: React.FC = () => {
return (
<div>
Hello World!
<TagList />
</div>
);
};
export default HelloWorldPage;
6. Add a tags
prop to the TagList
component
interface TagListProps {
tags: string[];
}
export const TagList: React.FC<TagListProps> = ({ tags }) => {
return (
<ul>
<li>Animalia</li>
<li>Chordata</li>
<li>Mammalia</li>
</ul>
)
}
7. Loop through tags
to render each item
export const TagList: React.FC<TagListProps> = ({ tags }) => {
return (
<ul>
{tags.map((tag) => (
<li key={tag}>{tag}</li>
))}
</ul>
)
}
8. Pass values to the tags
prop on HelloWorldPage
const HelloWorldPage: React.FC = () => {
return (
<div>
Hello World!
<TagList tags={['Animalia', 'Chordata', 'Mammalia']} />
</div>
);
};
Material UI Basics
Material UI is included in the STRUDEL application by default. It contains many useful components for reusable elements and patterns throughout a web user interface.
See more in the Materials UI Docs.
1. Import the Chip
component to TagList.tsx
import { Chip } from '@mui/material';
2. Replace the li
elements with Chip
components
export const TagList: React.FC<TagListProps> = ({ tags }) => {
return (
<ul>
{tags.map((tag) => (
<Chip key={tag} label={tag} />
))}
</ul>
)
}
3. Import the Stack
component to TagList.tsx
import { Chip, Stack } from '@mui/material';
4. Replace the ul
element with the Stack
component
export const TagList: React.FC<TagListProps> = ({ tags }) => {
return (
<Stack direction="row" spacing={1}>
{tags.map((tag) => (
<Chip key={tag} label={tag} />
))}
</Stack>
)
}
5. Import the Typography
component to index.tsx
import { Typography } from '@mui/material';
6. Wrap the title text with the Typography
component
const HelloWorldPage: React.FC = () => {
return (
<div>
<Typography variant="h3" component="h1">
Hello World!
</Typography>
<TagList tags={['Animalia', 'Chordata', 'Mammalia']} />
</div>
);
};
7. Import the Container
component to index.tsx
import { Container, Typography } from '@mui/material';
6. Replace the div
element with the Container
component
const HelloWorldPage: React.FC = () => {
return (
<Container maxWidth="sm">
<Typography variant="h3" component="h1">
Hello World!
</Typography>
<TagList tags={['Animalia', 'Chordata', 'Mammalia']} />
</Container>
);
};
7. Use the sx
prop to style Typography
<Typography
variant="h3"
component="h1"
sx={{
borderBottom: '1px solid',
borderBottomColor: 'primary.main',
marginBottom: 2,
paddingBottom: 2,
}}
>
Hello World!
</Typography>
Customizing the Task Flow
Now we will utilize the component we made in the preview panel and add some more custom data to the panel.
For this exercise we will be working inside of src/pages/explore-data/_components_/PreviewPanel.tsx
1. Import the TagList
component to PreviewPanel.tsx
import { TagList } from '../../hello-world/_components/TagList';
2. Replace the row description with a TagList
Replace:
<Typography variant="body2">Row description, subtitle, or helper text.</Typography>
With:
<TagList
tags={[
previewItem.kingdom,
previewItem.phylum,
previewItem.class,
previewItem.order,
]}
/>
3. Add another TagList
directly after the first
<TagList
tags={[previewItem.family, previewItem.genus, previewItem.species]}
/>
4. Replace Property Group 1 with Location data
<Box>
<Typography fontWeight="medium" mb={1}>
Location
</Typography>
<LabelValueTable
rows={[
{ label: 'Continent', value: previewItem.continent },
{ label: 'Country', value: previewItem.country },
{ label: 'Municipality', value: previewItem.municipality },
]}
/>
</Box>
4. Replace Property Group 2 with Record data
<Box>
<Typography fontWeight="medium" mb={1}>
Record
</Typography>
<LabelValueTable
rows={[
{ label: 'Basis of Record', value: previewItem.basisOfRecord },
{ label: 'Protocol', value: previewItem.protocol },
{ label: 'Status', value: previewItem.occurrenceStatus },
]}
/>
</Box>