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

Update output page display #135

Merged
merged 24 commits into from
Oct 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
234b918
remove some logging
MichaelPesce Aug 5, 2024
48fab75
convert output to table; needs styling, formatting
MichaelPesce Aug 5, 2024
fd729c6
add 'smart' algorithm to sort input sections; make them two separate …
MichaelPesce Aug 13, 2024
77c80c3
remove unused code; use input category if outputcategory is not there
MichaelPesce Aug 13, 2024
7c1a69c
round and right align values in output
MichaelPesce Aug 13, 2024
400baa2
add disabled color for run button in theme
MichaelPesce Aug 15, 2024
8f269d3
Merge branch 'main' of https://github.com/MichaelPesce/watertap-ui in…
MichaelPesce Aug 15, 2024
c948293
merge main in
MichaelPesce Aug 16, 2024
35b88a7
use theme provider to handle button colors
MichaelPesce Aug 16, 2024
8903788
add key to table row
MichaelPesce Aug 16, 2024
36ebaee
try using separate job for checkout, conda incubator
MichaelPesce Aug 16, 2024
945788b
undo that
MichaelPesce Aug 16, 2024
0568fac
add debugging
MichaelPesce Aug 16, 2024
859d3d0
add performance logging
MichaelPesce Aug 16, 2024
ba16c7e
add .blg
MichaelPesce Aug 16, 2024
1844393
remove performance logging from workflow
MichaelPesce Aug 19, 2024
6eb3a9d
merge main in, handle merge conflict
MichaelPesce Sep 5, 2024
35f411f
rename cache at the end of run for windows
MichaelPesce Sep 5, 2024
f75848f
add styling to output table - bold, outlines
MichaelPesce Sep 20, 2024
eb7313e
realign table columns
MichaelPesce Sep 27, 2024
b29d20e
expand comment on organizing variables function
MichaelPesce Oct 3, 2024
3e3911d
add comment for mui theme
MichaelPesce Oct 3, 2024
c0be505
add comment above useeffect
MichaelPesce Oct 3, 2024
40cd497
add comment explaining render rows
MichaelPesce Oct 3, 2024
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
14 changes: 12 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,12 @@ jobs:
name: E2E testing (${{ matrix.os }})

runs-on: ${{ matrix.os-version }}

strategy:
fail-fast: false
matrix:
os:
- linux
- win64
# - macos
include:
- os: linux
os-version: ubuntu-latest
Expand All @@ -42,6 +40,11 @@ jobs:
activate-environment: watertap-ui-env
miniforge-version: latest

- name: Set up debug logging
run: |
echo "ACTIONS_RUNNER_DEBUG=true" >> $GITHUB_ENV
echo "ACTIONS_STEP_DEBUG=true" >> $GITHUB_ENV

- name: Add theme to .env file
working-directory: ./electron/ui
run: |
Expand Down Expand Up @@ -127,6 +130,13 @@ jobs:
electron/ui/cypress/screenshots/
electron/ui/cypress/videos/

## post-run conda often fails for weird reasons. this is a potential solution
## see https://github.com/conda-incubator/setup-miniconda/issues/277#issuecomment-1431458277
- name: Rename conda package cache
if: runner.os == 'Windows'
shell: bash
run: mv "${CONDA_PKGS_DIR}" "${CONDA_PKGS_DIR}_do_not_cache"

pytest:
name: pytest (${{ matrix.os }})
runs-on: ${{ matrix.os-version }}
Expand Down
28 changes: 20 additions & 8 deletions electron/ui/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import {getProjectName} from './services/projectName.service';
import MainContent from "./components/MainContent/MainContent";
import WaitForProject from "./components/WaitForProject/WaitForProject";
import {themes} from './theme';
import { ThemeProvider, createTheme } from '@mui/material/styles';


