Skip to content
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

[Security Solution][Endpoint] Response Console framework support for argument value selectors #148693

Conversation

paul-tavares
Copy link
Contributor

@paul-tavares paul-tavares commented Jan 10, 2023

Summary

  • PR adds the ability for Commands to define custom value selectors - components that will be rendered as the value when the Argument name is entered in the Console. These Argument Selectors can then provide the user with a better UX for selecting data that is not easily entered in the console via text input.
  • Introduces a File picker Argument Selector (not yet being used by real commands) that will be used in upcoming features.
  • Introduces a new mustHaveValue property to the definition of a command's argument. Usage (from JSDocs):
/**
   * If argument (when used) should have a value defined by the user.
   * Default is `false` which mean that argument can be entered without any value - internally the
   * value for the argument will be a boolean `true`.
   * When set to `true` the argument is expected to have a value that is non-boolean
   * In addition, the following options can be used with this parameter to further validate the user's input:
   *
   * - `non-empty-string`: user's value must be a string whose length is greater than zero. Note that
   *   the value entered will first be `trim()`'d.
   * - `number`: user's value will be converted to a Number and ensured to be a `safe integer`
   * - `number-greater-than-zero`: user's value must be a number greater than zero
   */

PR Testing

Since there are currently no commands that use this new framework, the following can be used access a test command in the console:

  1. On the Endpoint List page, add the following to the URL: &show_upload=1. Example: http://localhost:5601/app/security/administration/endpoints?page_index=0&page_size=10&show_upload=1
  2. use the upload command for dev testing purposes only. It is defined with two arguments that have ArgumentSelector: --file and --mock

** 🔴 NOTE:**: this dev command will be deleted from the code prior to merging this PR or soon after it is merged.


More about Argument Selectors

When an argument, having an SelectorComponent defined, is typed into the console, the UI provided by that selector component will be inserted as the value to the argument name. It is up to the Argument Selector to provide the desired UI to the user. Argument Selectors have the following behaviors:

  1. The argument name typed by the user will be replaced with a UI that show the argument name as readonly and inserts the argument selector component into the value section. Example: user types --file, which is replaced in the console's input with --file=[argument selector UI here]
  2. [Left] / [Right] keys will jump over the entire argument. It does not move through each letter once the argument name has been replaced with the UI for displaying the argument selector
  3. [Delete] / [Backspace] keys will delete the entire argument from the input area
  4. Display content of Arguments that are displayed with Argument Selectors can not be selected with the mouse (click and highlight)
  5. Command input history (Menu shown when [ArrowUP] is clicked) and the console's command output area (after a command has been [Enter]'d) will display a text representation of the value provided by the Argument Selector.
  6. When selecting a previously entered command from the input history ([ArrowUp]), the textual representation of any argument with Argument Selector will not be applied to the console's input area. Only the argument name will be entered (triggering the selector to be used again)

Some limitations

Some current limitation that may be addressed in subsequent PR(s):

  1. Highlight of text and replacement (via keyboard key click) still works - as long as the selection does not traverse an argument that is using an argument selector.
  2. When multiples of the same argument (that have value selectors) are used, and one instance of this argument already exists, and the user attempts to enter another BEFORE the existing instance, the newly entered argument will "steal" the value from the now second instance
  3. Pasting data into the console's input area that includes argument's that are defined with an Argument selector will work as expected with the exception that if the pasted data had a value for that argument, it will be displayed as well (not removed). It is up to the user to delete it.

NOTE
The screen capture below shows argument selectors for two arguments - file and mock. These are meant to just show the interaction and usage of the argument selectors. The file argument selector UX could changed once we get feedback from the UX team.

olm-5711-console-argument-selectors

Checklist

@paul-tavares paul-tavares added release_note:skip Skip the PR/issue when compiling release notes Team:Defend Workflows “EDR Workflows” sub-team of Security Solution v8.7.0 labels Jan 10, 2023
@paul-tavares paul-tavares self-assigned this Jan 10, 2023
@paul-tavares paul-tavares marked this pull request as ready for review January 18, 2023 20:24
@paul-tavares paul-tavares requested a review from a team as a code owner January 18, 2023 20:24
@elasticmachine
Copy link
Contributor

Pinging @elastic/security-defend-workflows (Team:Defend Workflows)

Copy link
Member

@ashokaditya ashokaditya left a comment

Choose a reason for hiding this comment

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

Took an initial pass at reviewing this. The file selector popup UX looks awesome when I tried it out. 🤩

I noticed something that you probably already know but I thought I'll mention it since it's not listed in the limitations section. That is, whenever the file selector is empty (no files are selected) the popup opens up on every cursor move (left or right) no matter where the cursor is and even if I close the popup. I would expect that once I close the popup it should not show up unless I click on the file argument value ("click to select file"). See this clip. Once a file is selected the popup shows up again only when the file argument value ("click to select file") is clicked.

upload-argument

For later UX consideration,

  1. Once a file is selected and the file selector popup is opened again I see the same message as when no file was selected. Maybe show a different message like "Select a file to replace the current one" or similar.
  2. When the command is executed, the --file argument value shows just the file name. Should we show the absolute path of the file instead if that's useful info?

Comment on lines 23 to 25
.popoverAnchor {
display: block;
}
Copy link
Member

Choose a reason for hiding this comment

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

Curios why the display style is needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

at some point I needed this, but looks like with the most current code, it's no longer needed. I will deleted it. Thanks for the feedback.

@@ -381,6 +323,70 @@ export const handleExecuteCommand: ConsoleStoreReducer<
);
}

