Fixes #39253 - Implement "Not Found" error handling for invalid Job I…#1030
Fixes #39253 - Implement "Not Found" error handling for invalid Job I…#1030pondrejk wants to merge 1 commit into
Conversation
3cf4949 to
412d2fe
Compare
adamruzicka
left a comment
There was a problem hiding this comment.
Some nitpicks, seems to work well.
| <EmptyStateBody> | ||
| {sprintf( | ||
| __( | ||
| 'There is no job invocation with id %s or there are access permissions needed. Please contact your administrator if this issue continues.' |
There was a problem hiding this comment.
From the top of my head, I could envision four error cases that can happen:
- The user doesn't have permission to view job invocations at all (backend should give 403 unauthorized)
- The user doesn't have permission to view this particular job invocation (backend should give 404)
- The user has permission to view, but the job invocation doesn't exist (backend should give 404)
- The backend failing to process the request (think 500 ISE)
Should we distinguish 1 vs 2+3 vs 4?
With that being said, the old page showed "Not found" for all cases, except 4 so feel free treat this as optional.
There was a problem hiding this comment.
Would it make sense to include the backend message to the page? It could be more informative without us needing to introduce some parsing logic, wdyt?
There was a problem hiding this comment.
Not sure if the backend says anything reasonable, but worth a try.
There was a problem hiding this comment.
In some cases the backend adds a nice message like for case 3 »Resource job_invocation not found by id '88'«
| <EmptyStateBody> | ||
| {sprintf( | ||
| __( | ||
| 'There is no job invocation with id %s or there are access permissions needed. Please contact your administrator if this issue continues.' |
There was a problem hiding this comment.
Since we know what the permissions required are, should we list them as we do on the unauthorized page?
|
|
||
| const jobInvocationsIndexPath = '/job_invocations'; | ||
|
|
||
| const JobInvocationEmptyState = ({ jobInvocationId }) => { |
There was a problem hiding this comment.
AFAIR we have some patterns in core:
- EmptyState: https://github.com/theforeman/foreman/tree/develop/webpack/assets/javascripts/react_app/components/common/EmptyState
- PermissionDenied: https://github.com/theforeman/foreman/tree/develop/webpack/assets/javascripts/react_app/components/PermissionDenied
Should we re-use them instead of implementing a brand new specific page for it? I mean if they are not feasible, that's okay, I'm just asking if it was considered? I might lag behind our UI changes, so not sure if those aren't marked for future removal.
There was a problem hiding this comment.
I did consider them, but found them a bit too restrictive. Otoh, if its worth it I can also extend them based on what we agree upon here
There was a problem hiding this comment.
What about them was too restrictive? might be worth to extend them as you said
236a8c6 to
afbb4da
Compare
|
@ofedoren @MariaAga @adamruzicka since the last time:
|
ofedoren
left a comment
There was a problem hiding this comment.
It's more a high level review, I'd rather leave the React stuff for someone else :)
- One of the reasons why I wanted to re-use or enhance and re-use something from Foreman is because we're still trying to unify the UI across the pages at some degree.
Looking at the recent change to models page in Foreman and here I see a bunch of common things, essentially a lot of repetitions, which makes it harder to unify in the future if we'd need some changes. Anyway, at least now these two pages have at least different strings:
It just feels odd :/
-
We'd rather add tests, especially since we can use AI for that, just make sure it actually tests something.
-
There is yet another custom error formatter. And AFAIU there is an idea of creating a general formatter that can be re-used then in other places. Should we wait for that or at least mark somehow to revisit this one and replace after the general/common one is available.
-
Some inline comments.
|
|
||
| const jobInvocationsIndexPath = '/job_invocations'; | ||
|
|
||
| const JobInvocationEmptyState = ({ jobInvocationId, errorMessage = null }) => { |
There was a problem hiding this comment.
We already use defaultProps for that
| const JobInvocationEmptyState = ({ jobInvocationId, errorMessage = null }) => { | |
| const JobInvocationEmptyState = ({ jobInvocationId, errorMessage }) => { |
Well I thought the point of these patterns was to declare the overall shape of things for the implementations to fill in their own content that could be site specific. To me they look fairly unified, I can extend the foreman pattern, but then we'd need to agree on which parts should be unified and which should stay modifiable |
|
this is now dependent on theforeman/foreman#10986 |
adamruzicka
left a comment
There was a problem hiding this comment.
This will also require a required foreman version bump in engine.rb, ideally as a separate commit.
0a17018 to
da1c2b0
Compare
da1c2b0 to
fa8441c
Compare
Hi, opened #1039 |
| onClick: () => visit(foremanUrl(jobInvocationsIndexPath)), | ||
| ouiaId: 'job-invocation-empty-state-go-to-job-invocations-button', | ||
| }} | ||
| secondaryActions={[ | ||
| { | ||
| label: __('Create a new job invocation'), | ||
| onClick: () => visit(foremanUrl('/job_invocations/new')), |
There was a problem hiding this comment.
It seems that ResourceLoadFailedEmptyState accepts urls, and uses react-router for the actions (which is faster than visit), could the onClicks be replaced with a url?
There was a problem hiding this comment.
I tried it out but didn't work for me, maybe because /job_invocations is still a rails index page?
There was a problem hiding this comment.
In what way did it not work? I tried it out locally and using
primaryAction={{
label: __('Go to job invocations'),
url: foremanUrl(jobInvocationsIndexPath),
ouiaId: 'job-invocation-empty-state-go-to-job-invocations-button',
}}
secondaryActions={[
{
label: __('Create a new job invocation'),
url: foremanUrl('/job_invocations/new'),
ouiaId: 'job-invocation-empty-state-create-new-job-invocation-button',
},
]}
Works, and navigates
There was a problem hiding this comment.
right, works for me to :) honestly, I don't know what was the issue last time I tried, sorry for the confusion
| const { status: permissionsApiStatus } = useAPI( | ||
| 'get', | ||
| currentPermissionsUrl, | ||
| { | ||
| key: CURRENT_PERMISSIONS, | ||
| } | ||
| ); |
There was a problem hiding this comment.
I do think its good to check if the permissions api failed, but I think this logic should be moved to core (in a new PR, unrelated to this one)
There was a problem hiding this comment.
I'm not sure how to go about this, since permissionsApiStatus is one of the things we use to find what errorMessage to send to the ResourceLoadFailedEmptyState. Can you suggest where should I put that logic in core and how I'd trigger it?
There was a problem hiding this comment.
Sorry my bad, I rechecked, and the data from currentPermissionsUrl is already in useForemanPermissions in the empty state, so no need to call it at all.
Foreman ui meta data (which goes to useForemanPermissions)
permissions: (User.current.admin? ? Permission.all : User.current.permissions).pluck(:name),
https://github.com/theforeman/foreman/blob/07ce9438d216cf7d1cef3763de66b83f22669c16/app/helpers/application_helper.rb#L422
api call to currentPermissionsUrl
@current_permissions = @user.admin? ? Permission.all : @user.permissions
https://github.com/theforeman/foreman/blob/07ce9438d216cf7d1cef3763de66b83f22669c16/app/controllers/api/v2/permissions_controller.rb#L32
There was a problem hiding this comment.
makes sense, so I removed those currentPermissionsUrl calls
MariaAga
left a comment
There was a problem hiding this comment.
Since the empty state unloads the job invocation page when the api is done, with an error, it causes some components (JobInvocationToolbarButtons) to unload to fast and cause console warnings. I think this could be fixed by doing something like toolbarButtons={ jobInvocationApiStatus === API_STATUS.SUCCESS && <JobInvocationToolbarButtons jobId={id} data={items} />}
fa8441c to
8f0283f
Compare
thanks for noticing, I added your suggestion, but I had to also add some isMounted conditions to JobInvocationToolbarButtons for the console warning to stop |
8f0283f to
5ce73bc
Compare
|
@MariaAga Hi, I think I've addressed all the comments, can you plrease take a look again? |
MariaAga
left a comment
There was a problem hiding this comment.
I ran an AI review, and it caught that with the api permisisons removal, the toolbar and the actions, dont get to see the correct permissions, so it will be good to switch out the permissions checks in webpack/JobInvocationDetail/CheckboxesActions.js and webpack/JobInvocationDetail/JobInvocationToolbarButtons.js with the usePermissions hook. (this causes the buttons next to the search bar to always be disabled)
Also missing a test to make sure the empty state loads.
| breadcrumbOptions={breadcrumbOptions} | ||
| toolbarButtons={<JobInvocationToolbarButtons jobId={id} data={items} />} | ||
| toolbarButtons={ | ||
| jobInvocationApiStatus === API_STATUS.SUCCESS && ( |
There was a problem hiding this comment.
The STATUS constant from foremanReact/constants has keys PENDING, RESOLVED, and ERROR — there is no SUCCESS. This comparison always evaluates to false, so
JobInvocationToolbarButtons is never rendered regardless of API state. Should be API_STATUS.RESOLVED.
| return null; | ||
| }, [jobInvocationApiStatus, jobInvocationErrorMessage]); | ||
|
|
||
| const httpStatus = jobInvocationHttpStatus; |
There was a problem hiding this comment.
Used once, no transformation. Pass jobInvocationHttpStatus directly to the prop.
| export const visit = jest.fn(url => { | ||
| global.window.location.href = url; | ||
| }); |
| import { foremanUrl } from 'foremanReact/common/helpers'; | ||
| import ResourceLoadFailedEmptyState from 'foremanReact/components/common/EmptyState/ResourceLoadFailedEmptyState'; | ||
|
|
||
| const jobInvocationsIndexPath = '/job_invocations'; |
There was a problem hiding this comment.
should live in JobInvocationConstants.js alongside jobInvocationDetailsUrl.
5ce73bc to
aaa3633
Compare

…nvocation IDs
SAT-44544