function App() {
let navigate = useNavigate();
Expand All @@ -21,15 +23,22 @@ function App() {
const [checkAgain, setCheckAgain] = useState(1)
const WAIT_TIME = 2

console.log("App hasTheme = ",hasTheme);
// use Material UI theme for styles to be consistent throughout app
const mui_theme = createTheme({
MichaelPesce marked this conversation as resolved.
Show resolved Hide resolved
palette: {
primary: {
main: theme?.button.background,
},
},
});

useEffect(() => {
if (hasTheme && checkAgain !== 0)
{
// Get list of flowsheets
getFlowsheetsList()
.then((data) => {
console.log("got flowsheets list")
// console.log("got flowsheets list")
setHasFlowsheetsList(true);
setCheckAgain(0)
}).catch((e) => {
Expand All @@ -45,12 +54,15 @@ function App() {

const subProcState = {value: numberOfSubprocesses, setValue: setNumberOfSubprocesses}
return (
<div className="App">
<MainContent theme={theme} hasTheme={hasTheme} hasFlowsheets={hasFlowsheetsList}
subProcState={subProcState}/>
<WaitForProject hasTheme={hasTheme}></WaitForProject>
<SplashPage theme={theme} hasTheme={hasTheme} hasFlowsheets={hasFlowsheetsList}/>
</div>

<ThemeProvider theme={mui_theme}>
<div className="App">
<MainContent theme={theme} hasTheme={hasTheme} hasFlowsheets={hasFlowsheetsList}
subProcState={subProcState}/>
<WaitForProject hasTheme={hasTheme}></WaitForProject>
<SplashPage theme={theme} hasTheme={hasTheme} hasFlowsheets={hasFlowsheetsList}/>
</div>
</ThemeProvider>
)
}

Expand Down
1 change: 0 additions & 1 deletion electron/ui/src/components/Graph/Graph.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ export default function Graph() {
setGraphImage(URL.createObjectURL(data))
}
else {
console.log("data.size is 0")
if (tryAgain) setTryAgain(false)
}
}).catch((err)=>{
Expand Down
192 changes: 93 additions & 99 deletions electron/ui/src/components/SingleOutput/SingleOutput.js
Original file line number Diff line number Diff line change
@@ -1,30 +1,62 @@
import React, {useState} from "react";
import React, {useState, useEffect, Fragment} from "react";
import {useParams} from "react-router-dom";
// MUI imports
import Accordion from "@mui/material/Accordion";
import AccordionDetails from "@mui/material/AccordionDetails";
import AccordionSummary from "@mui/material/AccordionSummary";
import Box from "@mui/material/Box";
import Button from "@mui/material/Button";
import DownloadIcon from '@mui/icons-material/Download';
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import Grid from "@mui/material/Grid";
import Modal from "@mui/material/Modal";
import SaveIcon from '@mui/icons-material/Save';
import Stack from "@mui/material/Stack";
import TextField from "@mui/material/TextField";
import Toolbar from "@mui/material/Toolbar";
import {
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
} from '@mui/material'
import Paper from '@mui/material/Paper';

export default function SingleOutput(props) {
let params = useParams();
const {outputData, downloadOutput, saveConfig} = props;
const [configName, setConfigName] = useState(outputData.name)
const [openSaveConfig, setOpenSaveConfig] = React.useState(false);
const [saved, setSaved] = React.useState(false);
const [outputTableData, setOutputTableData] = useState({})

const handleOpenSaveConfig = () => setOpenSaveConfig(true);
const handleCloseSaveConfig = () => setOpenSaveConfig(false);

/**
* organize output data into a list of dictionaries formatted for the output table
*/
useEffect(()=> {
let export_variables = {...outputData.outputData.exports}
MichaelPesce marked this conversation as resolved.
Show resolved Hide resolved
let rows = {}
for (let key of Object.keys(export_variables)) {
let export_variable = export_variables[key]
let category = export_variable.output_category
if (!category) category = export_variable.input_category
let category_rows
if (Object.keys(rows).includes(category)) category_rows = rows[category]
else {
category_rows = []
rows[category] = category_rows
}
category_rows.push({
key: key,
name: export_variable.name,
value: export_variable.value,
units: export_variable.display_units,
rounding: export_variable.rounding || 2
})
}
setOutputTableData(rows)
}, [outputData])

const modalStyle = {
position: 'absolute',
Expand Down Expand Up @@ -87,101 +119,49 @@ export default function SingleOutput(props) {
});
}

const renderOutputAccordions = () => {
let var_sections = organizeVariables(outputData.outputData.exports)
// console.log("var_sections",var_sections)
return Object.entries(var_sections).map(([key, value]) => {
let gridSize = 4;
let _key = key + Math.floor(Math.random() * 100001);
if (Object.keys(value.output_variables).length > 0) {
return (<Grid item xs={gridSize} key={_key}>
<Accordion expanded={true} style={{border: "1px solid #ddd"}}>
<AccordionSummary expandIcon={<ExpandMoreIcon/>}>
{value.display_name}
</AccordionSummary>
<AccordionDetails>
<Box
component="form"
sx={{
'& > :not(style)': {m: 1},
}}
autoComplete="off"
/**
* generate html for table
* @returns table body component containing table rows
*/
const renderRows = () => {
try {
MichaelPesce marked this conversation as resolved.
Show resolved Hide resolved
return (
<TableBody>
{Object.entries(outputTableData).map(([category, rows]) => (
<Fragment key={category}>
<TableRow>
<TableCell
rowSpan={rows.length+1}
sx={{border:"1px solid #ddd"}}
>
{
renderFields(value.output_variables)
}
</Box>
</AccordionDetails>
</Accordion>
</Grid>)
}
else {
return null;
}
})
};

// renders the data in output accordions
const renderFields = (fieldData) => {
// console.log("field data", fieldData)
return Object.keys(fieldData).map((key) => {
let _key = key + Math.floor(Math.random() * 100001);

// handle rounding
let roundedValue
if (fieldData[key].rounding != null) {
if (fieldData[key].rounding > 0) {
roundedValue = parseFloat((fieldData[key].value).toFixed(fieldData[key].rounding))
} else if (fieldData[key].rounding === 0) {
roundedValue = Math.round(fieldData[key].value)
} else // if rounding is negative
{
let factor = 1
let tempRounding = fieldData[key].rounding
console.log('rounding is negative : ', fieldData[key].rounding)
while (tempRounding < 0) {
factor *= 10
tempRounding += 1
}
roundedValue = Math.round((fieldData[key].value / factor)) * factor
console.log("old value is: ", fieldData[key].value)
console.log('new value is: ', roundedValue)
}
} else // if rounding is not provided, just use given value
{
roundedValue = fieldData[key].value
}
return (<div key={_key}>
<span>{fieldData[key].name + " "}</span>
<span
style={{color: "#68c3e4", fontWeight: "bold"}}>{roundedValue}</span>
<span>{" " + fieldData[key].display_units}</span>
</div>)
})
};

const organizeVariables = (bvars) => {
let var_sections = {}
for (const [key, v] of Object.entries(bvars)) {
let catg = v.output_category
let is_input = v.is_input
let is_output = v.is_output
if (catg === null) {
catg = ""
}
if (!Object.hasOwn(var_sections, catg)) {
var_sections[catg] = {
display_name: catg,
variables: {},
input_variables: {},
output_variables: {}
}
}
var_sections[catg]["variables"][key] = v
if (is_input) var_sections[catg]["input_variables"][key] = v;
if (is_output) var_sections[catg]["output_variables"][key] = v
<b>{category}</b>
</TableCell>
</TableRow>
{rows.map((row, idx) => (

<TableRow key={`_${idx}`}>
<TableCell align='right'>
{row.name}
</TableCell>
<TableCell align='center'>
{row.value.toLocaleString('en-US', {maximumFractionDigits:row.rounding})}
</TableCell>
<TableCell align='left'>
{row.units}
</TableCell>
</TableRow>
))}

</Fragment>
))}

</TableBody>
)
} catch(e) {
console.log("unable to render rows: ")
console.log(e)
}
return var_sections

}

return (
Expand Down Expand Up @@ -228,7 +208,21 @@ export default function SingleOutput(props) {
</Grid>
</Modal>
</Grid>
{renderOutputAccordions()}
<Grid item xs={12}>
<Paper>
<Table size="small" sx={{border:"1px solid #ddd"}}>
<TableHead>
<TableRow>
<TableCell>Category</TableCell>
<TableCell align='right'>Variable</TableCell>
<TableCell align='center'>Value</TableCell>
<TableCell align='left'>Units</TableCell>
</TableRow>
</TableHead>
{renderRows()}
</Table>
</Paper>
</Grid>
</>
);
}
2 changes: 0 additions & 2 deletions electron/ui/src/components/SolveDialog/SolveDialog.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,9 @@ export default function SolveDialog(props) {
const { open, handleSolved, handleError, flowsheetData, id, isSweep } = props;

useEffect(()=>{
console.log("solve dialog use effect")
try {
if(open)
{
console.log("open solve dialog is true")
if(isSweep) {
sweep(id, flowsheetData.inputData)
.then(r => r.json().then(data => ({status: r.status, body: data})))
Expand Down
6 changes: 3 additions & 3 deletions electron/ui/src/theme.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export const themes = {
color: '#FFFFFF', background: '#67C3E4', logoBackground: '#F2F7F8'
},
button: {
background: '#1976d2'
background: '#1976d2',
},
tabs: {
background: '#F1F3F3', color: '#727272'
Expand Down Expand Up @@ -62,7 +62,7 @@ export const themes = {
color: '#000000', background: '#F6F4F4', logoBackground: '#F8F6F6'
},
button: {
background: '#1669B6'
background: '#1669B6',
},
tabs: {
background: '#F6F4F4', color: '#727272'
Expand All @@ -87,7 +87,7 @@ export const themes = {
color: '#FFFFFF', background: '#000000', logoBackground: '#333333' // FIXME?
},
button: {
background: '#1669B6'
background: '#333333',
},
tabs: {
background: '#F1F3F3', color: '#727272'
Expand Down
Loading
Loading