-
Notifications
You must be signed in to change notification settings - Fork 15
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
Add 'Clean up' button to Host Details page #1623
Conversation
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 great!
Only 2 things.
- Could you add a gif on how it works?
- Change
fireEvent
byuserEvent
We can merge after that XD
|
||
const dispatch = useDispatch(); | ||
|
||
const openDeregistrationModal = () => { |
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.
I think we can use directly the setCleanUpModalOpen(true)
, right?
I know that you did to be consistent with the other.
Anyway, up to you, not a big deal hehe
@@ -1,5 +1,6 @@ | |||
import React from 'react'; | |||
import { screen } from '@testing-library/react'; | |||
import { screen, fireEvent } from '@testing-library/react'; |
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.
Use userEvent
instead of fireEvent
. It is the recommended library.
You will need to setup the user, etc
Check other test files with this approach
@@ -66,4 +67,115 @@ describe('HostDetails component', () => { | |||
) | |||
).toBeInTheDocument(); | |||
}); | |||
|
|||
it("should not display 'Clean up' button when host is not deregisterable", () => { |
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.
double quotes? I guess the ci will complain about this hehe
I would remove the single quotes in any case from Clean up
and put them in the test string
@@ -66,4 +67,115 @@ describe('HostDetails component', () => { | |||
) | |||
).toBeInTheDocument(); | |||
}); | |||
|
|||
it("should not display 'Clean up' button when host is not deregisterable", () => { |
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.
We could maybe add a deregistration
describe to group the tests about this topic.
Again, not strong opinions
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.
+1
|
||
const cleanUpHost = () => { | ||
setCleanUpModalOpen(false); | ||
dispatch(deregisterHost(host)); |
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.
We should get the host
as argument in the function.
If we use the global variable, we have the risk of having strange things.
For example, if the function was used when host
is not loaded, things wouldn't work.
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.
Okey!
Once we have the navigation
sorted out the code looks good
|
||
const cleanUpHost = (selectedHost) => { | ||
setCleanUpModalOpen(false); | ||
dispatch(deregisterHost({ host: selectedHost, navigate })); |
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.
We careful with this!
If you change the payload format for the function, you need to change it every place that it is used, the host list view in this case.
I would suggest to go with deregisterHost({ ...selectedHost, navigate })
, but if you prefer this way don't forget to change the host list view call as well
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.
Ah yes this is true. I thought tests would catch this in HostsList.test.jsx
, but it didn't. Is there a way to have tests detect this kind of change? 👀
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.
Most probably not...
assets/js/state/sagas/hosts.js
Outdated
@@ -52,6 +52,7 @@ export function* deregisterHost({ payload }) { | |||
yield put(setHostDeregistering(payload)); | |||
try { | |||
yield call(del, `/hosts/${payload.id}`); | |||
payload.navigate?.('/hosts'); |
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.
Never seen this format before.
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.
Fancy Optional chaining with function calls.
Basically, if payload.navigate
doesn't exist, then when we try to call payload.navigate()
, we instead just returned undefined
, acting like a NOOP.
If we didn't do this, then when calling payload.navigate()
, we would get the error thrown: Uncaught TypeError: payload.navigate is not a 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.
We need to do this because we only want to navigate back to HostsList
from HostDetails
. It doesn't really make sense to do it from HostsList
because we are already there and it is updated by websocket events. So as a result we don't pass in navigate
to the payload to make this a NOOP.
assets/js/state/sagas/hosts.js
Outdated
@@ -52,6 +52,7 @@ export function* deregisterHost({ payload }) { | |||
yield put(setHostDeregistering(payload)); | |||
try { | |||
yield call(del, `/hosts/${payload.id}`); | |||
payload.navigate?.('/hosts'); |
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.
payload.navigate?.('/hosts'); | |
const { navigate } = payload; | |
navigate('/hosts'); |
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.
Sorry :D
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.
But if payload.navigate
doesn't exist and then we try to call navigate()
we will get Uncaught TypeError: navigate is not a function
.
With optional chaining if navigate
doesn't exist, the call to navigate()
just returns undefined
, essentially a NOOP.
We need to do this because we only want to navigate back to HostsList
from HostDetails
. It doesn't really make sense to do it from HostsList
because we are already there and it is updated by websocket events. So as a result we don't pass in navigate
to the payload to make this a NOOP.
assets/js/state/sagas/hosts.js
Outdated
@@ -52,6 +52,7 @@ export function* deregisterHost({ payload }) { | |||
yield put(setHostDeregistering(payload)); | |||
try { | |||
yield call(del, `/hosts/${payload.id}`); | |||
payload.navigate?.('/hosts'); |
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.
I agree to remove the optional chaining and unify the flows, we need to redirect always even on the host list, it's a no-op for the router, and we avoid to pass or not pass parameters, we don't have types and this cause only confusion imho.
Unify the things, pass the navigate always and remove the optional chaining
This reverts commit 2197e42.
Include a mocked `navigate()` function in action payload
assets/js/state/sagas/hosts.test.js
Outdated
@@ -84,15 +84,15 @@ describe('Hosts sagas', () => { | |||
it('should send host deregister request', async () => { | |||
const host = hostFactory.build(); | |||
|
|||
const mockNavigate = (route) => route; |
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.
As we have chosen to always provide a function navigate()
to the action payload for the deregisterHost()
Saga, now in the test we need to provide a mocked navigate
function. Is this function fine?
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.
You could have just a () => {}
but this is fine as well
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.
Changed!
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.
LGTM
assets/js/components/HostsList.jsx
Outdated
@@ -66,7 +66,9 @@ function HostsList() { | |||
|
|||
const cleanUpHost = (host) => { | |||
setCleanUpModalOpen(false); | |||
dispatch(deregisterHost({ ...host, navigate })); | |||
|
|||
const { id, hostname } = host; |
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.
Pls destructure on the function argument level 👁️
CleanUpHostDetails.webm
Description
Adds the 'Clean up' button to the Host Details page. Allows the user to deregister a host.
How was this tested?
Added frontend unit tests to test the behaviour of the button.