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

[Ingest pipelines] Upload indexed document to test a pipeline #77939

Conversation

alisonelizabeth
Copy link
Contributor

@alisonelizabeth alisonelizabeth commented Sep 18, 2020

This PR adds the ability to upload a document(s) from an existing index when testing a pipeline.

Fixes #74796

Skipping release note as I think this change can fall under the general improvements made to the debugging workflow. Release note added on #74964.

How to review

Testing instructions

  1. Create a pipeline (for a sample pipeline, see: [Ingest pipelines] Test pipeline enhancements #74964).
  2. Create an index with at least one document, or use the kibana sample data. For example:
PUT /test/_doc/1
{
  "name": "John Doe"
}
  1. Click the "Add documents" link
  2. Add a sample document in the "Documents" code editor (you can just use the example in the help text)
  3. Click the "Import existing documents" accordion
  4. Add the index name and document ID of the document from step 2 and click "Import". Note: You can use the link to "Discover" to help find the document to use.
  5. Verify the document was added successfully, the document added in step 4 still exists, and you are able to run the pipeline.

UX

I'm interested in any design feedback on this. Two questions in particular on my end:

  • Does it make sense to have a single form to import documents (particularly in the case where you might want to add more than one document)? I first considered doing something similar to what we see in the mappings editor for the relationships parameter, where you could add multiple rows, but I'm not sure how useful this is.

Example from mappings editor:
Screen Shot 2020-09-22 at 1 37 31 PM

  • Thoughts on having the imported document populate the code editor below? I think we had initially discussed potentially having some sort of preview of the document you selected. However, I thought adding it to the code editor might be nice in the scenario where you might want to tweak the imported document, or also add a second sample document with JSON.

Screenshots

Initial view:
Screen Shot 2020-09-21 at 3 11 56 PM

Accordion open:
Screen Shot 2020-09-21 at 3 12 55 PM

Field errors:
Screen Shot 2020-09-21 at 3 13 00 PM

API error:
Screen Shot 2020-09-21 at 3 13 10 PM

@alisonelizabeth alisonelizabeth added v8.0.0 Team:Kibana Management Dev Tools, Index Management, Upgrade Assistant, ILM, Ingest Node Pipelines, and more release_note:skip Skip the PR/issue when compiling release notes v7.10.0 Feature:Ingest Node Pipelines Ingest node pipelines management labels Sep 18, 2020
@alisonelizabeth alisonelizabeth force-pushed the ingest_pipelines/add_existing_documents branch from 6b36ab5 to ef10904 Compare September 21, 2020 14:35
@alisonelizabeth alisonelizabeth marked this pull request as ready for review September 22, 2020 17:50
@alisonelizabeth alisonelizabeth requested a review from a team as a code owner September 22, 2020 17:50
@elasticmachine
Copy link
Contributor

Pinging @elastic/es-ui (Team:Elasticsearch UI)

@alisonelizabeth alisonelizabeth changed the title [WIP] [Ingest pipelines] Upload indexed document to test a pipeline [Ingest pipelines] Upload indexed document to test a pipeline Sep 22, 2020
Copy link
Contributor

@cjcenizal cjcenizal left a comment

Choose a reason for hiding this comment

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

🔥 This is awesome! I tested locally and the UX and code both look solid to me. I had some suggestions for enhancing the UX and making the code a bit more robust around some corner cases, but nothing worth blocking on.

Does it make sense to have a single form to import documents (particularly in the case where you might want to add more than one document)?

I found this UX to be fairly intuitive. I think it's useful and works well. I think adding a list of multiple indices and documents would add unnecessary complexity.

Thoughts on having the imported document populate the code editor below?

This was a really cool interaction! It was straightforward to load up documents and then find and review them in the code editor. I think we can provide more feedback when a document is successfully loaded, per one of my comments below.

'DISCOVER_APP_URL_GENERATOR'
);
const discoverUrl = await discoverUrlGenerator.createUrl({ indexPatternId: undefined });
setDiscoverLink(discoverUrl);
Copy link
Contributor

Choose a reason for hiding this comment

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

It seems possible for the component to be mounted at the time getDiscoverUrl is called, but unmounted by time time discoverUrl resolves. In that case, don't we want to move the umounted check a little later in the control flow?

const getDiscoverUrl = async (): Promise<void> => {
  const discoverUrlGenerator = services.urlGenerators.getUrlGenerator(
    'DISCOVER_APP_URL_GENERATOR'
  );
  const discoverUrl = await discoverUrlGenerator.createUrl({ indexPatternId: undefined });
  if (!unmounted) {
    setDiscoverLink(discoverUrl);
  }
};

Copy link
Contributor

@cjcenizal cjcenizal Sep 22, 2020

Choose a reason for hiding this comment

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

I'm not very familiar with how our URL generators work, so maybe this is a dumb question. What happens if Discover is disabled? Will discoverUrlGenerator or maybe discoverUrl resolve to undefined? In which case should we check that it's defined before consuming them?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for bringing this up!

