Skip to content

[Cases] Save draft user comment#146327

Merged
js-jankisalvi merged 50 commits intoelastic:mainfrom
js-jankisalvi:save-draft-user-cmment
Dec 14, 2022
Merged

[Cases] Save draft user comment#146327
js-jankisalvi merged 50 commits intoelastic:mainfrom
js-jankisalvi:save-draft-user-cmment

Conversation

@js-jankisalvi
Copy link
Contributor

@js-jankisalvi js-jankisalvi commented Nov 24, 2022

Summary

This PR saves user's draft comment in a session storage.

Fixed below scenarios requested by users:

  • When I’m writing a new comment and someone posts a new comment before me
  • When I’m writing a new comment and someone updates an old comment
  • When I’m editing an old comment and someone posts a new comment
  • When I’m editing an old comment and someone updates an old comment
Draft.comment.mov

Checklist

Delete any items that are not applicable to this PR.

Passed Flakey tests suite:

https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/1647

@js-jankisalvi js-jankisalvi changed the title Save draft user cmment [Cases] Save draft user comment Nov 24, 2022
@js-jankisalvi js-jankisalvi self-assigned this Nov 24, 2022
@js-jankisalvi js-jankisalvi requested a review from a team November 30, 2022 16:12
@js-jankisalvi js-jankisalvi marked this pull request as ready for review November 30, 2022 16:12
@js-jankisalvi js-jankisalvi requested a review from a team as a code owner November 30, 2022 16:12
@elasticmachine
Copy link
Contributor

Pinging @elastic/response-ops-cases (Feature:Cases)

@js-jankisalvi js-jankisalvi added the release_note:skip Skip the PR/issue when compiling release notes label Nov 30, 2022
bottomRightContent?: React.ReactNode;
caseTitle?: string;
caseTags?: string[];
draftCommentStorageKey?: string;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I'm understanding the MarkdownEditorForm correctly, it's used by the description and the comments. I think we could make it a required prop if we applied the same logic you have here for the description and then we wouldn't need to check if it is defined. Would it be complicated to add it to description?

Copy link
Contributor Author

@js-jankisalvi js-jankisalvi Dec 2, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding draftCommentStorageKey to description is not complicated. I thought it as an optional feature, hence optional prop. I am okay to make it mandatory prop.

Correction:
we don't need to add it to description as we are creating storage key in UserActionMarkdown. So it handles storing draft for comments and description while editing them. I will make it a required key and remove the check.

Now that you mentioned description, do we need to store draft description while user is creating a case?
Right now I have handled Edit scenarios after the case is created.

Copy link
Contributor

@jonathan-buttner jonathan-buttner Dec 2, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need to store draft description while user is creating a case?

Na, let's just do the edit scenario 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In that case I will keep draftCommentStorageKey?: string; optional as MarkdownEditorForm is also used in description of create cases.


