-
Notifications
You must be signed in to change notification settings - Fork 30
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
VV: Display the VV in the Classifier #6457
Conversation
eeab260
to
ea41bde
Compare
ea41bde
to
8acf455
Compare
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.
In this PR, I think there's a bit of a misunderstanding about using custom hooks, so I left a detailed comment with documentation and reference to examples in this repo. The current pattern of useSubjectJSON()
in the VolumetricViewer.js is a blocker to merging this PR, so please see my recommendations on how to change it, and let me know if you'd like to have a call to discuss.
.views(self => ({ | ||
get isVolumetricViewer() { | ||
return (isValidReference(() => self.active)) | ||
? self.active.experimental_tools.includes('volumetricViewer') | ||
: false | ||
} | ||
})) |
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.
This works and I can see the VolumetricViewer component when I run this branch locally. In our Tues meeting I recommended this view be on the Project store model, which can be confusing because there's Project.js and ProjectStore.js. I mentioned there are already two views on the Project store model, and those are in Project.js.
At this point I think it's half dozen of one and six of the other, but just wanted to be clear about what I recommended Tuesday. In ProjectStore.js, you have to use isValidReference()
to grab the active project
, whereas if the view is in Project.js, you just grab the active project via the storeMapper()
. An example of the latter is get display_name()
below (just an FYI, feel free to keep the view in ProjectStore.js if you prefer):
get display_name() { | |
return self.strings.get('display_name') | |
}, |
The presentational component SlideTutorialContainer uses project.display_name
view:
Lines 12 to 14 in fbab1d8
projects: { | |
active: project | |
}, |
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.
Got this moved over to the proper file in latest commit - thanks for the clarification!
useEffect(() => { | ||
if (subjectData !== '') { | ||
setData(Buffer.from(subjectData, 'base64')) | ||
} else if (subjectUrl !== '') { | ||
fetch(subjectUrl) | ||
.then((res) => res.json()) | ||
.then((data) => { | ||
setData(Buffer.from(data, 'base64')) | ||
}) | ||
} else { | ||
console.log('No data to display') | ||
} | ||
}, []) | ||
useSubjectJSON({ setSubjectData, subject }) | ||
}, [subject]) |
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.
It's a bit difficult to see from the diff, but this is the pattern you've got here:
useEffect(() => {
useSubjectJSON({ setSubjectData, subject })
}, [subject])
On first look, this is a custom hook inside useEffect
which goes against the React Rules of Hooks "Do not call Hooks inside functions passed to useMemo, useReducer, or useEffect." However, looking closer at your function named useSubjectJSON()
in lib-subject-viewers, it's not actually a hook.
useSubjectJSON()
in lib-classifier utilizes useEffect
and useState
to fetch and return subject data to the viewer. It's a custom React hook and allowed the "use" naming convention because useEffect
and useState
are inside the useSubjectJSON()
function.
In this PR, you've got useEffect
and useState
inside VolumetricViewer.js instead of inside useSubjectJSON()
, which is just a fetcher function.
Is this pattern intentional? Let me know if you'd like to have a call to discuss custom hooks.
Overall, I recommend:
- Naming your fetcher function in lib-subject-viewers something specific to volumetric data like
useVolumetricSubject()
. - Pass
onError
,onReady
, andsubject
to a custom hookuseVolumetricSubject()
exactly like it's done below for JSONDataViewer. The custom hookuseVolumetricSubject()
then returnssubjectData
, anderror
. This pattern would clean up the code in VolumetricViewer.js, removing the need for twouseEffect
functions, and the need to storesubjectData
and error status in auseState
.
Line 45 in fbab1d8
const { data: jsonData, loading, error, type, viewer } = useSubjectJSON({ onError, onReady, subject}) |
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.
Got this incorporated as well - I appreciate the focus on the hook's interface within the VolumetricViewer
component. That helped me refactor/isolate where the state should live.
c01f534
to
a6158bd
Compare
@goplayoutside3 - got the changes suggested above incorporated and incorporated a couple small changes based on our conversation during today's Brain meeting. |
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 much better, thanks for the update! I'm able to view the volumetric viewer test project while running app-project or lib-classifier locally. No other FEM subject viewers are affected 👍
I'm going to approve, but see my notes in the SubjectViewer.spec.js file. The unit tests need a bit of reworking before this PR can be merged.
|
||
const wrapper = shallow(<SubjectViewer subjectQueueState={asyncStates.success} subject={{ viewer: 'variableStar', viewerConfiguration }} />) | ||
expect(wrapper.find(JSONDataViewer).props().viewerConfiguration).to.deep.equal(viewerConfiguration) | ||
it('should render the VolumetricViewer if the subject store successfully loads', 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.
it('should render the VolumetricViewer if the subject store successfully loads', function () { | |
it('should render the VolumetricViewer if isVolumetric = true', function () { |
This test is specific to a volumetric project. You've deleted the generic unit test for 'if the subject store successfully loads'.
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.
Yes - this was because the spec was originally in Enzyme and mounting/rendering sub-components gets pretty dicy when converting to RTL... So, my thought was to make a more "robust" test of the SubjectViewer that handles the async nature of the VolumetricViewer because, if it can handle that, it should be able to render the default Viewer. I admit it compromises completeness of test coverage (handling the rendering of the non-async viewers), but the test I added is meant to make up for that with it being the more "complex" scenario due to its async nature.
expect(screen.getByText('Suspense boundary')).to.exist() | ||
expect(screen.findByTestId('subject-viewer-volumetric')).to.exist() |
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 expectation on line 38 is a false positive. I can change that line to findByTestId('subject-viewer-volumetriccccc').to.exist()
and it will still be true. See the documented Issue about findBy
queries: #6383
This unit test needs reworking before this PR can be merged.
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.
Great catch! Fixed with adding async
in the spec and a proper return element that doesn't dive into WebGL/Canvas context rendering in the testrunner.
a6158bd
to
ece899d
Compare
@goplayoutside3 - fixed the broken spec and explained the approach to writing that spec. If you'd like me to add another spec for the non-volumetric viewers, I can timebox getting one to render without throwing up errors given the Enzyme => RTL conversion removes the shallow-mounting benefit that Enzyme had. |
The only thing missing from this setup ^ is a mocked Mobx store because most of the viewer components have a "connector" wrapper that looks to the store for more data. The store is often mocked in Storybook and then used in a spec file, but here's one example where the store is mocked directly in a spec: Lines 60 to 70 in b5af532
You're welcome to continue with just one test for |
CI tests are failing due to changes in SubjectViewer.spec.js
0070da9
to
679f7d5
Compare
Hey Delilah - quick summary of the 2 most recent commits:
|
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.
Thanks!
679f7d5
to
83c7f91
Compare
Package
lib-classifier
andlib-subject-viewers
Describe your changes
volumetricViewer
to the Project Store/hooks
folder with newly createduseSubjectJSON.js
to fetch the Subject JSONHow to Review
lib-classifier
locally should display the VV with the 4x4x4 cubeapp-project
locally should display the VV with the 4x4x4 cubeChecklist
PR Creator - Please cater the checklist to fit the review needed for your code changes.
PR Reviewer - Use the checklist during your review. Each point should be checkmarked or discussed before PR approval.
General
yarn panic && yarn bootstrap
ordocker-compose up --build
and FEM works as expectedGeneral UX
Example Staging Project: i-fancy-cats
New Feature