[Lens] Normalize values by time unit#83904
Conversation
|
@elasticmachine merge upstream |
|
merge conflict between base and head |
|
@elasticmachine merge upstream |
|
Pinging @elastic/kibana-app (Team:KibanaApp) |
lukeelmers
left a comment
There was a problem hiding this comment.
Small nits, but nothing critical -- app services code LGTM. 👍
| inputColumnId: string, | ||
| outputColumnName: string | undefined | ||
| outputColumnName: string | undefined, | ||
| options: { allowColumnOverride: boolean } = { allowColumnOverride: false } |
There was a problem hiding this comment.
nit: Could we add the new option to the jsdoc so there's a brief explanation in the comments?
| ) { | ||
| if (input.columns.some((column) => column.id === outputColumnId)) { | ||
| if ( | ||
| !options.allowColumnOverride && |
There was a problem hiding this comment.
naming nit: I think allowColumnOverwrite would be a bit more intuitive than "Override", but I don't feel strongly about this.
wylieconlon
left a comment
There was a problem hiding this comment.
This is overall working very well! Left a lot of small code and naming comments, but I think it's enough to require a second round. There's also these questions that I don't think are required, but that might affect the layout of the code:
What happens if in the future we want to support the suffix formatter as an extra formatter, without time scaling? For example, metrics are commonly stored as "per second" values.
What happens if in the future we want to support time scaling without a suffix?
What happens if in the future we want to support time scaling without the date histogram?
| <EuiText size="s"> | ||
| <EuiLink | ||
| data-test-subj="indexPattern-time-scaling-enable" | ||
| color="text" |
There was a problem hiding this comment.
Can we use the default EuiLink styling instead of removing the affordances of the color and underline?
There was a problem hiding this comment.
I won't block this any more, but I do think this is a confusing design because it lacks the affordances of the EUI examples. The main reason I think this is problematic is that it's using a menu-oriented design, but only has one item.
x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/time_scaling.tsx
Show resolved
Hide resolved
| fullWidth | ||
| label={i18n.translate('xpack.lens.indexPattern.timeScale.label', { | ||
| defaultMessage: 'Normalize by unit', | ||
| })} |
There was a problem hiding this comment.
I'd like to add a tooltip to this form to explain the most common questions, especially the "why":
Normalized values are displayed as a rate, calculated from the date histogram interval. Values can scale down from a larger interval or to scale up a smaller interval. Partial intervals are allowed.
| ...state.layers[layerId].columns, | ||
| [columnId]: { | ||
| ...selectedColumn, | ||
| timeScale: e.target.value as TimeScaleUnit, |
There was a problem hiding this comment.
I would prefer that we update the default label every time the time scale is changed. I found it pretty confusing when the axis labels were showing "timestamp per 30 minutes" but my data is "Count of records" instead of "Count of records per second"
There was a problem hiding this comment.
Good Idea, I will integrate this.
x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/time_scaling.tsx
Outdated
Show resolved
Hide resolved
x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_editor.tsx
Outdated
Show resolved
Hide resolved
| import { TimeScaleUnit } from '../time_scale'; | ||
| import { IndexPatternPrivateState } from '../types'; | ||
|
|
||
| const DEFAULT_TIME_SCALE = 'm' as const; |
There was a problem hiding this comment.
Why is this the default, and not per-second? I ask because we can pretty much guarantee that per-second is smaller than the interval they have, so it's unlikely to scale up. I think that's a benefit.
There was a problem hiding this comment.
Took that from the mocks as well, but I see your point and I think per second is a better default
| // Private | ||
| operationType: string; | ||
| customLabel?: boolean; | ||
| timeScale?: TimeScaleUnit; |
There was a problem hiding this comment.
Why did you add this to the top-level IndexPatternColumn type instead of to params? We have more uses of column.params, including when building the expression output.
There was a problem hiding this comment.
I thought it would be a better place to clarify it's not managed by the individual operations, but it makes more sense to put it there anyway. I will adjust the PR.
There was a problem hiding this comment.
@wylieconlon Looking into this I would like to keep it as it is as the types for params are pretty complex right now and I would have to overwrite them in weird ways in a bunch of places to make it work. We should clean that up but I don't think we have to do it on this PR. Ideally I would like to keep the frame managed pieces to the top level, with params being reserved for the individual operations. This makes the types much simpler.
| data: DataPublicPluginStart; | ||
| } | ||
|
|
||
| export type TimeScalingMode = 'disabled' | 'mandatory' | 'optional'; |
There was a problem hiding this comment.
It looks like mandatory time scaling isn't handled in this PR: nothing is different in the UI if it's mandatory vs optional. Intentional?
There was a problem hiding this comment.
The "remove" button is not shown if it's set to mandatory (implicitly checking the absence of mandatory by checking for optional in a branch of the code that ruled out undefined and disabled already)
| ...state.layers[layerId].columns, | ||
| [columnId]: { | ||
| ...selectedColumn, | ||
| timeScale: undefined, |
There was a problem hiding this comment.
If timeScale were part of params, you'd be allowed to use the updateColumnParam helper from layer_helpers. Would be simpler than writing all this!
Unfortunately this idea conflicts with my idea of using a new updateLayer function instead of setState- we can only pick one of these for simplification.
There was a problem hiding this comment.
I think updateLayer makes sense here because we anyway have to adjust the label as well based on your other comment
|
Thanks for your comments @wylieconlon , I'm currently working through them. I noticed the transition logic doesn't work at the moment, I'm adjusting this (lot's of edge cases in there!). About your questions:
It would be a separate thing to let the user configure next to the regular format - we already have the "parentFormat" field in there, it would be about making this configurable by the user. The time scaling code would have to check for that to make sure it doesn't get applied twice.
Same as above - "parentFormat" would be explicitly set, and the time scaling expression logic checks for that and adjusts
I think the logic for that can be encapsulated in the |
|
@wylieconlon OK, should be ready to review again. I implemented most of your comments and left replies in cases I didn't. Also I made sure the time scale property is transitioned correctly in the places necessary right now - once we introduce transitions for calculations we have to make sure it works correctly there as well. |
mbondyra
left a comment
There was a problem hiding this comment.
Tested on Safari, code looks good to me 🆗
wylieconlon
left a comment
There was a problem hiding this comment.
I think there are two comments that should be addressed before merging, but I'm approving because I don't think I need to give it another pass.
Tested in FF and the functionality is looking good!
x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/time_scaling.tsx
Outdated
Show resolved
Hide resolved
| <EuiText size="s"> | ||
| <EuiLink | ||
| data-test-subj="indexPattern-time-scaling-enable" | ||
| color="text" |
There was a problem hiding this comment.
I won't block this any more, but I do think this is a confusing design because it lacks the affordances of the EUI examples. The main reason I think this is problematic is that it's using a menu-oriented design, but only has one item.
| if (previousTimeScale) { | ||
| const suffixPosition = oldLabel.lastIndexOf(` ${unitSuffixesLong[previousTimeScale]}`); | ||
| if (suffixPosition !== -1) { | ||
| cleanedLabel = oldLabel.substring(0, suffixPosition); |
There was a problem hiding this comment.
I think you should change this implementation before merging, because I think that the reference editor work will cause the time scaling suffixes to get removed accidentally. The reference logic is calling getDefaultLabel when modifying columns, so I think the suffix adding needs to move into the operation definitions. A nice benefit of this is that you won't need to do any string manipulation here.
There was a problem hiding this comment.
Can you clarify a little how you expect it to work? The label change would happen in the getDefaultLabel or buildColumn function of the operations supporting time scaling?
|
Thanks for the review @wylieconlon , I moved the logic of adjusting the label and carrying over the time scale param into the individual operations. While doing that I made sure the calculations are covered as well. I also fixed an additional case I stumbled over - if the date histogram gets removed, the label has to be adjusted as well. Luckily we already had the In a very recent bug fix of mine (#84121) I wrote the following:
Well, this time is now, because if the user interacts with the time scaling UI, the label gets updated from the outside, but it would not be shown because the internal state is cached already. I think I found a better solution, implemented on this PR - in the debounced input, I'm keeping track of whether a debounced change caused by the user typing is pending right now to be pushed up the the root state. If that's the case, incoming value updates are discarded (to not get into the way of the typing user). If there are no in-flight changes caused by typing, the value from the root state is copied into the local state. This should fix both cases - keeping the input snappy and making sure the state is always consistent. @mbondyra could you take a look at that part? |
|
I also changed the wording a little because "Normalize by time unit" is a little too long for the tooltip icon to not wrap into a new line: I think we can improve wording, but I would like to keep iterating on this off this PR and do a whole pass over the UI by the end of the current development cycle. |
|
Reapproved, I'm not totally convinced to 'normalize by unit' copy, but we can iterate on that. Works fine and code looks good. |
…bana into add-metadata-to-node-details * 'add-metadata-to-node-details' of github.com:phillipb/kibana: [APM] ML anomaly detection integration: Displaying anomaly job results in the Transaction duration chart is not as intended (elastic#84415) Support for painless language autocomplete within monaco (elastic#80577) [Lens] Time scale ui (elastic#83904) removing beta callouts (elastic#84510) [Lens] (Accessibility) add aria-label to chart type icon (elastic#84493) Trusted Apps signer API. (elastic#83661) increase stdout max listeners for legacy logging (elastic#84497) [APM] Service overview: Add throughput chart (elastic#84439) [Discover] Unskip main functional tests (elastic#84300) Uptime overview overhaul (elastic#83406) [APM] Adjust time formats based on the difference between start and end (elastic#84470) [ML] Renaming saved object repair to sync (elastic#84311) [UsageCollection] Remove `formatBulkUpload` and other unused APIs (elastic#84313) [Visualizations] Adds visConfig.title and uiState to build pipeline function (elastic#84456) [Elasticsearch Migration] Update docs re UsageCollection (elastic#84322) TSVB field list performance issue on using annotations (elastic#84407) [Security Solution] Exceptions Cypress tests (elastic#81759) [ML] Fix spaces job ID check (elastic#84404) [Security Solution][Detections] Handle dupes when processing threshold rules (elastic#83062)
* master: (25 commits) [Alerting] fixes buggy default message behaviour (elastic#84202) [Graph] Use new ES client and change license API (elastic#84398) [DOCS] Adds redirect to known plugins page (elastic#84001) Update IndexPatternSelect to get fields from indexPatternService instead of savedObject attributes (elastic#84376) Adding timestamps to created events so the sorting is stable (elastic#84515) [DOCS] Redirects for drilldown links (elastic#83846) [Fleet] Support for showing an Integration Detail Custom (UI Extension) tab (elastic#83805) [Enterprise Search] Migrate shared Schema components (elastic#84381) [Discover] Unskip date_nanos and shard links functional tests (elastic#82878) [APM] ML anomaly detection integration: Displaying anomaly job results in the Transaction duration chart is not as intended (elastic#84415) Support for painless language autocomplete within monaco (elastic#80577) [Lens] Time scale ui (elastic#83904) removing beta callouts (elastic#84510) [Lens] (Accessibility) add aria-label to chart type icon (elastic#84493) Trusted Apps signer API. (elastic#83661) increase stdout max listeners for legacy logging (elastic#84497) [APM] Service overview: Add throughput chart (elastic#84439) [Discover] Unskip main functional tests (elastic#84300) Uptime overview overhaul (elastic#83406) [APM] Adjust time formats based on the difference between start and end (elastic#84470) ...
|
@flash1293 Do you think the title of this PR should be updated so that it fits in the release notes? |
💚 Build SucceededMetrics [docs]Module Count
Async chunks
Page load bundle
History
To update your PR or re-run it, just comment with: |




Fixes #77811
This PR puts the
lens_time_scaleexpression function and the suffix formatter to use and allows to specify the time unit to scale a value by (if there's a date histogram available)app-services changes
The changes in the
expressionplugin are minimal - it's just adding an option to allow overwriting an existing column with the output value for thebuildResultColumnhelper.