-
Notifications
You must be signed in to change notification settings - Fork 8.2k
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] 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) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Small nits, but nothing critical -- app services code LGTM. 👍
@@ -44,9 +44,13 @@ export function buildResultColumns( | |||
input: Datatable, | |||
outputColumnId: string, | |||
inputColumnId: string, | |||
outputColumnName: string | undefined | |||
outputColumnName: string | undefined, | |||
options: { allowColumnOverride: boolean } = { allowColumnOverride: false } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
naming nit: I think allowColumnOverwrite
would be a bit more intuitive than "Override", but I don't feel strongly about this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we use the default EuiLink styling instead of removing the affordances of the color and underline?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Took that from the mocks as well, but I see your point and I think per second is a better default
|
||
export interface BaseIndexPatternColumn extends Operation { | ||
// Private | ||
operationType: string; | ||
customLabel?: boolean; | ||
timeScale?: TimeScaleUnit; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@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.
@@ -99,6 +99,8 @@ export interface ParamEditorProps<C> { | |||
data: DataPublicPluginStart; | |||
} | |||
|
|||
export type TimeScalingMode = 'disabled' | 'mandatory' | 'optional'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tested on Safari, code looks good to me 🆗
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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_scale
expression 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
expression
plugin are minimal - it's just adding an option to allow overwriting an existing column with the output value for thebuildResultColumn
helper.