diff --git a/src/ThreeEditor/components/Dialog/OpenFileDialog.tsx b/src/ThreeEditor/components/Dialog/OpenFileDialog.tsx index 0213141e0..b965ab074 100644 --- a/src/ThreeEditor/components/Dialog/OpenFileDialog.tsx +++ b/src/ThreeEditor/components/Dialog/OpenFileDialog.tsx @@ -1,25 +1,9 @@ import RemoveCircleOutlineIcon from '@mui/icons-material/RemoveCircleOutline'; import { TabContext, TabList, TabPanel } from '@mui/lab'; -import { - Box, - Button, - Divider, - IconButton, - List, - ListItem, - ListItemButton, - Tab, - Tabs, - TextField, - Tooltip -} from '@mui/material'; +import { Box, Button, Divider, IconButton, Tab, TextField, Tooltip } from '@mui/material'; import { ChangeEvent, SyntheticEvent, useCallback, useMemo, useState } from 'react'; -import EXAMPLES from '../../../examples/examples'; import { LoaderContext } from '../../../services/LoaderService'; -import { FullSimulationData } from '../../../services/ShSimulatorService'; -import { SimulatorType } from '../../../types/RequestTypes'; -import { StatusState } from '../../../types/ResponseTypes'; import { ConcreteDialogProps, CustomDialog } from './CustomDialog'; import { DragDropProject } from './DragDropProject'; @@ -28,10 +12,13 @@ export function OpenFileDialog({ loadFromJson, loadFromFiles, loadFromUrl, - loadFromJsonString -}: ConcreteDialogProps) { + loadFromJsonString, + dialogState +}: ConcreteDialogProps & { + dialogState: string; +}) { const [currentFileList, setCurrentFileList] = useState(); - const [value, setValue] = useState('1'); + const [value, setValue] = useState(dialogState); const handleChange = (event: SyntheticEvent, newValue: string) => { setValue(newValue); }; @@ -42,11 +29,10 @@ export function OpenFileDialog({ }; const [url, setUrl] = useState(''); - const [exampleIndex, setExampleIndex] = useState(null); const handleUrlChange = (event: ChangeEvent) => { setUrl(event.target.value); }; - const tabList = useMemo(() => ['Examples', 'Upload file', 'From URL', 'Plain text'], []); + const tabList = useMemo(() => ['Upload file', 'From URL', 'Plain text'], []); const tabPanelProps = useCallback( (index: number) => ({ value: index.toString(), @@ -54,34 +40,6 @@ export function OpenFileDialog({ }), [value] ); - const [selectedSimulator, setSelectedSimulator] = useState(SimulatorType.COMMON); - - function fetchExampleData(exampleName: string) { - fetch(`${process.env.PUBLIC_URL}/examples/${exampleName}`) - .then(function (response) { - if (response.status !== 200) { - console.log('Looks like there was a problem. Status Code: ' + response.status); - - return; - } - - response.json().then(function (data) { - const simulationData: FullSimulationData = data as FullSimulationData; - - loadFromJson( - [simulationData].map(e => { - return { - ...e, - jobState: StatusState.COMPLETED - }; - }) - ); - }); - }) - .catch(function (err) { - console.log('Fetch Error :-S', err); - }); - } return ( - setSelectedSimulator(newValue)} - aria-label='simulator selection tabs' - variant='fullWidth'> - {Object.values(SimulatorType).map(simulator => ( - - ))} - - - - - {Object.entries(EXAMPLES[selectedSimulator]).map((name, idx) => ( - setExampleIndex(idx)}> - - {name[0]} - - - ))} - - - - - - + - + + + + , + separator: true + }, { label: 'Editor', tooltipLabel: 'Editor', diff --git a/src/WrapperApp/components/NavDrawer/NavDrawerList.tsx b/src/WrapperApp/components/NavDrawer/NavDrawerList.tsx index bd3127d0f..720c18229 100644 --- a/src/WrapperApp/components/NavDrawer/NavDrawerList.tsx +++ b/src/WrapperApp/components/NavDrawer/NavDrawerList.tsx @@ -1,12 +1,9 @@ import AutoStoriesIcon from '@mui/icons-material/AutoStories'; import GitHubIcon from '@mui/icons-material/GitHub'; -import LoginIcon from '@mui/icons-material/Login'; -import LogoutIcon from '@mui/icons-material/Logout'; import PersonIcon from '@mui/icons-material/Person'; import { Box, Divider, - IconButton, List, ListItem, ListItemButton, @@ -206,7 +203,17 @@ export function NavDrawerList({ } function NavDrawerElement({ - menuOption: { label, richLabel, tooltipLabel, value, disabled, info, description, icon }, + menuOption: { + label, + richLabel, + tooltipLabel, + value, + disabled, + info, + description, + icon, + separator + }, open, selected, secondaryAction, @@ -279,6 +286,7 @@ function NavDrawerElement({ {listItemContent} )} + {separator && } ); diff --git a/src/WrapperApp/components/Panels/ExamplePanel.tsx b/src/WrapperApp/components/Panels/ExamplePanel.tsx new file mode 100644 index 000000000..03c8e4ab5 --- /dev/null +++ b/src/WrapperApp/components/Panels/ExamplePanel.tsx @@ -0,0 +1,53 @@ +import { Box, Grid2, Paper, Typography } from '@mui/material'; + +import EXAMPLES, { useFetchExampleData } from '../../../examples/examples'; +import { SimulatorType } from '../../../types/RequestTypes'; + +interface ExamplePanelProps { + setTabsValue: (value: string) => void; +} + +export function ExamplePanel({ setTabsValue }: ExamplePanelProps) { + const fetchExampleData = useFetchExampleData(); + + return ( + + {Object.values(SimulatorType).map(simulator => ( + + {/* Simulator Name */} + + {simulator.toUpperCase()} + + + {/* Grid2 of Examples */} + + {Object.entries(EXAMPLES[simulator]).map(([exampleName, fileName]) => ( + + {' '} + {/* Set a fixed width here */} + { + fetchExampleData(fileName); + // Change the tab to 'editor' after loading the example + setTabsValue('editor'); + }}> + {exampleName} + + + ))} + + + ))} + + ); +} diff --git a/src/__tests__/FlukaConverter.test.ts b/src/__tests__/FlukaConverter.test.ts index accd74048..f60b8c6a9 100644 --- a/src/__tests__/FlukaConverter.test.ts +++ b/src/__tests__/FlukaConverter.test.ts @@ -35,92 +35,61 @@ describe('Fluka Converter', () => { ) ).toBeTruthy(); - //find the "Editor" button on the left menu and assure it is already selected - const editorButton = await driver.findElement(By.xpath("//div[@aria-label = 'Editor']")); - - if ((await editorButton.getAttribute('aria-selected')) !== 'true') - console.warn( - `Editor button is not selected even though it should be it's default state.` - ); - await editorButton.click().then(async () => { - //click rerenders the nav drawer, so we need to wait for it to rerender - expect( - await driver.wait( - until.elementLocated( - By.xpath("//div[@aria-label = 'Editor' and @aria-selected = 'true']") - ), - 10_000 - ) - ).toBeTruthy(); - }); - - //find the "open" button (second from the left on the upper bar) and then click it - const openButton = await driver.findElement(By.xpath("//span[@aria-label = 'Menu Open']")); - await openButton.click(); - - //wait for the "open project" window to appear - const openProjectTitleId = 'open-project-dialog-title'; - - const openProjectWidget = await driver.wait( - until.elementLocated( - By.xpath(`//div[@role = 'dialog' and @aria-labelledby = '${openProjectTitleId}']`) - ), - 10_000 + // Find and click the "Examples" button + const examplesButton = await driver.findElement( + By.xpath("//div[@aria-label = 'Examples']") ); - const openProjectTitle = await openProjectWidget.findElement(By.id(openProjectTitleId)); - await driver.wait(until.elementTextIs(openProjectTitle, 'Open Project'), 5_000); + // Scroll into view to ensure the element is visible + await driver.executeScript('arguments[0].scrollIntoView(true);', examplesButton); - //find the "examples" button in the window and click it. (we find it by contained text as its id changes every time) - const examplesButton = await openProjectWidget.findElement( - By.xpath("//button[contains(text(),'Examples')]") - ); - //check if the tab is not already selected - expect(await examplesButton.getAttribute('aria-selected')).toBe('false'); + // Click the button + await driver.wait(until.elementIsVisible(examplesButton), 5_000); + await driver.wait(until.elementIsEnabled(examplesButton), 5_000); await examplesButton.click(); - //find the "examples" panel we just opened - const examplesPanel = await driver.wait( + // Wait until the "Examples" button is marked as active + await driver.wait( until.elementLocated( - By.xpath( - `//div[@role = 'tabpanel' and @aria-labelledby = '${await examplesButton.getAttribute( - 'id' - )}' and @id = '${await examplesButton.getAttribute('aria-controls')}']` - ) + By.xpath("//div[@aria-label = 'Examples' and @aria-selected = 'true']") ), 10_000 ); - //check if the tab is not hidden - expect(await examplesPanel.getAttribute('hidden')).toBeFalsy(); + // Find the "FLUKA" section header + const flukaSectionHeader = await driver.findElement(By.xpath("//h5[text()='FLUKA']")); - // select SHIELDHIT subsection - examplesPanel.findElement(By.xpath("//button[contains(text(),'shieldhit')]")).click(); + // Scroll into view of the header + await driver.executeScript('arguments[0].scrollIntoView(true);', flukaSectionHeader); - //find the list of examples - const examplesList = await examplesPanel.findElement(By.id('Examples list')); + // Ensure the section header is visible + expect(await flukaSectionHeader.isDisplayed()).toBeTruthy(); - //find the first option in the list - //it has value=0 and is li element - const firstExample = await examplesList.findElement(By.xpath("//li[@value = '0']")); - - //check if the first example is "Proton pencil beam in water" - //text is located in element with id corresponding to aria-labelledby of the list element - const exampleLabel = await openProjectWidget.findElement( - By.id(await firstExample.getAttribute('aria-labelledby')) + // Find the first example in the "FLUKA" section + const firstExample = await driver.findElement( + By.xpath( + "//h5[text()='FLUKA']/following-sibling::div//div[contains(@class, 'MuiPaper-root')][1]" + ) ); - expect(await exampleLabel.getText()).toBe('Proton pencil beam in water'); - //click the first example + // Scroll into view of the first example + await driver.executeScript('arguments[0].scrollIntoView(true);', firstExample); + + // Ensure the first example is visible + expect(await firstExample.isDisplayed()).toBeTruthy(); + + // Click the first example await firstExample.click(); - expect(await firstExample.getAttribute('aria-selected')).toEqual('true'); - //find the "load" button and click it - const loadButton = await openProjectWidget.findElement( - By.xpath("//button[@aria-label = 'Load example button']") + // Check if the tab switched to "Editor" + const editorTab = await driver.wait( + until.elementLocated( + By.xpath("//div[@aria-label = 'Editor' and @aria-selected = 'true']") + ), + 10_000 ); - expect(await loadButton.isEnabled()).toEqual(true); - await loadButton.click(); + + expect(editorTab).toBeTruthy(); const loadFileTitleId = 'load-file-alert-dialog-title'; const loadFileContentId = 'load-file-alert-dialog-content'; @@ -168,13 +137,6 @@ describe('Fluka Converter', () => { ) ).toBeTruthy(); - //find the "Fluka" button and click it - const flukaButton = await driver.findElement(By.xpath("//button[@value = 'fluka']")); - await flukaButton.click(); - - //accept the "current data will be lost" alert - await driver.switchTo().alert().accept(); - //wait until the "generate from editor" button and click it (it takes some time for the button to change from "initializing") //xpath is used as again the id changes every time const generateButton = await driver.findElement( diff --git a/src/__tests__/ShieldhitConverter.test.ts b/src/__tests__/ShieldhitConverter.test.ts index d0132139d..92afce128 100644 --- a/src/__tests__/ShieldhitConverter.test.ts +++ b/src/__tests__/ShieldhitConverter.test.ts @@ -36,92 +36,63 @@ describe('ShieldhitConverter', () => { ) ).toBeTruthy(); - //find the "Editor" button on the left menu and assure it is already selected - const editorButton = await driver.findElement(By.xpath("//div[@aria-label = 'Editor']")); - - if ((await editorButton.getAttribute('aria-selected')) !== 'true') - console.warn( - `Editor button is not selected even though it should be it's default state.` - ); - await editorButton.click().then(async () => { - //click rerenders the nav drawer, so we need to wait for it to rerender - expect( - await driver.wait( - until.elementLocated( - By.xpath("//div[@aria-label = 'Editor' and @aria-selected = 'true']") - ), - 10_000 - ) - ).toBeTruthy(); - }); - - //find the "open" button (second from the left on the upper bar) and then click it - const openButton = await driver.findElement(By.xpath("//span[@aria-label = 'Menu Open']")); - await openButton.click(); - - //wait for the "open project" window to appear - const openProjectTitleId = 'open-project-dialog-title'; - - const openProjectWidget = await driver.wait( - until.elementLocated( - By.xpath(`//div[@role = 'dialog' and @aria-labelledby = '${openProjectTitleId}']`) - ), - 10_000 + // Find and click the "Examples" button + const examplesButton = await driver.findElement( + By.xpath("//div[@aria-label = 'Examples']") ); - const openProjectTitle = await openProjectWidget.findElement(By.id(openProjectTitleId)); - await driver.wait(until.elementTextIs(openProjectTitle, 'Open Project'), 10_000); + // Scroll into view to ensure the element is visible + await driver.executeScript('arguments[0].scrollIntoView(true);', examplesButton); - //find the "examples" button in the window and click it. (we find it by contained text as its id changes every time) - const examplesButton = await openProjectWidget.findElement( - By.xpath("//button[contains(text(),'Examples')]") - ); - //check if the tab is not already selected - expect(await examplesButton.getAttribute('aria-selected')).toBe('false'); + // Click the button + await driver.wait(until.elementIsVisible(examplesButton), 5_000); + await driver.wait(until.elementIsEnabled(examplesButton), 5_000); await examplesButton.click(); - //find the "examples" panel we just opened - const examplesPanel = await driver.wait( + // Wait until the "Examples" button is marked as active + await driver.wait( until.elementLocated( - By.xpath( - `//div[@role = 'tabpanel' and @aria-labelledby = '${await examplesButton.getAttribute( - 'id' - )}' and @id = '${await examplesButton.getAttribute('aria-controls')}']` - ) + By.xpath("//div[@aria-label = 'Examples' and @aria-selected = 'true']") ), 10_000 ); - //check if the tab is not hidden - expect(await examplesPanel.getAttribute('hidden')).toBeFalsy(); - - // select SHIELDHIT subsection - examplesPanel.findElement(By.xpath("//button[contains(text(),'shieldhit')]")).click(); + // Find the "SHIELDHIT" section header + const shieldhitSectionHeader = await driver.findElement( + By.xpath("//h5[text()='SHIELDHIT']") + ); - //find the list of examples - const examplesList = await examplesPanel.findElement(By.id('Examples list')); + // Scroll into view of the header + await driver.executeScript('arguments[0].scrollIntoView(true);', shieldhitSectionHeader); - //find the first option in the list - //it has value=0 and is li element - const firstExample = await examplesList.findElement(By.xpath("//li[@value = '0']")); + // Ensure the section header is visible + expect(await shieldhitSectionHeader.isDisplayed()).toBeTruthy(); - //check if the first example is "Proton pencil beam in water" - //text is located in element with id corresponding to aria-labelledby of the list element - const exampleLabel = await openProjectWidget.findElement( - By.id(await firstExample.getAttribute('aria-labelledby')) + // Find the first example in the "SHIELDHIT" section + const firstExample = await driver.findElement( + By.xpath( + "//h5[text()='SHIELDHIT']/following-sibling::div//div[contains(@class, 'MuiPaper-root')][1]" + ) ); - expect(await exampleLabel.getText()).toBe('Proton pencil beam in water'); - //click the first example + // Scroll into view of the first example + await driver.executeScript('arguments[0].scrollIntoView(true);', firstExample); + + // Ensure the first example is visible + expect(await firstExample.isDisplayed()).toBeTruthy(); + + // Click the first example await firstExample.click(); - expect(await firstExample.getAttribute('aria-selected')).toEqual('true'); - //find the "load" button and click it - const loadButton = await openProjectWidget.findElement( - By.xpath("//button[@aria-label = 'Load example button']") + // Check if the tab switched to "Editor" + const editorTab = await driver.wait( + until.elementLocated( + By.xpath("//div[@aria-label = 'Editor' and @aria-selected = 'true']") + ), + 10_000 ); - expect(await loadButton.isEnabled()).toEqual(true); - await loadButton.click(); + + expect(editorTab).toBeTruthy(); const loadFileTitleId = 'load-file-alert-dialog-title'; const loadFileContentId = 'load-file-alert-dialog-content'; @@ -169,19 +140,6 @@ describe('ShieldhitConverter', () => { ) ).toBeTruthy(); - //find the "SHIELD-HIT12A" button and click it - const shieldhitButton = await driver.findElement( - By.xpath("//button[@value = 'shieldhit']") - ); - await shieldhitButton.click(); - - //accept the "current data will be lost" alert - try { - await driver.switchTo().alert().accept(); - } catch (error) { - // TODO: remove this when the alert is fixed - } - //wait until the "generate from editor" button and click it (it takes some time for the button to change from "initializing") //xpath is used as again the id changes every time const generateButton = await driver.findElement( diff --git a/src/examples/examples.ts b/src/examples/examples.ts index 89d1687a8..ee4a21982 100644 --- a/src/examples/examples.ts +++ b/src/examples/examples.ts @@ -1,7 +1,41 @@ +import { useLoader } from '../services/LoaderService'; +import { FullSimulationData } from '../services/ShSimulatorService'; import { SimulatorExamples, SimulatorType } from '../types/RequestTypes'; +import { StatusState } from '../types/ResponseTypes'; type SimulationMap = Record; const EXAMPLES: SimulationMap = require(`./exampleMap.json`); +export function useFetchExampleData() { + const { loadFromJson } = useLoader(); + + const fetchExampleData = (exampleName: string) => { + fetch(`${process.env.PUBLIC_URL}/examples/${exampleName}`) + .then(response => { + if (response.status !== 200) { + console.log('Looks like there was a problem. Status Code: ' + response.status); + + return; + } + + response.json().then(data => { + const simulationData: FullSimulationData = data as FullSimulationData; + + loadFromJson( + [simulationData].map(e => ({ + ...e, + jobState: StatusState.COMPLETED + })) + ); + }); + }) + .catch(err => { + console.log('Fetch Error :-S', err); + }); + }; + + return fetchExampleData; +} + export default EXAMPLES;