I read through the docs again, and there is a isDeprecated flag that is returned from the url generator. I added a check for this in the code.

Copy link
Contributor

Choose a reason for hiding this comment

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

TIL about the isDeprecated flag! I tested this out locally by setting discover.enabled: false and I ended up getting a console error:

image

I read the docs a bit more closely and I think isDeprecated is intended to address the situation when an app has changed the way it stores state in its URLs, like the way Discover stores filter, query, and sort state in the URL. I'm guessing the above error is the intended way they surface a generator missing due to a plugin being disabled. In this case, I suggest use a try/catch to detect the scenario and handle it gracefully. Here's an example of what I mean, though ideally we'd inspect the type of error and bubble it up if it's not a no generator found error:

const getDiscoverUrl = async (): Promise<void> => {
  let isDeprecated;
  let createUrl;

  try {
    ({ isDeprecated, createUrl } = services.urlGenerators.getUrlGenerator(
      'DISCOVER_APP_URL_GENERATOR'
    ));
  } catch(e) {
    // Discover is not enabled.
    setDiscoverLink(undefined);
    return;
  }

  if (isDeprecated) {
    setDiscoverLink(undefined);
    return;
  }

  const discoverUrl = await createUrl({ indexPatternId: undefined });

  if (isMounted.current) {
    setDiscoverLink(discoverUrl);
  }
};

Copy link
Contributor

Choose a reason for hiding this comment

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

I created #78344 to improve the URL generator docs or API for this 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.

Ah, I see. Thanks for looking into this more closely! I've updated the code and added a comment with a link to the issue you created.

),
indexField: {
fieldLabel: i18n.translate(
'xpack.ingestPipelines.pipelineEditor.loadDocuments.table.indexColumnLabel',
Copy link
Contributor

Choose a reason for hiding this comment

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

Just wondering why table and column are used in the IDs here and on line 63?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oops! I started with a slightly different design, and forgot to update the the IDs here.

}
),
validationMessage: i18n.translate(
'xpack.ingestPipelines.pipelineEditor.loadDocuments.idRequiredError',
Copy link
Contributor

@cjcenizal cjcenizal Sep 22, 2020

Choose a reason for hiding this comment

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

Nit: should be idRequiredErrorMessage based on the guidelines.

}
),
validationMessage: i18n.translate(
'xpack.ingestPipelines.pipelineEditor.loadDocuments.indexRequiredError',
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: should be indexRequiredErrorMessage based on the guidelines.

}

onAddDocuments(document);
form.reset();
Copy link
Contributor

Choose a reason for hiding this comment

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

If you're adding multiple documents from the same index, it can be useful to retain the form state so you don't need to keep re-entering the index. Similarly, if the IDs happen to be sequential I can imagine it being useful to retain the document ID so you can just increment them easily. At the very least it's helpful to see which document you just added so you can refer to it when choosing the next one. For these reasons I suggest retaining the form state and removing this reset.

I think it would be helpful feedback to surface a success callout just above the form when the request is successful, like this:

image

Copy link
Contributor Author

Choose a reason for hiding this comment

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

These are great points. I removed the reset and added the success callout.

Screen Shot 2020-09-23 at 12 28 25 PM