if (argDefinition.mustHaveValue !== undefined && argDefinition.mustHaveValue !== false) {
Copy link
Member

Choose a reason for hiding this comment

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

This file is now showing me cyclomatic complexity warning now and that it is at 32 now and exceeds 20 which is the limit. Consider adding an eslint ignore.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's a warning right? so no need to ignore it. I'll have to come back at some point and break it up

/**
* If the argument is required to be entered by the user. NOTE that this will only validate that
* the user has entered the argument name - it does not validate that the argument must have a
* value. Argument's that have no value entered by the user have (by default) a value of
Copy link
Member

Choose a reason for hiding this comment

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

nit: typo Arguments...

Copy link
Contributor

@gergoabraham gergoabraham left a comment

Choose a reason for hiding this comment

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

Awesome modification! I got nothing major with my current understanding, only small findings/questions - but those can be managed in subsequent PRs.

Comment on lines 238 to 242
/**
* The instance of the argument in the current command. This is a zero-based number indicating
* which instance of the argument is being rendered.
*/
argInstance: number;
Copy link
Contributor

Choose a reason for hiding this comment

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

the name for this field is a bit misleading to me: should it be maybe argIndex?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I guess I could have renamed it argIndex. I went with argInstance to kind of match the value I was already using internally and I just exposed it to the argument value component. "Instance" to indicate which instance of the argument usage is being rendered.

Copy link
Contributor

Choose a reason for hiding this comment

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

I see, thanks! would you consider to rename it? reading instance indicates to me that this is an object, an object instance of a class, and definitely not a number.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ohh. I see what you meant by instance. Yes, I will rename it

return i18n.translate(
'xpack.securitySolution.console.commandValidation.mustHaveNonBlankValue',
{
defaultMessage: 'Argument --${argName} must have a value',
Copy link
Contributor

Choose a reason for hiding this comment

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

is this intentionally the same as the string for mustHaveValue?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

🤦

No. It should not be a duplicate. I will change to use the one above.

type InputAreaStateAction = ConsoleDataAction & {
type:
| 'updateInputPopoverState'
| 'updateInputHistoryState'
| 'clearInputHistoryState'
| 'updateInputTextEnteredState'
| 'updateInputPlaceholderState'
| 'setInputState';
| 'setInputState'
| 'updateInputCommandArgState';
};

export const handleInputAreaState: ConsoleStoreReducer<InputAreaStateAction> = (
Copy link
Contributor

Choose a reason for hiding this comment

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

for this function I'm seeing the eslint(complexity) warning: Arrow function has a complexity of 31. Maximum allowed is 20.

I think this could be refactored in a subsequent PR

Copy link
Contributor Author

Choose a reason for hiding this comment

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

correct. This one also needs to be refactored and broken down

@@ -131,16 +129,13 @@ const createCommandHistoryEntry = (
export const handleExecuteCommand: ConsoleStoreReducer<
Copy link
Contributor

Choose a reason for hiding this comment

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

this also has too large cyclomatic complexity according to the eslint rule

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yeah, I been meaning to break it out into separate functions to do the validations.

@paul-tavares
Copy link
Contributor Author

Thanks @ashokaditya for the feedback.

Re:

"...the file selector is empty (no files are selected) the popup opens up on every cursor move (left or right) no matter where the cursor is and even if I close the popup.

Yeah, I noticed this as well. I did not spent too much time on the UX of the file picker as part of this PR and I do know that particular selector does need to be adjusted to be "smarter" about the states it supports. I might even have to introduce a "state store" per argument selector so that they can keep state for their own use cases. I added this item to the internal issue that is tracking this work for consideration

**re: **

"1. Once a file is selected and the file selector popup is opened again I see the same message as when no file was selected. Maybe show a different message like "Select a file to replace the current one" or similar.

I did not see the need to change the text since it is generic. Do you find that it could be confusing to the user as to what the outcome will be by selecting another file?

Re:

  1. When the command is executed, the --file argument value shows just the file name. Should we show the absolute path of the file instead if that's useful info?

I don't think we have access to the full file path from the File DOM interface.

@paul-tavares
Copy link
Contributor Author

@ashokaditya

FYI - for this item:

"...the file selector is empty (no files are selected) the popup opens up on every cursor move (left or right) no matter where the cursor is and even if I close the popup.

I have made the change to the framework and the File picker to keep state, so the "I'm always open when you move the cursor" will not happen anymore.

Thansk again for the feedback.

@kibana-ci
Copy link
Collaborator

💛 Build succeeded, but was flaky

Failed CI Steps

Test Failures

  • [job] [logs] FTR Configs #33 / spaces api with security copy to spaces user with no access from the default space single-namespace types "after each" hook for "should return 403 when copying to space without conflicts or references"

Metrics [docs]

Module Count

Fewer modules leads to a faster build time

id before after diff
securitySolution 3557 3563 +6

Async chunks

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

id before after diff
securitySolution 12.8MB 12.8MB +11.0KB
Unknown metric groups

ESLint disabled in files

id before after diff
securitySolution 75 76 +1

Total ESLint disabled count

id before after diff
securitySolution 500 501 +1

History

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

cc @paul-tavares

Copy link
Member

@ashokaditya ashokaditya left a comment

Choose a reason for hiding this comment

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

🚢 it!

@paul-tavares paul-tavares merged commit 9ac065a into elastic:main Jan 25, 2023
@kibanamachine kibanamachine added the backport:skip This commit does not require backporting label Jan 25, 2023
@paul-tavares paul-tavares deleted the task/olm-5711-console-arg-value-selector-support branch January 25, 2023 21:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backport:skip This commit does not require backporting release_note:skip Skip the PR/issue when compiling release notes Team:Defend Workflows “EDR Workflows” sub-team of Security Solution v8.7.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants