-
Notifications
You must be signed in to change notification settings - Fork 11
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
Fix Reload Button Crash #144
Conversation
Pressing the Reload button in rapid succession would crash the loader by calling `handleReloadClick` multiple times very quickly and getting to a state where the loader was running and the `isLoaded` state variable was set incorrectly. Adding this conditional should prevent `handleReloadClick` from setting this at an unintended time.
src/components/OSCALLoader.js
Outdated
@@ -56,8 +56,10 @@ export default function OSCALLoader(props) { | |||
}; | |||
|
|||
const handleReloadClick = () => { | |||
setIsLoaded(false); | |||
loadOscalData(oscalUrl); | |||
if (isLoaded) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we consider also visually disabling the reload button as part of this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea, I'll look into that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be able to just set the disabled
flag: https://material-ui.com/components/buttons/
Added a state variable `contentLoaded` in OSCALLoader.js that tracks whether the content of the page has loaded or not. This state variable is passed into the renderer (Profile, Catalog, SSP, or Component), which sets it to true when the content has loaded. It is also passed into the OSCALLoaderForm component, which passes it into the button as the `disabled` prop, such that the button will be disabled initially, then enabled once the content has loaded.
In some circumstances, notably the profile tests, the prop `setContentLoaded` is undefined, causing failures. In order to resolve these failures and maintain the isolated functionality of the components, a conditional is added to check if the prop is defined before calling.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me so far. I had a few minor suggestions.
Move the function setLoadedStates to Profile Utils and import it where it is used to reduce duplication of code. Also added brackets to if statements for readability.
Clean up the imports in profile utils to improve readability and address linting issues. Changed the import of fetchProfileModifications to no longer be default, because it's cleaner not to have a default when importing more than one function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall everything seems to work great, as the tests pass locally and I can see the added functionality. My only comment, besides my requested change, is that it seems we can still click the reload button multiple times, which increases the time it takes for the page to load. I'm not sure how (if you could) disable the reload button before a second click, but I just thought I'd mention this.
Agreed; it feels like it freezes on a mouse click and "buffers" the click even when the button is disabled. I'll look into this further, but has anyone worked with these types of React components and have any tips on making it run a bit smoother? |
Change the `handleReloadClick` function to import and call the `setLoadedStates` util function, in order to reduce duplication. Also added a check for the `contentLoaded` state variable to the conditional in the function for readability and to cover certain edge cases.
Removing some left over debugging statements.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking good overall. We could consider a slightly different approach that lets OSCALLoader
handle state changes, passes that on to the OSCALLoaderForm
, and passes an onResolutionComplete
function to the OSCAL objects which are responsible for calling it when their resolution is done. I'll create a parallel draft PR to describe what I mean.
Thanks! This seems a bit cleaner. I'd like to see what others think, but I vote we go with your alternate approach. |
…brary into EGRC-463 Merging from EGRC-463-alt to incorporate the alternate way of resolving the ticket: The state variable `isResourceLoaded` is now used to track when the viewer pages load, and a setter function is passed into each parent component. Resolved merge conflicts and a few readability/linter complaints.
I still see the issue, when on the profile viewer, of being able to click on the reload button multiple times (even when it's disabled). I initially wondered if this is an issue of simply displaying all the data on the screen. However, the background color of the reload button correctly reflects whether all the data has been rendered so that does not seem to be the issue. My guess is that we are incorrectly modifying |
@mikeisen1, I've noticed that there are certain states where the browser is pretty much frozen, and I'm not sure the additional clicks are actually being registered, which doesn't seem to have to do with the reload functionality as much as resolving and rendering controls. Is that what you're seeing? |
I took a look at it a little more and yeah it does seem that it is an issue of the browser being frozen. Is this something that should be resolved as part of a separate issue? |
Ah, so only on the initial load? I think we can fix that by just setting the initial default of |
src/components/OSCALCatalog.js
Outdated
@@ -17,6 +17,10 @@ const useStyles = makeStyles((theme) => ({ | |||
export default function OSCALCatalog(props) { | |||
const classes = useStyles(); | |||
|
|||
useEffect(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is useEffect
needed, or can we just call props.onResolutionComplete()
?
src/components/OSCALLoader.js
Outdated
@@ -29,6 +29,7 @@ const defaultOscalSspUrl = | |||
export default function OSCALLoader(props) { | |||
const [error, setError] = useState(null); | |||
const [isLoaded, setIsLoaded] = useState(false); | |||
const [isResolutionComplete, setIsResolutionComplete] = useState(true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The may need to change to false
based on PR comments.
At least on my end, I notice that happens not only on the initial load, but also sometimes when I click on reload. |
Changed the initialization of the state variable `isResolutionComplete` to initially be false, so that the button will appear disabled when the page is first loading in. Also made some minor cleanup to OSCALCatalog.js; removed the unnecessary `useEffect` call.
Pressing the Reload button in rapid succession would crash
the loader by calling
handleReloadClick
multiple timesvery quickly and getting to a state where the loader was running
and the
isLoaded
state variable was set incorrectly.Adding this conditional should prevent
handleReloadClick
from setting this at an unintended time.