const onAddDocumentHandler = useCallback(
(document) => {
const { documents: existingDocuments } = formatData();
Copy link
Contributor

@cjcenizal cjcenizal Sep 22, 2020

Choose a reason for hiding this comment

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

If the user clears out the content of the "Documents" editor so that it's entirely blank and then tries to import a document, they get this error:

image

We can fix this by changing this line to:

const { documents: existingDocuments = [] } = formatData();

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Great catch!

setIsLoadingDocument(true);
setLoadingDocumentError(undefined);

const { error, data: document } = await services.api.loadDocument(index, id);
Copy link
Contributor

@cjcenizal cjcenizal Sep 22, 2020

Choose a reason for hiding this comment

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

If the network's a bit slow and the user navigates away before this request resolves, then we'll get an error about updating state on an unmounted component:

image

It's a bit verbose, but here's one way we can solve this problem. We can track unmounted state like this:

  const isMounted = useRef(false);

  useEffect(() => {
    isMounted.current = true;

    return () => {
      isMounted.current = false;
    };
  }, []);

Then we can check this state before updating any state after the request resolves:

if (isMounted.current) {
  setIsLoadingDocument(false);

  if (error) {
    setLoadingDocumentError(error);
    return;
  }

  onAddDocuments(document);
  form.reset();
}

To reduce the verbosity we could extract the logic for tracking isMounted state into its own hook per the last few comments on this discussion: https://gist.github.com/jaydenseric/a67cfb1b809b1b789daa17dfe6f83daa

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Great catch! I've added a use_is_mounted hook.

addDocumentsButton: i18n.translate(
'xpack.ingestPipelines.pipelineEditor.importDocumentsAccordion.importButtonLabel',
{
defaultMessage: 'Import existing documents',
Copy link
Contributor

Choose a reason for hiding this comment

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

I found this phrasing a little confusing... "existing" had me trying to draw a comparison to a "non-existing" document, and "import" made me think of uploading a file. How about we use the verb "Add" instead, and instead of "existing" we clarify that the document comes from an index? I think this summarizes the help text of this section nicely.

image

<EuiSpacer size="l" />

{/* Documents editor */}
<UseField
Copy link
Contributor

Choose a reason for hiding this comment

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

WDYT of surfacing the number of documents somewhere? For example in the label:

image

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 like this idea. It would require some refactoring though, since the field label is currently defined in the form schema. I'm going to leave as-is for now.

@alisonelizabeth
Copy link
Contributor Author

Thanks for the very helpful review @cjcenizal! I addressed your feedback via 4b4c81b.

@mdefazio
Copy link
Contributor

Sorry I'm just now getting to this. Here's some ideas for the layout:

  • Using panels in flyouts adds a lot of extra UI noise and I think because it's an accordion we can just use euiColorLightestShade as the background color for the content inside it.
  • Because the index and document can be quite long, I think it's worthwhile to have these inputs on their own line. Yes it adds a lot of height to the section, but the user opened this up and can easily close it when done.
  • I moved the success message to be beside the button. If I continuously add documents, this can help avoid any jumping in the UI.
  • With this in mind, I added a 'Clear documents' text button at the top right of the documents window. Does what it says in case I want to swap out documents.
  • (Tiny nit, would be nice to hit enter from the document id input to add the document)
  • Does it make sense to use a search dropdown for the index selector like we have in Discover?

Here's a mockup illustrating these edits:
image

@alisonelizabeth alisonelizabeth requested a review from a team as a code owner September 24, 2020 16:47
@alisonelizabeth
Copy link
Contributor Author

alisonelizabeth commented Sep 24, 2020

@mdefazio thanks for the great suggestions! I've implemented most of them. Would you mind taking another look when you get a chance?

With this in mind, I added a 'Clear documents' text button at the top right of the documents window. Does what it says in case I want to swap out documents.

I like this idea. I think this work more closely aligns with #78183 though, so I will add this functionality as part of that PR.

Does it make sense to use a search dropdown for the index selector like we have in Discover?

I think this would be a nice enhancement. I'm going to put this on hold for now, but will consider adding this capability in a separate PR.

Screenshot with latest changes:
Screen Shot 2020-09-24 at 11 13 52 AM

Copy link
Contributor

@mdefazio mdefazio left a comment

Choose a reason for hiding this comment

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

LGTM!

@alisonelizabeth
Copy link
Contributor Author

@elasticmachine merge upstream

@kibanamachine
Copy link
Contributor

💚 Build Succeeded

History

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

@alisonelizabeth alisonelizabeth merged commit 88df93b into elastic:master Sep 28, 2020
@alisonelizabeth alisonelizabeth deleted the ingest_pipelines/add_existing_documents branch September 28, 2020 12:47
alisonelizabeth added a commit to alisonelizabeth/kibana that referenced this pull request Sep 28, 2020
gmmorris added a commit to gmmorris/kibana that referenced this pull request Sep 28, 2020
* master: (226 commits)
  [Enterprise Search] Added Logic for the Credentials View (elastic#77626)
  [CSM] Js errors (elastic#77919)
  Add the @kbn/apm-config-loader package (elastic#77855)
  [Security Solution] Refactor useSelector (elastic#75297)
  Implement tagcloud renderer (elastic#77910)
  [APM] Alerting: Add global option to create all alert types (elastic#78151)
  [Ingest pipelines] Upload indexed document to test a pipeline (elastic#77939)
  TypeScript cleanup in visualizations plugin (elastic#78428)
  Lazy load metric & mardown visualizations (elastic#78391)
  [Detections][EQL] EQL rule execution in detection engine (elastic#77419)
  Update tutorial-full-experience.asciidoc (elastic#75836)
  Update tutorial-define-index.asciidoc (elastic#75754)
  Add support for runtime field types to mappings editor. (elastic#77420)
  [Monitoring] Usage collection (elastic#75878)
  [Docs][Actions] Add docs for Jira and IBM Resilient (elastic#78316)
  [Security Solution][Resolver] Update @timestamp formatting (elastic#78166)
  [Security Solution] Fix app layout (elastic#76668)
  [Security Solution][Resolver] 2 new functions to DAL (elastic#78477)
  Adds new elasticsearch client to telemetry plugin (elastic#78046)
  skip flaky suite (elastic#78512) (elastic#78511) (elastic#78510) (elastic#78509) (elastic#78508) (elastic#78507) (elastic#78506) (elastic#78505) (elastic#78504) (elastic#78503) (elastic#78502) (elastic#78501) (elastic#78500)
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Feature:Ingest Node Pipelines Ingest node pipelines management release_note:skip Skip the PR/issue when compiling release notes Team:Kibana Management Dev Tools, Index Management, Upgrade Assistant, ILM, Ingest Node Pipelines, and more v7.10.0 v8.0.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Debug an ingest node pipeline using an indexed document
5 participants