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

[Lens] Add more in-editor Advanced documentation #86821

Merged
merged 45 commits into from
Jan 20, 2021

Conversation

dej611
Copy link
Contributor

@dej611 dej611 commented Dec 22, 2020

Summary

Fixes #81780

This PR is a first attempt to implement more advanced documentation in product using the popover component, as suggested in the ref issue.

In this PR the definition type interface has been also extended to support a getHelpMessage function which will render a help text when available. This has been useful in the case of the date histogram definition.

Implemented documentation:

  • How does interval granularity work?

    Screenshot 2020-12-23 at 19 15 55
    Previous version Screenshot 2020-12-22 at 16 56 32
  • How does auto date histogram work?

Screenshot 2020-12-23 at 19 18 28

Previous version Screenshot 2020-12-22 at 19 42 25
  • What is each fitting function doing?

Screenshot 2020-12-22 at 19 35 53

  • How does moving average work?

Screenshot 2020-12-23 at 19 17 30

Checklist

Delete any items that are not applicable to this PR.

Copy link
Contributor

@wylieconlon wylieconlon left a comment

Choose a reason for hiding this comment

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

Overall looking good, left some suggestions though!

max-height: 500px;
max-width: 400px;
overflow-y: scroll;
}

This comment was marked as resolved.

// Below 5 seconds the "humanize" call returns the "few seconds" sentence, which is not ok for ms
// This special config rewrite makes it sure to have precision also for sub-seconds durations
// ref: https://github.com/moment/moment/issues/348
function wrapMomentPrecision<T>(callback: () => T): T {
Copy link
Contributor

Choose a reason for hiding this comment

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

This logic sets the display to "1 seconds" which should be "1 second" (not plural). Is that a moment issue?

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, nice catch. I'll investigate

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Did an investigation on the topic.

TLDR; I would leave this glitch as for now, delaying the decision for when moment.js will be replaced in the codebase or if the localization of the humanize function would be eventually internally handled.

Longer explanation:

The issue is relative to moment.js as it is reproducible within the wrapMomentPrecision function with the following line:

console.log(moment.localeData().relativeTime(1, true, 'ss', false));

moment.js has an internal RelativeTimeSpec configuration that leads to this result, and while it is possible to fix it with a configuration customization, it is rather hard to safely restore the default.
The fix is an override of the configuration with a function that replaces the template string in use to specifically handle the 1 second case. the problem is that it should be done for all supported locales (~134 in moment itself + custom one, not sure how many in Kibana - I've found one custom so far).

The default configuration restoration is hard as there's no (clean) direct way to access the raw RelativeTimeSpec object in use, but only access it's output. The thing is not impossible, but moment.js typings does not like it: there's an internal prop to be accessed which is not typed and not meant to be accessed.

A potential solution would rely on module augmentation:

// Need to augment the moment module to access a hidden config parameter
declare module 'moment' {
  interface Locale {
    _config: LocaleSpecification;
  }
}


function wrapMomentPrecision<T>(callback: () => T): T {
  ...

  const defaultLocaleConfig = moment.localeData()._config;
  moment.updateLocale(moment.locale(), {
    relativeTime: {
      // what about other locales than "en" here?
      ss: (n: number): string => n === 1 ? 'a second' : `${n} second`
    },
  });

  // Execute the format/humanize call in the callback
  const result = callback();

  // restore all the default values now in moment to not break it
  moment.updateLocale(moment.locale(), defaultLocaleConfig);
}

It would be possible to propose upstream to give access to the LocaleSpecification data/configuration (the parent object of RelativeTimeSpec) but it is not guaranteed to be merged or accepted (moment.js is currently in maintenance mode).
Also it may requires to list and cover all potential locales in Kibana as well.

const result = callback();

// restore all the default values now in moment to not break it
units.forEach(({ unit }, i) => moment.relativeTimeThreshold(unit, defaultValues[i]));
Copy link
Contributor

Choose a reason for hiding this comment

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

If there's only one unit, why loop?

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 used to be multiple unit settings.
I've left the loop for now in case I need to tweak some other units: can refactor to single one if it's all good.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Found some rounding errors, so added few more units to the list.

ownFocus
isOpen={isPopoverOpen}
button={
<EuiLink onClick={() => setIsPopoverOpen(!isPopoverOpen)}>
Copy link
Contributor

Choose a reason for hiding this comment

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

It wasn't obvious that this was clickable to me. How about making it primary color or adding an icon?

advancedDescription: (
<p>
{i18n.translate('xpack.lens.indexPattern.dateHistogram.autoAdvancedExplanation', {
defaultMessage: 'The specific interval adopted follow the logic in this table:',
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
defaultMessage: 'The specific interval adopted follow the logic in this table:',
defaultMessage: 'The specific interval follows this logic:',

{
field: 'bound',
name: i18n.translate('xpack.lens.indexPattern.dateHistogram.autoBoundHeader', {
defaultMessage: 'Target Interval measured',
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
defaultMessage: 'Target Interval measured',
defaultMessage: 'Target interval measured',

/>
}
closePopover={() => setIsPopoverOpen(false)}
anchorPosition="leftCenter"
Copy link
Contributor

Choose a reason for hiding this comment

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

The current position of the popover overlaps the label for the form. Would it be possible to change the anchorPosition, and also to make the popover button trigger from EuiFormRow instead of the ButtonIcon?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Did a quick change to the EuiFormRow positioning:

Screenshot 2020-12-23 at 18 07 48

It looks a bit confusing to me given the Create custom ranges link just below.

Probably putting it on the right hand side may looks better: my only concern is that if you pass to custom intervals and then get back the cursor will hover it (not a major concern):

Screenshot 2020-12-23 at 18 12 31

In this last case it makes sense to move the anchorPosition to upRight.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Pushed the second version in the PR.

@dej611
Copy link
Contributor Author

dej611 commented Dec 28, 2020

@elasticmachine merge upstream

@dej611 dej611 marked this pull request as ready for review December 28, 2020 13:42
@dej611 dej611 requested a review from a team December 28, 2020 13:42
@dej611 dej611 requested review from a team as code owners December 28, 2020 13:42
@dej611 dej611 added release_note:enhancement Team:Visualizations Visualization editors, elastic-charts and infrastructure labels Dec 28, 2020
@elasticmachine
Copy link
Contributor

Pinging @elastic/kibana-app (Team:KibanaApp)

@dej611
Copy link
Contributor Author

dej611 commented Dec 28, 2020

While testing the moment i18n I noticed the humanize formatter currently does not translate duration strings:

Screenshot 2020-12-28 at 13 11 58

The picture above should be zh-CN, but I noticed the same behaviour with ja-JP. Maybe there's an additional configuration other than the i18n.locale parameter in Kibana for moment?
(Forget the a second in the screenshot, it was hardcoded. All the other strings come from moment.js).
I could not find anything about it.

@dej611
Copy link
Contributor Author

dej611 commented Jan 11, 2021

@elasticmachine merge upstream

Copy link
Contributor

@gchaps gchaps left a comment

Choose a reason for hiding this comment

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

Exciting to see this. Overall looks very nice. Is there any concern that we'll have three different links to get the user help: tooltip icon, lifesaver icon, and "How it works" link?

button={
<HelpPopoverButton onClick={() => setIsPopoverOpen(!isPopoverOpen)}>
{i18n.translate('xpack.lens.indexPattern.movingAverage.helpText', {
defaultMessage: 'How does it work?',
Copy link
Contributor

Choose a reason for hiding this comment

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

I suggest that we use this format for the text throughout:

How it works
How moving average works

defaultMessage='The size of the interval is chosen to be a "nice" value. It is possible for the chosen
interval to stay the same when changing the granularity slider if the "nice" interval is
the same. The minimum granularity is 1, and the maximum is
{setting}. To change the maximum granularity setting, go to Advanced settings.'
Copy link
Contributor

Choose a reason for hiding this comment

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

@MichaelMarcialis Can popovers have links? If so, it might be nice to link to Advanced Settings. Or, are they similar to tooltips, which don't allow links.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, popovers can include links.

@MichaelMarcialis
Copy link
Contributor

Exciting to see this. Overall looks very nice. Is there any concern that we'll have three different links to get the user help: tooltip icon, lifesaver icon, and "How it works" link?

Good question. In this case, I believe the pattern is that the questionInCircle icon is used to indicate to users that a hover action will trigger a tooltip with a short descriptive message. Alternatively, the help icon (with or without subsequent text`) is used to indicate that a click will trigger a popover with more robust help information. Since the required action and contents differs between the two, I think it's OK to support the two different appearances.

Copy link
Contributor

@wylieconlon wylieconlon left a comment

Choose a reason for hiding this comment

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

Few more changes!

/>
</p>

<p>
<FormattedMessage
id="xpack.lens.indexPattern.movingAverage.longerExplanation"
defaultMessage="The Lens Moving Average uses a simple arithmetic mean of the window and applies a skip policy for gaps:
this means that for missing values the bucket is skipped and the calculation is performed on the next one."
defaultMessage="To calculate the moving average, **Lens** uses the mean of the window and applies a skip policy for gaps.
Copy link
Contributor

Choose a reason for hiding this comment

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

Markdown isn't supported here, so the bold doesn't show. There's a few places we need to update this.

/>
</p>

<ul>
Copy link
Contributor

Choose a reason for hiding this comment

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

Also there is no moving average for the first position- we should probably show the missing values too.

Comment on lines 339 to 340
defaultMessage: `When there are missing values in an area or line chart these can be represented in different ways in **Lens**. Missing values are drawn using dotted
lines, and will not fill missing values at the left side of the chart.`,
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this can be condensed more because the first sentence is pretty vague. How about "Gaps in the data are not shown by default, but can be represented as dotted lines with different modes."

@dej611
Copy link
Contributor Author

dej611 commented Jan 14, 2021

@elasticmachine merge upstream

@dej611
Copy link
Contributor Author

dej611 commented Jan 14, 2021

@gchaps Changed the title pattern to be more subject specific. I'd say the length of the link is now pretty long, but I don't have a strong opinion here.

Screenshot 2021-01-14 at 14 40 05

Screenshot 2021-01-14 at 14 40 12

Screenshot 2021-01-14 at 14 40 20

@wylieconlon removed the markdown bold from text.
@flash1293 @wylieconlon tried to integrate the partial window concept into a new section in the popover, and mention the moving average starting from the second value of the series.

@gchaps
Copy link
Contributor

gchaps commented Jan 14, 2021

@dej611 I agree with you that the link text is too long. What I mean to say was:

  • Use "How it works" for the link text.
  • Use the longer form in the title of the popup. For example, "How moving average works"

@dej611
Copy link
Contributor Author

dej611 commented Jan 18, 2021

@elasticmachine merge upstream

@dej611
Copy link
Contributor Author

dej611 commented Jan 19, 2021

@wylieconlon I think I did address your concern. In case we could resolve the remaining issue offline and move this PR forward.

Copy link
Contributor

@wylieconlon wylieconlon left a comment

Choose a reason for hiding this comment

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

@dej611 This looks mergeable! Thanks for all the updates.

@kibanamachine
Copy link
Contributor

💚 Build Succeeded

Metrics [docs]

Module Count

Fewer modules leads to a faster build time

id before after diff
lens 466 476 +10

Async chunks

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

id before after diff
lens 1.1MB 1.1MB +19.1KB

Page load bundle

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

id before after diff
data 1003.8KB 1010.1KB +6.3KB

History

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

@dej611 dej611 merged commit 86789da into elastic:master Jan 20, 2021
@dej611 dej611 deleted the doc/lens/popups branch January 20, 2021 16:49
dej611 added a commit to dej611/kibana that referenced this pull request Jan 20, 2021
Co-authored-by: Kibana Machine <[email protected]>
Co-authored-by: Wylie Conlon <[email protected]>
Co-authored-by: Michael Marcialis <[email protected]>
dej611 added a commit that referenced this pull request Jan 20, 2021
Co-authored-by: Kibana Machine <[email protected]>
Co-authored-by: Wylie Conlon <[email protected]>
Co-authored-by: Michael Marcialis <[email protected]>

Co-authored-by: Kibana Machine <[email protected]>
Co-authored-by: Wylie Conlon <[email protected]>
Co-authored-by: Michael Marcialis <[email protected]>
@jloleysens
Copy link
Contributor

@dej611 This component looks really useful! We are working on updating ILM and are finding it difficult to explain "rollover" in a concise way. Some kind of in-product documentation would be really useful there.

Is the idea that plugins develop their own solutions for now or is there a plan to have a shared component in Kibana?

@dej611
Copy link
Contributor Author

dej611 commented Feb 2, 2021

I am no aware of any particular Kibana-wide approach to in-product documentation like this.
The components and design proposed before their actual implementation can be found here: the tooltip + popover approach was chosen by its minimal impact on the editor UI (compared to other solutions).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Feature:Lens release_note:enhancement Team:Visualizations Visualization editors, elastic-charts and infrastructure v7.12.0 v8.0.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Advanced Lens documentation
10 participants