useDebounce(
() => {
if (isFirstRender.current) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just curious, how come we want to ignore the first render? Is it because it would store the initial value before the user starts typing?

Could we instead just compare the field.value with initialValue and see if they're equal?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, every time you visit a case, you get an empty newComment key stored in the session eventhough user didn't touch the markdown.
i.e. xpack.cases.caseView.{caseId}.{newComment}.markdownEditor
So we want to ignore first render so that it doesn't store newComment markdown key with empty value.

Unfortunately initialValue is undefined for newComment markdown until submit(add comment) is triggered. That's why initialValue is not helpful to detect first render.


useEffect(() => {
if (initialValue && initialValue !== field.value) {
field.setErrors([{ message: i18n.COMMENT_VERSION_CONFLICT_ERROR }]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thinking about this more, do we really need the user to refresh? We just want them to be aware that something changed under them. Maybe an alternative would be to some warning text that it change and saving will overwrite 🤷‍♂️

If we set the errors we still let the user save the change but nothing happens, I wonder if we should disable the save button if want to continue with this type of solution.

Copy link
Contributor Author

@js-jankisalvi js-jankisalvi Dec 2, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the first approach, showing warning text instead of error as user is already in writing a comment and suddenly disabling the save button is a preventive action. So just a text warning suggesting that comment has changed, and letting user decide makes sense.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So just a text warning suggesting that comment has changed, and letting user decide makes sense.

Sounds good to me!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So just a text warning suggesting that comment has changed, and letting user decide makes sense.

Sounds good to me!

image

@js-jankisalvi js-jankisalvi added release_note:enhancement and removed release_note:skip Skip the PR/issue when compiling release notes labels Dec 2, 2022

removeItemFromSessionStorate(draftStorageKey);

/* had to add to this check that session key is removed to avaoid weird issue that on reset
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: avaoid -> avoid

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤦

caseId: string,
commentId: string
): string => {
const appIdKey = appId !== '' ? appId : 'kibana';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's default it to cases instead of kibana.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are returning key as return cases.${appIdKey}.${caseIdKey}.${commentIdKey}.markdownEditor so if we put cases when no appId, it will be cases.cases.${caseId}.${commentId}.markdownEditor

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shall I put const appIdKey = appId !== '' ? appId : 'default'; ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think is better to put const appIdKey = appId !== '' ? appId : 'cases';

Copy link
Contributor

@peteharverson peteharverson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Functionally this LGTM. Suggest any other edits to the UX, such as making the messaging clearer when the comment being edited has been updated, be done in a follow-up.

@cnasikas
Copy link
Member

@elasticmachine merge upstream

Comment on lines +45 to +58
if (isFirstRender.current) {
if (isEmpty(sessionValue) && !isEmpty(field.value)) {
/* this condition is used to for lens draft comment,
when user selects and visualization and comes back to Markdown editor,
it is a first render for Markdown editor, however field has value of visualization which is not stored in session
hence saving this item in session storage
*/

setSessionValue(field.value);
}
isFirstRender.current = false;
return;
}
setSessionValue(field.value);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not 100% sure and maybe I miss something but I think this can be simplified as:

Suggested change
if (isFirstRender.current) {
if (isEmpty(sessionValue) && !isEmpty(field.value)) {
/* this condition is used to for lens draft comment,
when user selects and visualization and comes back to Markdown editor,
it is a first render for Markdown editor, however field has value of visualization which is not stored in session
hence saving this item in session storage
*/
setSessionValue(field.value);
}
isFirstRender.current = false;
return;
}
setSessionValue(field.value);
if (isFirstRender.current) {
isFirstRender.current = false;
}
setSessionValue(field.value);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just saw this test should not update the session value when it is first render so probably I am wrong 🙂.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm.. may be. let me verify this in local

Copy link
Contributor Author

@js-jankisalvi js-jankisalvi Dec 14, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

spoke too early. It fails the test with jest.advanceTimersByTime. better to not update it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Weird, with my code the test should not pass as it will update the value in the first render. Could you please remind me why we do not want to update the session value on the first render? I do not remember.

</MockHookWrapperComponent>
);

expect(result.container.querySelector('textarea')!.value).toEqual('value set in storage');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: this can be done expect(result.getByText('value set in storage')).toBeInTheDocument()

@kibana-ci
Copy link

💚 Build Succeeded

Metrics [docs]

Module Count

Fewer modules leads to a faster build time

id before after diff
cases 515 518 +3

Async chunks

Total size of all lazy-loaded chunks that will be downloaded as the user navigates the app

id before after diff
cases 348.1KB 349.8KB +1.7KB

Page load bundle

Size of the bundles that are downloaded on every page load. Target size is below 100kb

id before after diff
cases 127.1KB 127.4KB +240.0B
Unknown metric groups

ESLint disabled in files

id before after diff
osquery 1 2 +1

ESLint disabled line counts

id before after diff
enterpriseSearch 19 21 +2
fleet 60 66 +6
osquery 109 115 +6
securitySolution 445 451 +6
total +20

Total ESLint disabled count

id before after diff
enterpriseSearch 20 22 +2
fleet 69 75 +6
osquery 110 117 +7
securitySolution 521 527 +6
total +21

History

To update your PR or re-run it, just comment with:
@elasticmachine merge upstream

cc @js-jankisalvi

Copy link
Member

@cnasikas cnasikas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code LGTM! Tested without any issues. Great job 🚀!

@js-jankisalvi
Copy link
Contributor Author

Code LGTM! Tested without any issues. Great job 🚀!

Thank you for the help :)

@js-jankisalvi js-jankisalvi merged commit 412fa42 into elastic:main Dec 14, 2022
@kibanamachine kibanamachine added the backport:skip This PR does not require backporting label Dec 14, 2022
jloleysens added a commit to jloleysens/kibana that referenced this pull request Dec 14, 2022
* main: (21 commits)
  [Profiling] Remove link to 'Other' bucket (elastic#147523)
  [Synthetics UI] Add missing configuration options to the add/edit monitor forms (elastic#147265)
  [DOCS] Updates what's new pages (elastic#147483)
  [Fleet][Endpoint][RBAC V2] Update fleet router and config to allow API access via RBAC controls (elastic#145361)
  [Guided onboarding] Update guide IDs (elastic#147348)
  [Synthetics] Add synthetics settings alerting default (elastic#147339)
  [Security Solution][Endpoint] Fix Policy form being displayed as Read Only when displayed in Fleet pages (elastic#147212)
  [Cases] Save draft user comment (elastic#146327)
  [API Docs] Fix `--plugin` filter (elastic#147500)
  [Fleet] added a logic to use `destinationId` when tagging imported SOs (elastic#147439)
  Do not skip UPDATE_TARGET_MAPPINGS if upgrading to a newer stack version (elastic#147503)
  [Discover] Validate if Data View time field exists on Alert creation / editing (elastic#146324)
  [Discover] Fix Discover navigation from Lens embeddable (elastic#147000)
  Allow users to Update API Keys (elastic#146237)
  Update dependency xstate to ^4.35.0 (main) (elastic#147463)
  [Behavioral Analytics] Remove feature flag to hide functionality (elastic#147429)
  [Fleet] Add agent policy `inactivity_timeout`experimental setting (elastic#147432)
  [APM] Switching service groups from grid to flex layout (elastic#147448)
  [Fleet] Add missing endpoints to openApi specs (elastic#147452)
  [AO] Allow providing custom time range for Alert Summary Widget (elastic#147253)
  ...
@cnasikas cnasikas added the Team:ResponseOps Platform ResponseOps team (formerly the Cases and Alerting teams) t// label Jan 17, 2023
@js-jankisalvi js-jankisalvi deleted the save-draft-user-cmment branch October 6, 2023 07:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport:skip This PR does not require backporting Feature:Cases Cases feature release_note:enhancement Team:ResponseOps Platform ResponseOps team (formerly the Cases and Alerting teams) t// v8.7.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants