Skip to content

timeseries: replace matInput with reusable FilterInputComponent #4938

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

Merged
merged 2 commits into from
May 17, 2021

Conversation

psybuzz
Copy link
Contributor

@psybuzz psybuzz commented May 5, 2021

The Time Series tag filter input and run selector were using Angular's
matInput whose styles are only included when another mat-form-field
has been rendered on the page before [1].

To make the filter input styles deterministic, drop the matInput directive
and replace it with a custom, styled widget for filter inputs.

[1] angular/components#21871

@google-cla google-cla bot added the cla: yes label May 5, 2021
Comment on lines 56 to 63
.tb-text-input {
-webkit-appearance: none;
box-sizing: content-box;
font: inherit;
border: none;
outline: none;
padding: 0;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Instead of creating a CSS based components, just create an Angular widget.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Creating a widget wrapper around <input> seems to add unnecessary boilerplate, imo. Every attribute like autocomplete or event binding like (input) now requires extra @input's and @output's on this new widget. Also, every module that uses it must now import another NgModule.

What do we gain from a TBTextInputWidget, from this extra boilerplate?

Copy link
Contributor

Choose a reason for hiding this comment

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

If it has very consistent UX that we can supply with it, I think it is very well worth it. Kind of like mat-input; for me, I gain almost nothing by using it yet for the consistent UX, we use it.

CSS based widgetization is creating a new pattern unnecessarily.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Switched to the custom widget approach, PTAL

@psybuzz psybuzz marked this pull request as ready for review May 14, 2021 03:18
@psybuzz psybuzz changed the title timeseries: replace matInput with custom styles timeseries: replace matInput with reusable FilterInputComponent May 14, 2021
Copy link
Contributor

@stephanwlee stephanwlee left a comment

Choose a reason for hiding this comment

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

Thanks for your willingness to compromise.

It mostly LGTM and the comments are for clarifications and they are not blockers.
One thing though: I do notice that the tests are missing. I understand that the component is quite trivial (mostly a visual component). Was the omission an oversight or an intentional one?

@@ -126,9 +126,16 @@ export function sendKey<T>(
el.setSelectionRange(startingCursorIndex, startingCursorIndex);
}

// Use to override default options on programmatic events to be closer to
// user-initiated events, which bubble and cancel.
const baseEventOptions = {
Copy link
Contributor

Choose a reason for hiding this comment

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

Cool. Would you be able to spend a little bit of time to maybe find the TypeScript HTML typing for the event options? Since it is already checked when you pass it as the second argument to Event constructor, I guess it is okay as is, too.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done. And good idea, cause I actually misspelled "cancelable" :)

styles: [
`
:host {
display: flex;
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, is there a reason why this element has to be a non-inline element?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Consumers of <tb-filter-input> can still style it as display: inline-flex from the outside. The 'flex' part is here to make the <input> full height.

@ViewChild(MatAutocompleteTrigger)
autocompleteTrigger!: MatAutocompleteTrigger;

getAutocompleteTrigger(): MatAutocompleteTrigger {
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider just exposing closeAutocomplete unless the trigger has other APIs that must be used.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

After some consideration, I think "hide on Enter" really applies to all filter inputs, and have moved it into the widget. This lets us avoid exposing matAutocompleteTrigger entirely, since consumers should probably never have to worry about opening and closing the panel manually.

In the future, I think it probably makes sense to move the "invalid error icon" into a filter input widget as well. I've held off on that in this PR though.

@Component({
selector: 'tb-filter-input',
template: `
<input
Copy link
Contributor

@stephanwlee stephanwlee May 14, 2021

Choose a reason for hiding this comment

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

I noticed that the two applications both have the <mat-icon svgIcon="search_24px">. Would it maybe make sense to include the icon since it is literally for filters?

It would be close (in its contract) to this (on older safari): https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/search
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.

Done.

Copy link
Contributor Author

@psybuzz psybuzz left a comment

Choose a reason for hiding this comment

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

Thanks for the review!

I understand that the component is quite trivial (mostly a visual component). Was the omission an oversight or an intentional one?

In the previous commit, I was thinking it wasn't too valuable to test that this component properly passes props to 1 template element. However, writing the test ended up catching missed things, and I think checking that autocomplete overlays fire made it worth adding a test.

@@ -126,9 +126,16 @@ export function sendKey<T>(
el.setSelectionRange(startingCursorIndex, startingCursorIndex);
}

// Use to override default options on programmatic events to be closer to
// user-initiated events, which bubble and cancel.
const baseEventOptions = {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done. And good idea, cause I actually misspelled "cancelable" :)

styles: [
`
:host {
display: flex;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Consumers of <tb-filter-input> can still style it as display: inline-flex from the outside. The 'flex' part is here to make the <input> full height.

@ViewChild(MatAutocompleteTrigger)
autocompleteTrigger!: MatAutocompleteTrigger;

getAutocompleteTrigger(): MatAutocompleteTrigger {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

After some consideration, I think "hide on Enter" really applies to all filter inputs, and have moved it into the widget. This lets us avoid exposing matAutocompleteTrigger entirely, since consumers should probably never have to worry about opening and closing the panel manually.

In the future, I think it probably makes sense to move the "invalid error icon" into a filter input widget as well. I've held off on that in this PR though.

@Component({
selector: 'tb-filter-input',
template: `
<input
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

// Convert typing to object. Sadly, because keyCode is deprecated, it is not
// typed properly.
const keyboardEventArg = {key, keyCode} as {};
const keyboardEventArg = {...baseEventOptions, key, keyCode} as {};
Copy link
Contributor

Choose a reason for hiding this comment

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

FYI, as {} might have made you miss that typo.

@psybuzz psybuzz merged commit df038ab into tensorflow:master May 17, 2021
psybuzz added a commit that referenced this pull request May 17, 2021
The sync broke in #4938
because of property renaming-related errors. This change also fixes a
minor lint warning.

Test sync cl/374274713
psybuzz added a commit that referenced this pull request May 27, 2021
Recently [1], we introduced a `<tb-input-filter>` component that replaced
the runs selector's filter input field in Time Series. That change included a
regression where the input's click target was no longer full width.

This change restores the full width click target.

Manually ran `bazel tensorboard:dev` and checked that clicking in the
space to the right of the placeholder text still focuses the run selector's
input field in the Time Series dashboard.

[1] #4938
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants