Skip to content

Commit

Permalink
feat: reset app and move entries to hamburger menu
Browse files Browse the repository at this point in the history
  • Loading branch information
soofstad committed Apr 16, 2024
1 parent 0a79a54 commit 188c519
Show file tree
Hide file tree
Showing 12 changed files with 278 additions and 126 deletions.
2 changes: 1 addition & 1 deletion web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"source-map-explorer": "^2.5.3"
},
"scripts": {
"start": "export NODE_OPTIONS=--openssl-legacy-provider && react-scripts start",
"start": "export NODE_OPTIONS=--openssl-legacy-provider && WDS_SOCKET_PORT=80 react-scripts start",
"build": "export NODE_OPTIONS=--openssl-legacy-provider && react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
Expand Down
4 changes: 2 additions & 2 deletions web/src/Components/Bridging/Graphs/BridgeGraph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ const CustomTooltip = ({ active, payload, label }) => {
<div style={{ backgroundColor: 'white', border: '1px solid gray', padding: '5px', borderRadius: '2px' }}>
<div style={{ opacity: '50%' }}>{`Particle size : ${label}µm`}</div>
<div style={{ marginTop: '15px' }}>
{payload.map((graphData: any) => (
<div style={{ color: graphData.color }}>{`${graphData.name}: ${graphData.value}%`}</div>
{payload.map((graphData: any, index: number) => (
<div key={index} style={{ color: graphData.color }}>{`${graphData.name}: ${graphData.value}%`}</div>
))}
</div>
</div>
Expand Down
14 changes: 9 additions & 5 deletions web/src/Components/Combinations/CombinationCard.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
import React, { useContext, useEffect, useState } from 'react'
// @ts-ignore
import { Button, Icon, Switch, Input, Tooltip, Divider } from '@equinor/eds-core-react'
import { Button, Icon, Switch, Input, Tooltip } from '@equinor/eds-core-react'
import CombinationTable from './CombinationTable'
import styled from 'styled-components'
import { Card } from './CardContainer'
import { Bridge, Combination, GraphData, Product, Products } from '../../Types'
import EditProducts from '../Common/EditProducts'
import { CombinationAPI } from '../../Api'
import { ErrorToast } from '../Common/Toast'
import { findDValue, findGraphData } from '../../Utils'
import { IAuthContext, AuthContext } from 'react-oauth2-code-pkce'
import { edit, close, delete_to_trash } from '@equinor/eds-icons'
import { edit, delete_to_trash } from '@equinor/eds-icons'
import { toast } from 'react-toastify'

const CardHeader = styled.div`
display: flex;
Expand Down Expand Up @@ -82,6 +81,11 @@ export const CombinationCard = ({
let newMass: number = 0
let newDensity: number = 0
Object.values(combination.values).forEach(prod => {
if (!allProducts[prod.id]) {
console.error(`Product with id '${prod.id}' not found in allProducts`)
toast.error(`Product with id '${prod.id}' not found. Try resetting the application data.`, { autoClose: false })
return
}
newMass += allProducts[prod.id].sackSize * prod.value
newDensity += prod.value
})
Expand All @@ -102,7 +106,7 @@ export const CombinationCard = ({
})
.catch(error => {
console.error('fetch error' + error)
ErrorToast(`${error.response.data}`, error.response.status)
toast.error(`Failed to calculate bridge for combination '${combination.name}'`, { autoClose: false })
})
}, [combination, allProducts])

Expand Down
57 changes: 57 additions & 0 deletions web/src/Components/Common/ErrorBoundary.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { Icon, List, Typography } from '@equinor/eds-core-react'
import { account_circle } from '@equinor/eds-icons'
import { Component, ErrorInfo, ReactNode } from 'react'

interface Props {
children?: ReactNode
}

interface State {
hasError: boolean
}

class ErrorBoundary extends Component<Props, State> {
constructor(props) {
super(props)
this.state = { hasError: false }
}
// public state: State = {
// hasError: false,
// }

// eslint-disable-next-line @typescript-eslint/no-unused-vars
static getDerivedStateFromError(_: Error): State {
// Update state so the next render will show the fallback UI.
return { hasError: true }
}

public componentDidCatch(error: Error, errorInfo: ErrorInfo) {
console.error('Uncaught error:', error)
}

render() {
if (this.state.hasError) {
return (
<>
<Typography variant={'h3'}>Ops... Something went wrong 😞</Typography>
<Typography variant={'body_short'}>You should try the following:</Typography>
<List variant='numbered' style={{ lineHeight: '2.25rem' }}>
<List.Item>Refresh the page (F5)</List.Item>
<List.Item>
Resetting the application by clicking the <Icon data={account_circle} /> icon, and then{' '}
<i>&quot;reset application data&quot;</i>.
</List.Item>
<List.Item>
Contact technical support by email at{' '}
<a href={'mailto:fg_team_hermes@equinor.com'}>fg_team_hermes@equinor.com</a>
</List.Item>
</List>
</>
)
}

return this.props.children
}
}

export default ErrorBoundary
2 changes: 0 additions & 2 deletions web/src/Components/Common/Toast.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { toast } from 'react-toastify'
import React from 'react'

export const InfoToast = (msg: string) => toast.info(msg)
export const WarningToast = (msg: string) => toast.warning(msg)
export const ErrorToast = (msg: string, code?: number): any => {
const title = <p>Error</p>
const config: Object = { autoClose: 7000 }
Expand Down
10 changes: 5 additions & 5 deletions web/src/Components/Navbar/ContactButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ export const ContactButton = () => {
const [dialogOpen, setDialogOpen] = useState<boolean>(false)

return (
<>
<Button variant='outlined' onClick={() => setDialogOpen(true)}>
<div>
<div onClick={() => setDialogOpen(true)} style={{ display: 'flex', alignItems: 'center' }}>
<Icon data={comment_important} title='filter products' />
Contact
</Button>
<div style={{ paddingLeft: '15px' }}>Contact</div>
</div>
<Dialog style={{ width: 'min-content' }} open={dialogOpen}>
<Dialog.Header>
<Dialog.Title>Contact and support</Dialog.Title>
Expand All @@ -32,6 +32,6 @@ export const ContactButton = () => {
<Button onClick={() => setDialogOpen(false)}>Close</Button>
</Dialog.Actions>
</Dialog>
</>
</div>
)
}
182 changes: 103 additions & 79 deletions web/src/Components/Navbar/CreateProduct.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import React, { useContext, useState } from 'react'
// @ts-ignore
import { Button, Dialog, Icon, TextField, Table } from '@equinor/eds-core-react'
import { Button, Dialog, Icon, Table, Tabs, TextField } from '@equinor/eds-core-react'

import { ProductsAPI } from '../../Api'
import styled from 'styled-components'
import { ErrorToast } from '../Common/Toast'
import { AuthContext } from 'react-oauth2-code-pkce'
import { IAuthContext } from 'react-oauth2-code-pkce'
import { AuthContext, IAuthContext } from 'react-oauth2-code-pkce'
import { upload } from '@equinor/eds-icons'
import { TNewProduct } from '../../Types'
import { toast } from 'react-toastify'
Expand All @@ -30,7 +29,11 @@ const parseCumulativeProductCurve = (curve: string): number[][] => {
return elements.map(element => parseFloat(element))
})

return parsedData
// Filter out bad input
return parsedData.filter(dataPoint => {
if (dataPoint.length !== 2) return false
return !Number.isNaN(dataPoint[0]) && !Number.isNaN(dataPoint[1])
})
}

export const RefreshButton = () => {
Expand All @@ -39,6 +42,7 @@ export const RefreshButton = () => {
const { token }: IAuthContext = useContext(AuthContext)
const [newProduct, setNewProduct] = useState<TNewProduct>()
const [newProductData, setNewProductData] = useState<number[][]>([])
const [activeTab, setActiveTab] = useState<number>(0)

const postProduct = () => {
ProductsAPI.postProductsApi(token, { ...newProduct, productData: newProductData })
Expand All @@ -56,93 +60,113 @@ export const RefreshButton = () => {
}

return (
<>
<Button variant='outlined' onClick={() => setDialogOpen(true)}>
<div>
<div onClick={() => setDialogOpen(true)} style={{ display: 'flex', alignItems: 'center' }}>
<Icon data={upload} title='refresh' />
Create product
</Button>
<div style={{ paddingLeft: '15px' }}>Create product</div>
</div>
<Dialog open={dialogOpen} isDismissable={true} style={{ width: 'min-content' }}>
<Dialog.Header>
<Dialog.Title>Define a new product</Dialog.Title>
</Dialog.Header>
<Dialog.CustomContent style={{ display: 'flex', flexFlow: 'column', alignItems: 'center' }}>
<div style={{ display: 'flex', flexDirection: 'column', padding: '0px', alignSelf: 'start' }}>
<TextField
style={{ padding: '10px 0' }}
id='name'
label='Product name'
value={newProduct?.productName ?? ''}
onChange={event => setNewProduct({ ...newProduct, productName: event.target.value })}
/>
<TextField
style={{ padding: '10px 0' }}
id='supplier'
label='Supplier name'
value={newProduct?.productSupplier ?? ''}
onChange={event => setNewProduct({ ...newProduct, productSupplier: event.target.value })}
/>
</div>
<div>
<p>
Paste the product's measured data values here. Make sure it's been parsed correctly by inspecting the
table below before submitting.
</p>
<p>
The format of the pasted data should be two numbers on each line (space or tab separated), where the first
number is the fraction size in micron of the measuring point, and the other the cumulative volume
percentage.
</p>
<p>
The Optimizer requires each product to have 100 data points, from 0.01 - 3500 microns. If the data you
provide is missing data, the values will be interpolated and extrapolated.
</p>
<TextField
id='data'
style={{ width: '500px', overflow: 'auto' }}
placeholder='Paste the cumulative curve here'
multiline
rows={6}
label='Cumulative fractions data'
onChange={event => setNewProductData(parseCumulativeProductCurve(event.target.value))}
/>
</div>
<div style={{ maxHeight: '300px', overflow: 'auto', marginTop: '20px' }}>
<Table>
<Table.Head>
<Table.Row>
<Table.Cell>Index</Table.Cell>
<Table.Cell>Fraction(micron)</Table.Cell>
<Table.Cell>Cumulative</Table.Cell>
</Table.Row>
</Table.Head>
{newProductData.map((dataPoint: any, index) => (
<Table.Row key={index}>
<Table.Cell>{index} </Table.Cell>
<Table.Cell>{dataPoint[0]} </Table.Cell>
<Table.Cell>{dataPoint[1]} </Table.Cell>
</Table.Row>
))}
</Table>
</div>
<Tabs activeTab={activeTab} onChange={e => setActiveTab(e)}>
<Tabs.List>
<Tabs.Tab>Details</Tabs.Tab>
<Tabs.Tab>Verify</Tabs.Tab>
</Tabs.List>
<Tabs.Panels>
<Tabs.Panel>
<div style={{ display: 'flex', flexDirection: 'column', padding: '0px', alignSelf: 'start' }}>
<TextField
style={{ padding: '10px 0' }}
id='name'
label='Product name'
value={newProduct?.productName ?? ''}
onChange={event => setNewProduct({ ...newProduct, productName: event.target.value })}
/>
<TextField
style={{ padding: '10px 0' }}
id='supplier'
label='Supplier name'
value={newProduct?.productSupplier ?? ''}
onChange={event => setNewProduct({ ...newProduct, productSupplier: event.target.value })}
/>
</div>
<div>
<p>Paste the product's measured data values here.</p>
<p>
The format of the pasted data should be two numbers on each line (space or tab separated), where the
first number is the fraction size in micron of the measuring point, and the other the cumulative
volume percentage.
</p>
<p>
The Optimizer requires each product to have 100 data points, from 0.01 - 3500 microns. If the data
you provide is missing data, the values will be interpolated and extrapolated.
</p>
<TextField
id='data'
style={{ width: '500px', overflow: 'auto' }}
placeholder='Paste the cumulative curve here'
multiline
rows={6}
label='Cumulative fractions data'
onChange={event => setNewProductData(parseCumulativeProductCurve(event.target.value))}
/>
</div>
</Tabs.Panel>
<Tabs.Panel>
<p>Verify that the data looks correct before submitting. Go back and correct the input if necessary.</p>
<div style={{ maxHeight: '300px', overflow: 'auto', marginTop: '20px' }}>
<Table>
<Table.Head>
<Table.Row>
<Table.Cell>Index</Table.Cell>
<Table.Cell>Fraction(micron)</Table.Cell>
<Table.Cell>Cumulative(%)</Table.Cell>
</Table.Row>
</Table.Head>
{newProductData.map((dataPoint: any, index) => (
<Table.Row key={index}>
<Table.Cell>{index} </Table.Cell>
<Table.Cell>{dataPoint[0]} </Table.Cell>
<Table.Cell>{dataPoint[1]} </Table.Cell>
</Table.Row>
))}
</Table>
</div>
</Tabs.Panel>
</Tabs.Panels>
</Tabs>
</Dialog.CustomContent>
<Dialog.Actions style={{ width: 'fill-available', display: 'flex', justifySelf: 'normal' }}>
<ButtonWrapper>
<Button variant='outlined' onClick={() => setDialogOpen(false)} disabled={loading}>
Cancel
</Button>
<Button
disabled={loading || !newProductData || !newProduct?.productSupplier || !newProduct?.productName}
onClick={() => {
setLoading(true)
postProduct()
}}
>
Create
</Button>
{activeTab === 0 ? (
<Button variant='outlined' onClick={() => setDialogOpen(false)} disabled={loading}>
Cancel
</Button>
) : (
<Button variant='outlined' onClick={() => setActiveTab(0)}>
Back
</Button>
)}
{activeTab === 0 ? (
<Button onClick={() => setActiveTab(1)}>Next</Button>
) : (
<Button
disabled={loading || !newProductData || !newProduct?.productSupplier || !newProduct?.productName}
onClick={() => {
setLoading(true)
postProduct()
}}
>
Create
</Button>
)}
</ButtonWrapper>
</Dialog.Actions>
</Dialog>
</>
</div>
)
}

Expand Down
Loading

0 comments on commit 188c519

Please sign in to comment.