-
Notifications
You must be signed in to change notification settings - Fork 290
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
Fixes #29307 - Add patternfly4 search to new CV page #8745
Conversation
Issues: #29307 |
@jeremylenz I'm opening this up as a draft, I put the remaining tasks in the PR message. If you have a chance to look, I would love to hear any feedback on the overall approach (especially before I write tests) I moved the I would like to get away from the move_to_* folders. Our intent can still be to move the components to patternfly or foreman, but we don't necessarily have to call our folders that. These "temporary" folders have been here for years and we should take steps to be realistic about what we can and can't move and not organize our folders based on these assumptions, which makes things harder to find. |
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.
Thanks @johnpmitsch! A few initial comments below but I didn't get to play around too much, because I'm getting a console error when I search for "label = xxx" and then execute the search:
webcomponents-bundle.js:92 Uncaught TypeError: Cannot convert undefined or null to object
at Function.getOwnPropertyNames (<anonymous>)
at Function.../vendor-core/node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js.Object.keys (webcomponents-bundle.js:92)
at tableDataGenerator.js:124
at Array.forEach (<anonymous>)
at tableDataGenerator (tableDataGenerator.js:120)
at ContentViewsTable.js:20
at commitHookEffectList (react-dom.development.js:19986)
at commitPassiveHookEffects (react-dom.development.js:20016)
at HTMLUnknownElement.callCallback (react-dom.development.js:347)
at Object.invokeGuardedCallbackDev (react-dom.development.js:397)
../vendor-core/node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js.Object.keys @ webcomponents-bundle.js:92
(anonymous) @ tableDataGenerator.js:123
tableDataGenerator @ tableDataGenerator.js:120
(anonymous) @ ContentViewsTable.js:19
commitHookEffectList @ react-dom.development.js:19986
commitPassiveHookEffects @ react-dom.development.js:20016
callCallback @ react-dom.development.js:347
invokeGuardedCallbackDev @ react-dom.development.js:397
invokeGuardedCallback @ react-dom.development.js:454
flushPassiveEffectsImpl @ react-dom.development.js:22868
unstable_runWithPriority @ scheduler.development.js:643
runWithPriority$2 @ react-dom.development.js:11305
flushPassiveEffects @ react-dom.development.js:22841
(anonymous) @ react-dom.development.js:22419
scheduler_flushTaskAtPriority_Normal @ scheduler.development.js:436
flushTask @ scheduler.development.js:482
flushWork @ scheduler.development.js:607
performWorkUntilDeadline @ scheduler.development.js:231
react_devtools_backend.js:6 The above error occurred in the <ContentViewTable> component:
in ContentViewTable (created by ContentViewsPage)
in ContentViewsPage (created by Context.Consumer)
in withRouter(ContentViewsPage) (created by Headers)
in Headers (created by Context.Consumer)
in Route (created by _default)
in div (created by _default)
in _default (created by Application)
in Router (created by BrowserRouter)
in BrowserRouter (created by Application)
in Application (created by ConnectFunction)
in ConnectFunction (created by I18nProviderWrapper(Connect(Application)))
in IntlProvider (created by I18nProviderWrapper(Connect(Application)))
in I18nProviderWrapper(Connect(Application)) (created by StoreProvider(I18nProviderWrapper(Connect(Application))))
in Provider (created by StoreProvider(I18nProviderWrapper(Connect(Application))))
in StoreProvider(I18nProviderWrapper(Connect(Application))) (created by DataProvider(StoreProvider(I18nProviderWrapper(Connect(Application)))))
in DataProvider(StoreProvider(I18nProviderWrapper(Connect(Application))))
Consider adding an error boundary to your tree to customize error handling behavior.
Visit https://fb.me/react-error-boundaries to learn more about error boundaries.
import { usePaginationOptions, useForemanSettings } from 'foremanReact/Root/Context/ForemanContext'; | ||
|
||
import EmptyStateMessage from './EmptyStateMessage'; | ||
import Loading from './Loading'; | ||
import MainTable from './MainTable'; |
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.
👍 for breaking this out into its own file, makes it feel a little cleaner.
@MariSvirik Regarding the seach icon - from what I can tell the way our search and RH cloud search function is different. They search automatically and the magnifying glass is not a button, the search happens as you type. For instance: With this search, I didn't click anything or hit enter to get this result, the search happens as you type. Whereas for Foreman/Katello search, you have to click enter or click the search icon. So it seems like keeping it as a button is better, but I am wondering what you think is best. Right now I plan to copy the example in https://patternfly-react.surge.sh/documentation/react/components/toolbar but let me know if I should do something different! |
489af1c
to
abacec2
Compare
@jeremylenz This is fixed now! |
f26b591
to
0b8c753
Compare
I added one to make sure autocomplete shows, hopefully we can add more, but it is a start! |
0627a55
to
5f3a09a
Compare
Fixed this now, thanks @jeremylenz! Btw https://projects.theforeman.org/issues/29907 should also be fixed in this 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.
Thanks for moving it along!
Works mostly as expected, with a couple issues remaining. And I'm not seeing any more page flashes, so I think we're good with 29907.
-
When I change the per-page setting, the table reloads but executes a blank search, instead of the current active search. I would expect it to either clear out the search box, or re-execute the existing search.
-
If I click the X button, it displays the loading spinner and re-does the "search" for all items. As a user, I would expect clicking the X to be instant and not require waiting. At the least, we should store the "all items" search in memory (memoize it) so it doesn't have to make an API call every time. As to how, whatever makes the most sense to you -- Redux, useMemo, etc. Can be a follow-up PR.
-
A search for "not composite" is suggested when I type "not", but results in an error. (Btw, the error empty state looks great 😄)
inputValue: this.props.initialInputValue, | ||
}; | ||
|
||
this.handleStateChange = this.handleStateChange.bind(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.
If you do
handleStateChange = ({inputValue}) => {
...
then you don't have to do the bind
in the constructor here :)
e, isOpen, activeItems, highlightedIndex, | ||
selectItem, userInputValue, onSearch, | ||
)} |
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.
Did eslint take a lunch break or something? 😆
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 looks fine on my local system.. weird
e, isOpen, activeItems, highlightedIndex, | ||
selectItem, userInputValue, onSearch, |
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.
please format
return ( | ||
<TextInput | ||
{...downshiftProps} | ||
ref={inputRef} |
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.
👍 for switching to the useRef and non-function form of the prop. I was also going to suggest dropping ref
in favor of the innerRef
prop provided by PF4, but both ref
and innerRef
seem to put the event listener on the <input>
element and both work fine. So I guess either is fine.
Thanks, and ya I saw that, it looks pre-existing and on the server side so I filed here https://projects.theforeman.org/issues/30079 It will definitely is more of a concern with autosearching on typing. Speaking with UX and others yesterday about it, it sounds like we would like to try out automatic searching on typing with an option to disable, and we can do more testing of this with a nightly box with a lot of content views to see how it performs. So I'll update the PR with this as well as the other updates from review! |
@jeremylenz was able to update this and also include autosearch on typing, I'll follow up with a comment on how that works. I would like to add some more tests to Search, but otherwise it is ready for re-review 👍
Fixed!
This isn't how the existing pages work (they also make an API call when you clear the search) and afaik we didn't plan to change this behavior in this feature. If you want to file it and propose it for the future it could be a good addition, but I don't consider within scope of the new CV page. |
@MariSvirik @Rohoover @jeremylenz There are two new settings to disable it and also to configure the delay before searching. I defaulted to 500ms - 1 second felt too unresponsive and anything under 500ms sent too many requests if you typed slow. The settings are If you disable the automatic search, it functions the same as our existing search, but with pf4 components: Let me know if you have any suggestions or questions! |
eba7ab1
to
a77da06
Compare
@MariSvirik @Rohoover I forgot to show this, here is the empty search results and error state pages, I mostly followed patternfly's design guidelines, but let me know if anything should be tweaked :)
|
@johnpmitsch @Rohoover No matching content views found (RHtext medium, 20) Unable to connect |
@MariSvirik updated the text! I have to ask about the fonts, I think they are set in Foreman and would need to be changed there. Here are the new pages: |
These are now added as well |
@johnpmitsch just a slight note about capitalization. Thanks for doing such a good job 🥇 |
thanks, I updated 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.
Tested and works great! Love the debounced type-ahead search, though I really do miss the X button in the input. I'm guessing that's already decided on?
Comments below
webpack/components/Search/Search.js
Outdated
// Prevent empty search when page first loads, but search when input is cleared after that | ||
this.setState({ autoSearchOnEmpty: true }); |
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 not just remove this.onInputUpdate()
from componentDidMount
? I'm guessing it's because you need to do part of this function on mount, but not all of it. If that's the case, could this function be split into parts to remove the need to track autoSearchOnEmpty
?
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.
Removing it seems to work fine, I'm not sure why it was there in the first place 🤔 I checked RH repos and subscriptions page too and they work fine. Please double check me though!
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 removed autoSearchOnEmpty
from the state and also removed the 2 places where it's read and written, and everything seems to work fine. I'd say it's safe to remove
import { connect } from 'react-redux'; | ||
import * as settingActions from 'foremanReact/components/Settings/SettingsActions'; | ||
import { selectSettings } from '../../scenes/Settings/SettingsSelectors'; | ||
import Search from './Search'; |
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.
Oh. This answers my question from above. Seems like <Search>
is mostly moved code rather than new code. In that case, take your pick what to address 😄
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.
ya its mostly moved out of the index.js
. I'll keep it as a class component but maybe there are a couple places i can clean up like removing .bind(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.
+1 to removing the .bind
s 😄
app/models/setting/content.rb
Outdated
self.set('autosearch_while_typing', N_('For pages that support it, automatically perform search while typing in search input.'), | ||
true, N_('Automatic Search while Typing')), | ||
self.set('autosearch_delay', N_('Delay in milliseconds before performing search for automatic searching.'), | ||
500, N_('Automatic Search Typing Delay')) |
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 shows up in Settings before the other one:
Automatic Search Typing Delay
-- | -- | --
Automatic Search while Typing
It appears to be alphabetical. Would make more sense if the main setting showed first, followed by the delay setting. Would naming them "Search as you Type" and "Search as you Type Delay" work?
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.
@MariSvirik any thoughts on the naming of these settings?
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.
decided on Autosearch and Autosearch delay (May not be one word)
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.
According to the content team, it should be one word (not even hyphened) in order to be consistent with the way IBM hyphens their words.
@MariSvirik any thoughts on this? Should we keep the |
Decision after meeting: add X button to the right edge of the searchbar to provide the easy way for the query deletion. |
I would like to get away from the move_to_* folders. Our intent can still be to move the components to patternfly or foreman, but we don't necessarily have to call our folders that. These "temporary" folders have been here for years and we should take steps to be realistic about what we can and can't move and not organize our folders based on these assumptions, which makes things harder to find.
@jeremylenz @MariSvirik Updated the setting names! (@jeremylenz use Also added an "X" when autosearch is enabled and there is input
|
[test katello] |
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.
looking good @johnpmitsch! Just a few comments below
webpack/components/Search/Search.js
Outdated
// Prevent empty search when page first loads, but search when input is cleared after that | ||
this.setState({ autoSearchOnEmpty: true }); |
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 removed autoSearchOnEmpty
from the state and also removed the 2 places where it's read and written, and everything seems to work fine. I'd say it's safe to remove
import { connect } from 'react-redux'; | ||
import * as settingActions from 'foremanReact/components/Settings/SettingsActions'; | ||
import { selectSettings } from '../../scenes/Settings/SettingsSelectors'; | ||
import Search from './Search'; |
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.
+1 to removing the .bind
s 😄
e, isOpen, activeItems, highlightedIndex, | ||
selectItem, userInputValue, onSearch, | ||
)} |
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 looks fine on my local system.. weird
@jeremylenz updated! |
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.
Changes look good, thanks @johnpmitsch !
self.set('autosearch_while_typing', N_('For pages that support it, automatically perform search while typing in search input.'), | ||
true, N_('Autosearch')), | ||
self.set('autosearch_delay', N_('If Autosearch is enabled, delay in milliseconds before executing searches while typing.'), | ||
500, N_('Autosearch delay')) |
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.
TBH i don't think these should be configurable settings. The delay should be set to a reasonable default and the auto search should only be enabled on pages where it can return result in a timely fashion without hammering the server with requests. (i.e. <100 ms to get results for a full db)
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.
@tbrisker I am planning on running some production tests to see how well the autosearch performs on a servers with a lot of Content Views. I think that will allow us to make better decisions here on whether A) Autosearch should be enabled by default and B) what the delay should be. It's possible that we don't enable autosearch by default if it is not performant.
I agree we could do without the delay setting, but it would be nice to see how things perform in production first. I'm hesitant to remove it now because of how experimental this feature is. Does that sound ok to you?
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.
My opinion is that since these settings only affect an experimental page while cluttering the settings page for all users, my preference would be to drop them completely and try to go with "[hopefully] sane default" first and only add a setting if needed in the future and we can't settle on a default that works for all users.
Adds new search at
/labs/content_views
To-do:
UPDATE: this is an existing issue in pf3 pages as well, I filed here https://projects.theforeman.org/issues/30071 and added to the feature tracker to look later.
For this addition, we need to support pf3 and pf4 search. I originally tried to see what would happen if I updated the search to pf4, but it looks really out of place in the context of a pf3 page.
I updated the
TypeAhead
component to support both pf3 and pf4 so it could share the autocomplete functionality coming from thedownshift
package. TheSearch
component now takes apatternfly4
prop and defaults to pf3 if not set.I have some duplicated file names where the folder determines if the component is pf3 and pf4. This made sense to me, but I am open to suggestions. React (for better or worse) doesn't have a lot of opinions about file naming or conventions, and I don't see any strong opinions out there against this pattern, so it is really whatever we are comfortable with.