[App Search] Final Document Creation API, Logic, & Summary/Error views#86822
[App Search] Final Document Creation API, Logic, & Summary/Error views#86822cee-chen merged 10 commits intoelastic:masterfrom
Conversation
- errors can/should be shown in the EuiFlyoutBody banner (better UX since the JSON/file is right there for reference) vs its own page - No need to distinguish between ShowErrorSummary and ShowSuccessSummary + placeholder Summary view for now
- split up into subcomponents for easier reading/testing
|
@JasonStoltz Since so much code was refactored from the standalone UI, it would be awesome if you could go through and confirm/check off off the QA steps in the PR description to confirm that all behavior is still functioning as before. Please feel free to go beyond them also try and break this component as much as possible. Thanks again, I know this is a super huge PR and tried to split the commits into logical / separate pieces as much as possible (but there's still just a ton of code/tests). |
| const mount = (defaults?: object) => { | ||
| if (!defaults) { | ||
| resetContext({}); | ||
| } else { | ||
| resetContext({ | ||
| defaults: { | ||
| enterprise_search: { | ||
| app_search: { | ||
| document_creation_logic: { | ||
| ...defaults, | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| }); | ||
| } |
There was a problem hiding this comment.
I'm thinking about writing a reusable test helper for this logic at some point in the future 🤔 some day!!
There was a problem hiding this comment.
I'd be cool if it could extract the path from the logic automatically.
const mount = new Mounter(EngineLogic)
...
mount()
mount({ engineName: "foo" })
| // NOTE: I can't seem to reproduce this in a production setting. | ||
| it('handles errors returned from the API', async () => { |
There was a problem hiding this comment.
I'm not sure if I should keep this comment or not, I haven't been able to actually QA/repro this functionality (getting a summary.errors response) in production, but our documents endpoint does seem to indicate it's there (if I'm reading the Ruby code correctly, which it's very possible I'm not).
That being said there's other scenarios that realistically wouldn't happen that we're still guarding for (such as a non-file or corrupted file being submitted) but not actively QAing for, so if that's one of those scenarios maybe I should just not leave the comment because it's not super helpful.
There was a problem hiding this comment.
I don't have an opinion here.
...earch/public/applications/app_search/components/document_creation/document_creation_logic.ts
Show resolved
Hide resolved
|
|
||
| try { | ||
| const responses = await Promise.all(promises); | ||
| const summary: DocumentCreationSummary = { |
There was a problem hiding this comment.
This is not a change request. I wonder if a summary would have been better as a selector. Store the raw response, and use a summary selector to parse up the response into a summary. Just something to break up this monster logic file a bit. The parseSummary could even be its own function that could be unit tested independently.
Instead of a monster summary you could even have more fine grained selectors that parse up the response as needed.
There was a problem hiding this comment.
Super interesting, I really like that idea! I think my only hangup there is storing response in state, just because that feels a little weird since we're not really using it directly. I definitely agree the merging logic/parseSummary does feel like it could be a separate utility for sure.
There was a problem hiding this comment.
Yeah, something to think about. State doesn't necessarily need to be used directly.
| if (summary.errors.length > 0) { | ||
| actions.setErrors(summary.errors); | ||
| } else { | ||
| actions.setSummary(summary); |
There was a problem hiding this comment.
A pattern to try out in the future would be to avoid individual set methods like this and instead have "success" and "failure" actions for listeners.
https://kea.js.org/docs/guide/concepts#listeners
So instead of calling setErrors on failure, and setSummary + setCreationStep on success ... call uploadDocumentsFailure or uploadDocumentsSuccess respectively, and handle setting errors, summary, and creationStep in reducers that listen for those actions.
There was a problem hiding this comment.
I'd love to have a team session (maybe a tech talk or even just a rubber ducky) about this sometime actually - I struggle a little bit about writing things "the Kea way" because it feels super unintuitive to me. Like, I get that using reducers saves us extra actions.something calls, but to me having the action fns listed is really explicit and helpful from a developer POV as opposed to me having to ctrl+F all over the file to figure out what all vars/values an action happens to affect (vs. having them listed clearly in a row in one place).
Definitely would be super helpful for me to discuss this as a team!
There was a problem hiding this comment.
Yeah, its advice I've heard more than once, not only in the Kea context but also for Redux. As far as I understand it is common wisdom. It would be interesting to hear arguments against though, for sure.
There was a problem hiding this comment.
Ya I'd def love to see a code diff of what this logic file for example would look like. The failure/success actions make sense & are fairly straightforward, what's tripping me up I think is what to replace setWarnings with since it feels like that goes along with setErrors and setSummary.
I think I'll leave this as-is for now since I'm not sure what the 'ideal' code should look like and I'd rather walk it through with someone who's got a clearer picture in their head than me, but I'm very very interested in doing that w/ someone next year!
There was a problem hiding this comment.
I think what's also extra weird for me for this specific logic file / use case is that the summary can also include "errors" (aka invalid documents) which is a failure state, so it's not 100% a success state... and it's really hard to wrap my mind around that / describe that accurately via method names other than just 'showSummary'/'setSummary'.
There was a problem hiding this comment.
I think I'm going to go ahead and merge this PR in since I have another test helper PR that depends on this work, but I'll see if I can't open up a new PR with your proposed changes as a follow-up and continue the discussion there.
There was a problem hiding this comment.
Oh yeah sorry, this is totally non-blocking feedback. I don't think you need to make that change now, or ever. I think there's low value in going back and rewriting things in that style. I think there can be value for new code that we write, however, which is why I opened up the conversation.
There was a problem hiding this comment.
I'm using that style now in a new logic file that I'm writing, so your value has been realized!! 😁
One thing that I'd also like to chat about (maybe in the PR that I'll be opening shortly) is naming for actions that follow this style. I'll admit a lot of this is habit on my part, but historically for functions I try to name them with verbSomething (e.g., setX, fetchY, getZ) instead of a name that sounds like a noun - this makes it slightly easier for me to distinguish functions from variables at a glance. That breaks a bit for this style of writing logic files, so I tried out writing story actions with an onX prefix - e.g., onUploadDocumentsSuccess, onFetchY, and so forth.
Let me know what you think about that naming convention? I'm a little torn because onX var names makes me think of jQuery and callback hells for some reason but I also think it makes sense in this context.
There was a problem hiding this comment.
Haha. I think a past tense verb would be appropriate for an action name.
uploadDocumentsSucceeded
So you're saying "what happened" in code as you write it.
There was a problem hiding this comment.
Hmm! My only thought is that could definitely be mistaken for a boolean at a glance - we've used past tense for boolean states in the standalone UI. Normally I prefer a isX/hasY/didZ prefix/naming to indicate bools, but we're currently not consistent on that.
It also could be I'm being too prescriptive about my var/fn/bool names based on my past experiences - I've found it super helpful previously, but it's potentially not anymore since we have Typescript and Typescript should in theory be checking and documenting types for us.
...earch/public/applications/app_search/components/document_creation/document_creation_logic.ts
Show resolved
Hide resolved
...ugins/enterprise_search/public/applications/app_search/components/document_creation/utils.ts
Show resolved
Hide resolved
...rch/public/applications/app_search/components/document_creation/document_creation_flyout.tsx
Show resolved
Hide resolved
|
|
||
| it('handles client-side errors', async () => { | ||
| const { http } = HttpLogic.values; | ||
| const promise = (http.post as jest.Mock).mockReturnValueOnce(new Error()); |
There was a problem hiding this comment.
I don't under stand this. How does promise get assigned a promise value here?. You're return value that you are returning is not a promise 🤔
There was a problem hiding this comment.
I'm not actually sure.... but for some reason the test fails / doesn't work without it :dead_inside: I think it's because of the await Promise.all(promises) on line 187.
JasonStoltz
left a comment
There was a problem hiding this comment.
I left a couple of small comments but I am generally OK with this code. I tested it out, it all works well. There's great unit test coverage. I have no concerns.
60b6b81 to
0fe6f1c
Compare
|
@elasticmachine merge upstream |
💚 Build SucceededMetrics [docs]Module Count
Async chunks
Distributable file count
History
To update your PR or re-run it, just comment with: |
elastic#86822) * [Setup] Server API route * [Cleanup] Remove unnecessary DocumentCreationSteps - errors can/should be shown in the EuiFlyoutBody banner (better UX since the JSON/file is right there for reference) vs its own page - No need to distinguish between ShowErrorSummary and ShowSuccessSummary + placeholder Summary view for now * Add DocumentCreationLogic file upload logic * Update creation form components to show error/warning feedback * Add final post-upload summary view - split up into subcomponents for easier reading/testing * [lint] oops, double licenses * [PR feedback] map -> forEach * [PR feedback] Reset form state on flyout close Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
#86822) (#87211) * [Setup] Server API route * [Cleanup] Remove unnecessary DocumentCreationSteps - errors can/should be shown in the EuiFlyoutBody banner (better UX since the JSON/file is right there for reference) vs its own page - No need to distinguish between ShowErrorSummary and ShowSuccessSummary + placeholder Summary view for now * Add DocumentCreationLogic file upload logic * Update creation form components to show error/warning feedback * Add final post-upload summary view - split up into subcomponents for easier reading/testing * [lint] oops, double licenses * [PR feedback] map -> forEach * [PR feedback] Reset form state on flyout close Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
Summary
This is the (hopefully!) final PR for the Document Creation component/flyout. It's significantly different from the standalone UI code in that it has been heavily cleaned up, modernized to use Kea logic/state, converted from custom/STUI components to EUI, and improved UI & UX wise (flyout over modal, more specific JSON errors, unifying DocumentCreationButtons, etc.).
In this final PR, users should be able to:
Screencaps
Paste text JSON upload
File upload
Invalid documents
QA
Valid documents testing
video-games.jsonin our standalone repo) and confirm that it uploads without errorsLarge documents testing
Error testing
invalidinto the textarea and submit.JSON.parse: unexpected character at line 1 column 1 of the JSON datatrue,false,null, or1into the textarea and submit.Document contents must be a valid JSON array or object.{"ok": {"__proto__": "not ok"}}into the textarea and submit.invalid. Name ittest.json(or anything .json)Invalid document testing
visitorkey and change the value from a number to text, e.g."visitors": "test",{"test.key": "value"}Checklist