Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: bump deps #223

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
feat: reset app and move entries to hamburger menu
  • Loading branch information
soofstad committed Apr 16, 2024
commit 188c519fa656e16da1f46520ec01e5a808ae1c12
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
Loading