-
Notifications
You must be signed in to change notification settings - Fork 6
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
🐛 Handle server side redirects #586
Conversation
Codecov ReportAttention:
Additional details and impacted files@@ Coverage Diff @@
## main #586 +/- ##
==========================================
+ Coverage 71.27% 73.29% +2.01%
==========================================
Files 211 212 +1
Lines 4286 4314 +28
Branches 1161 1168 +7
==========================================
+ Hits 3055 3162 +107
+ Misses 1196 1108 -88
- Partials 35 44 +9 ☔ View full report in Codecov by Sentry. |
Maybe we should add an action for form steps as well: action: Edit: this is already the case 🤦 |
1724c36
to
1521d31
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.
Found my unpublished comment 😬
src/sdk.js
Outdated
newUrl = `${window.location.origin}${window.location.pathname}/${redirectPath}${ | ||
query.size ? '?' + query : '' | ||
}`; |
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.
if redirectPath
has query params and there's an uncontrolled query param like foo=bar
from the CMS, you will end up with:
https://example.com/base-path/stap/step-1?submissionId=123?foo=bar
which is of course not the correct form. I think getRedirectPathname
should return an object with the URL parts:
{
"path": relativePath,
"query": queryObj,
}
and then depending on the useHashRouting
compose the final URL in this method.
Note that this (probably) works correctly with hash-based routing.
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.
if
redirectPath
has query params and there's an uncontrolled query param likefoo=bar
from the CMS, you will end up with:
But shouldn't we keep unrelated query params? If the CMS needs foo
to work correctly and we strip it off, it can break things, can it?
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 we need to keep it, but now the implementation is naive in that there will only be before-hash query params or after-hash query params while both can be present at the same time - the problem is the double ?
in the resulting URL if you don't use hash based routing.
So you need to:
- Server loads URL with query params, possibly with CMS-required params
- SDK initializes
- SDK does
pick<query, '_of_action' | '_of_action_args'>
- SDK processes action & action args into the (relative) path & SDK-specific query params
- SDK builds a new URL:
- Join basePath + relative path
- Merge (original) params with SDK-specific query params from 4.
- Delete
_of_action
and `_of_action_args params
- SDK does
pushState
with newly constructed URL- it retains the "unrelated" query params
- it drops the private _action routing params
- it merges in any query params required by the SDK (like
submission_uuid
and?productId=...
for appointments)
The current implementation fails at 5.2 - the merging is not done properly
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 the new implementation should cover this
src/sdk.spec.js
Outdated
'/?_of_action=stap&_of_action_params=next_step%3Dstep-1&unrelated_q=1', | ||
'http://localhost/?unrelated_q=1#/startpagina', // SDK redirects to start page |
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.
that's odd, shouldn't it go to ...#/stap/step-1
?
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 suspect the api mocks to not cover an api call, so it goes back to the start page as it doesn't know about step-1
but I'm not sure about 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.
Edit, figured out while adding tests:
open-forms-sdk/src/sdk.spec.js
Lines 177 to 212 in c87f004
it.each([ | |
// With a base path: | |
[ | |
'/base-path/?_of_action=afspraak-annuleren&unrelated_q=1', | |
'http://localhost/base-path?unrelated_q=1#/afspraak-annuleren', | |
], | |
[ | |
'/base-path/?_of_action=afspraak-maken&unrelated_q=1', | |
'http://localhost/base-path?unrelated_q=1#/afspraak-maken', | |
], | |
[ | |
'/base-path/?_of_action=cosign&_of_action_params=submission_uuid%3Dabc&unrelated_q=1', | |
'http://localhost/base-path?unrelated_q=1#/cosign?submission_uuid=abc', | |
], | |
[ | |
'/base-path/?_of_action=resume&_of_action_params=next_step%3Dstep-1&unrelated_q=1', | |
'http://localhost/base-path?unrelated_q=1#/stap/step-1', | |
], | |
// Without a base path: | |
[ | |
'/?_of_action=afspraak-annuleren&unrelated_q=1', | |
'http://localhost/?unrelated_q=1#/afspraak-annuleren', | |
], | |
[ | |
'/?_of_action=afspraak-maken&unrelated_q=1', | |
'http://localhost/?unrelated_q=1#/afspraak-maken/producten', // SDK redirects to producten | |
], | |
[ | |
'/?_of_action=cosign&_of_action_params=submission_uuid%3Dabc&unrelated_q=1', | |
'http://localhost/?unrelated_q=1#/cosign?submission_uuid=abc', | |
], | |
[ | |
'/?_of_action=resume&_of_action_params=next_step%3Dstep-1&unrelated_q=1', | |
'http://localhost/?unrelated_q=1#/startpagina', // SDK redirects to start page | |
], | |
])( |
The behavior is different depending on having a basepath or not with hash routing, something might be going wrong
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.
please investigate further what's causing 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.
Tested locally:
When accessing localhost:3000/?_of_action=resume&_of_action_params=%7B%22next_step%22%3A%22test-step%22%7D
(localhost:3000/?_of_action=resume&_of_action_params=encodeURIComponent(JSON.stringify({next_step: 'test-step'}))
, I am redirected to startpagina
as expected, because I haven't started the form (it works and I get redirected to http://localhost:3000/#/stap/test-step
otherwise).
So I think having a basepath breaks for now. Looking into it
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.
so the resume flow relies on the submission_id
(query) param, as that gets loaded from the backend first before the actual step is rendered. Many of these components are wrapped in a <RequiredSubmission>
component/decorator.
Probably best to manually test the behaviour with a real submission, it doesn't make sense to redirect to a form/submission that's not in your session anyway.
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 ended up being a bit more complicated:
We have to differentiate between the react router base path and the "real" browser base path with hash based routing. In hash based routing, router base path will always be "", but we need the extra browserBasePath
to be able to correctly set this.clientBaseUrl
, as the CMS basepath needs to be taken into account
19a8de1
to
c87f004
Compare
Note for later: |
The backend is now agnostic to URL routing/hash based routing - it will always redirect back to the URL that was used to start the form and provide action & action params query arguments that specify the target for the frontend. The frontend parses this action & the params and maps it to the intended client side routes, effectively decoupling implementation details between backend and frontend. Note that this requires the SDK to operate correctly in two of the tree main steps in this flow: 1. SDK must correctly derive the 'base URL' for the form, irrespective of whether hash based routing is used or not. Fragments should *not* be sent to the backend, since they are ignored anyway. 2. The backend uses the URL supplied from 1. and append the action/action params from the context of the backend action/validation that was performed. 3. The SDK must correctly interpret the action and its params and route to the appropriate part of the application. TODO: using this pattern, we can probably refactor the _start=1 flow from the backend too, this can likely be converted to _of_action=startSubmission.
a939e9d
to
54d1198
Compare
Fixes open-formulieren/open-forms#3362
Linked to open-formulieren/open-forms#3574