finished implementing the custom grain functionality on the grains page and the basic desktop view, and also am now using permissions to disable the buttons ro add/update/remove
This commit is contained in:
parent
2f8897d8ed
commit
586c971795
4 changed files with 244 additions and 21 deletions
2
package-lock.json
generated
2
package-lock.json
generated
|
|
@ -10953,7 +10953,7 @@
|
||||||
},
|
},
|
||||||
"node_modules/protobuf-ts": {
|
"node_modules/protobuf-ts": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#2aa771366c36285eac26e4e0143c1759380e2fc9",
|
"resolved": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#917c54113cbb7e14d5037a647b9f6784bf3a8aad",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"protobufjs": "^6.8.8"
|
"protobufjs": "^6.8.8"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ export default function CustomGrainForm(props: Props) {
|
||||||
setConstantC(grainSettings.c.toString())
|
setConstantC(grainSettings.c.toString())
|
||||||
setKgPerBushel(grainSettings.kgPerBushel.toString())
|
setKgPerBushel(grainSettings.kgPerBushel.toString())
|
||||||
setBushelsPerTonne(grainSettings.bushelsPerTonne.toString())
|
setBushelsPerTonne(grainSettings.bushelsPerTonne.toString())
|
||||||
|
setNewGrainSettings(grainSettings)
|
||||||
}
|
}
|
||||||
},[grainSettings])
|
},[grainSettings])
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,144 @@
|
||||||
import { useState } from "react";
|
import { useCallback, useEffect, useState } from "react";
|
||||||
import PageContainer from "./PageContainer";
|
import PageContainer from "./PageContainer";
|
||||||
import CustomGrainForm from "grain/CustomGrainForm";
|
import CustomGrainForm from "grain/CustomGrainForm";
|
||||||
import { Box, Button, Grid2, Typography } from "@mui/material";
|
import { Box, Button, DialogActions, DialogContent, DialogTitle, Grid2, Typography } from "@mui/material";
|
||||||
import { pond } from "protobuf-ts/pond";
|
import { pond } from "protobuf-ts/pond";
|
||||||
import ButtonGroup from "common/ButtonGroup";
|
import ButtonGroup from "common/ButtonGroup";
|
||||||
import { useMobile } from "hooks";
|
import { useMobile, useSnackbar, useUserAPI } from "hooks";
|
||||||
|
import { useGrainAPI } from "providers/pond/grainAPI";
|
||||||
|
import ResponsiveTable from "common/ResponsiveTable";
|
||||||
|
import { GrainExtension } from "grain";
|
||||||
|
import ResponsiveDialog from "common/ResponsiveDialog";
|
||||||
|
import { useGlobalState } from "providers";
|
||||||
|
import { Scope } from "models";
|
||||||
|
|
||||||
export default function Grains() {
|
export default function Grains() {
|
||||||
const [currentCustomGrain, setCurrentCustomGrain] = useState<pond.GrainSettings>()
|
const [currentCustomGrain, setCurrentCustomGrain] = useState<pond.GrainSettings>()
|
||||||
|
const [formValid, setFormValid] = useState(false)
|
||||||
|
const [selectedGrain, setSelectedGrain] = useState<pond.GrainObject | undefined>()
|
||||||
const [displayCustom, setDisplayCustom] = useState(false)
|
const [displayCustom, setDisplayCustom] = useState(false)
|
||||||
const [grainTableData, setGrainTableData] = useState()
|
const { openSnack } = useSnackbar()
|
||||||
|
const [tableSize, setTableSize] = useState(5)
|
||||||
|
const [tablePage, setTablePage] = useState(0)
|
||||||
|
const [tableTotal, setTableTotal] = useState(0)
|
||||||
|
const grainAPI = useGrainAPI()
|
||||||
|
const userAPI = useUserAPI()
|
||||||
|
const [{as, user}] = useGlobalState();
|
||||||
|
const [permissions, setPermissions] = useState<pond.Permission[]>([])
|
||||||
|
const [openRemoveConfirmation, setOpenRemoveConfirmation] = useState(false)
|
||||||
|
const [openUpdateConfirmation, setOpenUpdateConfirmation] = useState(false)
|
||||||
|
const [grainObjectTableData, setGrainObjectTableData] = useState<pond.GrainObject[]>([])
|
||||||
|
const [supportedGrainTableData, setSupportedGrainTableData] = useState<GrainExtension[]>([])
|
||||||
const isMobile = useMobile()
|
const isMobile = useMobile()
|
||||||
|
|
||||||
//function to load the first set of custom grains
|
//function to load the first set of custom grains
|
||||||
const loadCustomGrain = () => {}
|
const loadCustomGrain = useCallback(() => {
|
||||||
|
grainAPI.listGrains(tableSize, tablePage * tableSize, "asc", "name").then(resp => {
|
||||||
|
setGrainObjectTableData(resp.data.grains)
|
||||||
|
setTableTotal(resp.data.total)
|
||||||
|
}).catch(err => {
|
||||||
|
openSnack("There was an issue loading your custom grains")
|
||||||
|
})
|
||||||
|
},[tableSize, tablePage])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if(displayCustom){
|
||||||
|
loadCustomGrain()
|
||||||
|
}
|
||||||
|
//if the user is viewing as a team get their permissions to the team, if they are not then we will get their permission to the grain typ individually when a type is selected
|
||||||
|
if(as){
|
||||||
|
userAPI.getUser(user.id(), { key: as, kind: "team" } as Scope).then(resp => {
|
||||||
|
setPermissions(resp.permissions);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},[loadCustomGrain, tableSize, tablePage, displayCustom, as])
|
||||||
|
|
||||||
|
const equationName = (enumVal: number) => {
|
||||||
|
switch(enumVal){
|
||||||
|
case pond.MoistureEquation.MOISTURE_EQUATION_CHUNG_PFOST:
|
||||||
|
return "Chung-Pfost"
|
||||||
|
case pond.MoistureEquation.MOISTURE_EQUATION_HALSEY:
|
||||||
|
return "Halsey"
|
||||||
|
case pond.MoistureEquation.MOISTURE_EQUATION_HENDERSON:
|
||||||
|
return "Henderson"
|
||||||
|
case pond.MoistureEquation.MOISTURE_EQUATION_OSWIN:
|
||||||
|
return "Oswin"
|
||||||
|
default:
|
||||||
|
return "None"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//function to update
|
//function to update
|
||||||
|
|
||||||
//tabs to select supported and custom
|
//table that will display the custom grains created by the user
|
||||||
const grainTab = () => {}
|
const grainObjectTable = () => {
|
||||||
|
return (
|
||||||
//table that will display the grains (both for the supported grain and custom for the user)
|
<ResponsiveTable<pond.GrainObject>
|
||||||
const grainTable = () => {
|
rows={grainObjectTableData}
|
||||||
|
onRowClick={(grainObj) => {
|
||||||
|
setCurrentCustomGrain(grainObj.settings ?? pond.GrainSettings.create())
|
||||||
|
setSelectedGrain(grainObj)
|
||||||
|
setFormValid(true)
|
||||||
|
/** if they are viewin as a team leave the permissions alone, if not then use the users permissions to the grain type,
|
||||||
|
* for the moment grain types are not shareable so this will be unused, but this will cover our bases if we want to implement sharing in the future
|
||||||
|
* */
|
||||||
|
if (!as) {
|
||||||
|
userAPI.getUser(user.id(), { key: grainObj.key, kind: "grain" } as Scope).then(resp => {
|
||||||
|
setPermissions(resp.permissions);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
columns={[
|
||||||
|
{
|
||||||
|
title: "Name",
|
||||||
|
render: row => <Box>
|
||||||
|
<Typography>
|
||||||
|
{row.name}
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Group",
|
||||||
|
render: row => <Box>
|
||||||
|
<Typography>
|
||||||
|
{row.settings?.group}
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Equation",
|
||||||
|
render: row => <Box>
|
||||||
|
<Typography>
|
||||||
|
{equationName(row.settings?.equation ?? 0)}
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
page={tablePage}
|
||||||
|
pageSize={tableSize}
|
||||||
|
handleRowsPerPageChange={(e) => {
|
||||||
|
setTableSize(e.target.value)
|
||||||
|
}}
|
||||||
|
setPage={(page) => {
|
||||||
|
setTablePage(page)
|
||||||
|
}}
|
||||||
|
total={tableTotal}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
//table that will display the grain extensions provided by us
|
||||||
|
const supportedGrainTable = () => {
|
||||||
|
return (
|
||||||
|
<ResponsiveTable<GrainExtension>
|
||||||
|
rows={supportedGrainTableData}
|
||||||
|
page={tablePage}
|
||||||
|
pageSize={tableSize}
|
||||||
|
handleRowsPerPageChange={() => {}}
|
||||||
|
setPage={() => {}}
|
||||||
|
total={tableTotal}
|
||||||
|
/>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
//the grain display for supported grain type to show the rest of the data such as what constants are used in the formula
|
//the grain display for supported grain type to show the rest of the data such as what constants are used in the formula
|
||||||
|
|
@ -32,11 +148,101 @@ export default function Grains() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const updateGrain = () => {
|
||||||
|
if(selectedGrain && currentCustomGrain){
|
||||||
|
grainAPI.updateGrain(selectedGrain.key, currentCustomGrain).then(resp => {
|
||||||
|
openSnack("Grain type updated")
|
||||||
|
}).catch(err => {
|
||||||
|
openSnack("There was an issue updating the selected grain type")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const updateGrainConfirmation = () => {
|
||||||
|
return (
|
||||||
|
<ResponsiveDialog open={openUpdateConfirmation} onClose={() => {setOpenUpdateConfirmation(false)}}>
|
||||||
|
<DialogTitle>Update Custom Grain</DialogTitle>
|
||||||
|
<DialogContent>
|
||||||
|
Update existing custom grain type?
|
||||||
|
<br/>
|
||||||
|
Note that updating the grain here will not change any bins or components this type was used for, those will retain the old settings.
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button variant="contained" color="primary" onClick={()=>{setOpenUpdateConfirmation(false)}}>Cancel</Button>
|
||||||
|
<Button variant="contained" color="primary" onClick={()=>{updateGrain()}}>Confirm</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</ResponsiveDialog>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const addNewGrain = () => {
|
||||||
|
if(currentCustomGrain){
|
||||||
|
grainAPI.addGrain(currentCustomGrain).then(resp => {
|
||||||
|
//new grain added
|
||||||
|
openSnack("New grain type added")
|
||||||
|
}).catch(err => {
|
||||||
|
openSnack("There was a problem creating the new grain type")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const removeGrain = () => {
|
||||||
|
if(selectedGrain){
|
||||||
|
grainAPI.removeGrain(selectedGrain.key).then(resp => {
|
||||||
|
openSnack("Grain type removed")
|
||||||
|
}).catch(err => {
|
||||||
|
openSnack("There was a problem removing the selected grain type")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const removeConfirmation = () => {
|
||||||
|
return (
|
||||||
|
<ResponsiveDialog open={openRemoveConfirmation} onClose={() => {setOpenRemoveConfirmation(false)}}>
|
||||||
|
<DialogTitle>Remove Custom Grain</DialogTitle>
|
||||||
|
<DialogContent>
|
||||||
|
Remove custom grain type?
|
||||||
|
<br />
|
||||||
|
Note that removing the grain here will not change any bins or components this type was used for, those will retain the old settings.
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button variant="contained" color="primary" onClick={()=>{setOpenRemoveConfirmation(false)}}>Cancel</Button>
|
||||||
|
<Button variant="contained" color="primary" onClick={()=>{removeGrain()}}>Confirm</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</ResponsiveDialog>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const customGrainActions = () => {
|
||||||
|
return (
|
||||||
|
<Box display="flex" justifyContent="space-between">
|
||||||
|
<Box>
|
||||||
|
{selectedGrain &&
|
||||||
|
<Button disabled={!permissions.includes(pond.Permission.PERMISSION_WRITE)} variant="contained" color="error" onClick={() => {setOpenRemoveConfirmation(true)}}>Remove Grain</Button>
|
||||||
|
}
|
||||||
|
</Box>
|
||||||
|
<Box>
|
||||||
|
{selectedGrain &&
|
||||||
|
<Button sx={{marginRight: 1}} onClick={() => setOpenUpdateConfirmation(true)} disabled={!formValid || !permissions.includes(pond.Permission.PERMISSION_WRITE)} variant="contained" color="primary">Update</Button>
|
||||||
|
}
|
||||||
|
<Button onClick={() => addNewGrain()} disabled={!formValid || !permissions.includes(pond.Permission.PERMISSION_WRITE)} variant="contained" color="primary">Save New</Button>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
//the grain display for custom grain the user has defined
|
//the grain display for custom grain the user has defined
|
||||||
const customGrainDisplay = () => {
|
const customGrainDisplay = () => {
|
||||||
return (
|
return (
|
||||||
<Box padding={2}>
|
<Box>
|
||||||
<CustomGrainForm grainSettings={currentCustomGrain} onGrainSettingsChange={()=>{}}/>
|
<CustomGrainForm
|
||||||
|
grainSettings={currentCustomGrain}
|
||||||
|
onGrainSettingsChange={(newSettings, formValid)=>{
|
||||||
|
setCurrentCustomGrain(newSettings)
|
||||||
|
setFormValid(formValid)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{customGrainActions()}
|
||||||
</Box>
|
</Box>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -44,10 +250,10 @@ export default function Grains() {
|
||||||
const desktopView = () => {
|
const desktopView = () => {
|
||||||
return (
|
return (
|
||||||
<Grid2 container>
|
<Grid2 container>
|
||||||
<Grid2 size={7}>
|
<Grid2 size={7} padding={2}>
|
||||||
|
{displayCustom ? grainObjectTable() : supportedGrainTable()}
|
||||||
</Grid2>
|
</Grid2>
|
||||||
<Grid2 size={5}>
|
<Grid2 size={5} padding={2}>
|
||||||
{displayCustom ? customGrainDisplay() : supportedDisplay()}
|
{displayCustom ? customGrainDisplay() : supportedDisplay()}
|
||||||
</Grid2>
|
</Grid2>
|
||||||
</Grid2>
|
</Grid2>
|
||||||
|
|
@ -73,20 +279,22 @@ export default function Grains() {
|
||||||
title: "Supported",
|
title: "Supported",
|
||||||
function: () => {
|
function: () => {
|
||||||
setDisplayCustom(false)
|
setDisplayCustom(false)
|
||||||
|
setTablePage(0)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Custom",
|
title: "Custom",
|
||||||
function: () => {
|
function: () => {
|
||||||
setDisplayCustom(true)
|
setDisplayCustom(true)
|
||||||
|
setTablePage(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
{!isMobile ? desktopView() : mobileView()}
|
{!isMobile ? desktopView() : mobileView()}
|
||||||
{/* <Button onClick={() => {setCurrentCustomGrain(pond.GrainSettings.create({name: "grain one"}))}}>CG1</Button>
|
{updateGrainConfirmation()}
|
||||||
<Button onClick={() => {setCurrentCustomGrain(pond.GrainSettings.create({name: "grain two"}))}}>CG2</Button> */}
|
{removeConfirmation()}
|
||||||
</PageContainer>
|
</PageContainer>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -22,6 +22,7 @@ export interface IGrainInterface {
|
||||||
types?: string[],
|
types?: string[],
|
||||||
otherTeam?: string,
|
otherTeam?: string,
|
||||||
) => Promise<AxiosResponse<pond.ListGrainsResponse>>;
|
) => Promise<AxiosResponse<pond.ListGrainsResponse>>;
|
||||||
|
updateGrain: (key: string, settings: pond.GrainSettings, otherTeam?: string) => Promise<AxiosResponse<pond.UpdateGrainResponse>>
|
||||||
removeGrain: (key: string, otherTeam?: string) => Promise<AxiosResponse<pond.RemoveGrainResponse>>;
|
removeGrain: (key: string, otherTeam?: string) => Promise<AxiosResponse<pond.RemoveGrainResponse>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -31,7 +32,7 @@ interface Props {}
|
||||||
|
|
||||||
export default function GrainProvider(props: PropsWithChildren<Props>) {
|
export default function GrainProvider(props: PropsWithChildren<Props>) {
|
||||||
const { children } = props;
|
const { children } = props;
|
||||||
const { get, del, post } = useHTTP();
|
const { get, del, post, put } = useHTTP();
|
||||||
const [{ as }] = useGlobalState();
|
const [{ as }] = useGlobalState();
|
||||||
|
|
||||||
//add
|
//add
|
||||||
|
|
@ -79,7 +80,6 @@ export default function GrainProvider(props: PropsWithChildren<Props>) {
|
||||||
get<pond.ListGrainsResponse>(
|
get<pond.ListGrainsResponse>(
|
||||||
pondURL(
|
pondURL(
|
||||||
"/grains?limit=" +
|
"/grains?limit=" +
|
||||||
"?limit=" +
|
|
||||||
limit +
|
limit +
|
||||||
"&offset=" +
|
"&offset=" +
|
||||||
offset +
|
offset +
|
||||||
|
|
@ -98,6 +98,19 @@ export default function GrainProvider(props: PropsWithChildren<Props>) {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//update
|
||||||
|
const updateGrain = (key: string, settings: pond.GrainSettings, otherTeam?: string) => {
|
||||||
|
const view = otherTeam ? otherTeam : as
|
||||||
|
if (view) {
|
||||||
|
return put<pond.UpdateGrainResponse>(
|
||||||
|
pondURL("/grains/"+ key + "?&as=" + view),
|
||||||
|
settings
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return put<pond.UpdateGrainResponse>(pondURL("/grains/" + key), settings);
|
||||||
|
}
|
||||||
|
|
||||||
//remove
|
//remove
|
||||||
const removeGrain = (key: string, otherTeam?: string) => {
|
const removeGrain = (key: string, otherTeam?: string) => {
|
||||||
const view = otherTeam ? otherTeam : as
|
const view = otherTeam ? otherTeam : as
|
||||||
|
|
@ -113,6 +126,7 @@ export default function GrainProvider(props: PropsWithChildren<Props>) {
|
||||||
addGrain,
|
addGrain,
|
||||||
getGrain,
|
getGrain,
|
||||||
listGrains,
|
listGrains,
|
||||||
|
updateGrain,
|
||||||
removeGrain
|
removeGrain
|
||||||
}}>
|
}}>
|
||||||
{children}
|
{children}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue