-
Notifications
You must be signed in to change notification settings - Fork 843
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
Responsive tables #584
Responsive tables #584
Conversation
This is great. The layout you have in place I think works well. Some random thoughts on the design bits.
|
Awesome, thank you for the feedback. In regards to your points:
|
cf3ceb5
to
5d0bdd0
Compare
Ooh. I like your halfsy toast idea for popovers. |
I opened a PR to adjust some of the JS, details: cchaos#2 Noticed a couple of things while I was working on that: The focus state of the mobile sorting popover could use some padding. Maybe remove Offline/Online status field in |
b4264aa
to
a68d0e9
Compare
Aaaand done! Ready for reviews... |
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 a biggun and a very hard problem to solve! Nice work.
I'll do a visual review first, since the code will take a bit.
Currently you're lowering the opacity of action buttons when they are disabled (after a selection of a different row). I think you might want to remove them (or set opacity: 0) instead. On a phone it's not going to be as apparent you can't click them because you won't have the lack of hover state context. You'll just see a gear and wonder why it can't be clicked. Though I could be overthinking it.
Should Basic and In-Memory table carry the same styling for checkbox selection? Right now one of them puts the checkboxes on the right, the other on the left. Think it looks good always on the right with the line that you have added.
For the expanding rows bit I'm wondering if the expanded row should replace the original row completely. Right now they are a little disjointed and look separate. If we keep the original around (and I haven't looked at the code, it likely requires it that way now), then we should figure out some way to visually tie the two rows together as a unit by adding some sort of wrapping border or shelving. Just something to say... hey, these two are together.
On your mobile version of the same component it works better because of the wrapper. Whatever you do with desktop, you can likely loose the gray shading for the expanded bit here.
Some weird spacing happening in the messaging for loading table items.
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 really impressive! The code looks great overall. I had a few comments. I also have some feedback on the design, take it for what you will.
Sorting
Is it broken? I can't figure out how to get it to work on the docs site:
Pagination
When I click the arrows, I'm using to seeing the pagination itself reflect the state change somehow. Maybe if it said "1/7" (current page / total pages) that would help, because then the number would change as I change the page.
Selection
This is a great solution, I just have a hard time with the placement of the checkbox because it's so disassociated with the content of the row itself. Now I have to scan the checkboxes on the right (I'm used to scanning content on the left), and then I need to zig my eyes left to scan and see which one is selected. I know we have the background color as a selection signifier, but the checkbox is a strong visual anchor and really aids scanning. If we put it on the left, we could put the actions on the top right. If the row is expandable, the expansion arrow could go below the checkbox, or even at the bottom left?
@@ -25,6 +25,8 @@ export const section = { | |||
<p> | |||
You can expand rows by passing in a <EuiCode>itemIdToExpandedRowMap</EuiCode> prop | |||
which will contain the content you want rendered inside the expanded row. | |||
You will also need to add the prop <EuiCode>isExpandedRow</EuiCode> to the row that |
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.
Maybe add a note that this only applies if you're building out a custom table, but not if you're using basic table or in-memory table?
@@ -167,6 +169,11 @@ export class EuiBasicTable extends Component { | |||
return criteria; | |||
} | |||
|
|||
scrollToTop = () => { | |||
const topOfTable = this.tableElement.offsetTop; | |||
window.scrollTo(0, topOfTable); |
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.
To be really future-proof, can we do window.scrollTo(window.scrollX, topOfTable)
since we don't want to affect the horizontal scroll at all?
After playing with this a little, I think we should remove this functionality. I totally understand the intention, especially on mobile... but the experience on the docs site is a little jarring when on a desktop, especially if I want to keep paging. Have you already experimented with tables in either Kibana or Cloud to identify pain points in our actual use cases? If not then it might make sense to remove it for now... it will be easy to add it back in if/when we discover that we really need it.
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.
That's fine. It's not a smooth scroll like I would like it to be anyway. But we should definitely keep it in mind once we see more users using mobile.
@@ -219,6 +220,22 @@ export class EuiContextMenuPanel extends Component { | |||
} | |||
} | |||
|
|||
getWatchedProps(items) { |
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.
Could you add some comments explaining what this is for?
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.
@jen-huang Should be able to help with that.
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.
@cjcenizal Added some inline comments to getWatchedProps()
and shouldComponentUpdate()
.
Previously, EuiContextMenuPanel
doesn't re-render if its items
changes, due to custom logic in shouldComponentUpdate()
. For mobile tables, there is a dropdown of sortable fields, using this component, that displays field name (unchanging) and sort direction (changing!). After changing sorting, the UI wouldn't update until dropdown is closed and re-opened.
To fix this I added the prop watchedItemProps
, which specifies what properties of items
the component should check for changes as part of shouldComponentUpdate()
. In this case we are watching isSorted
and isSortAscending
.
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 Jen! That makes a lot of sense. Very nice solution.
Could I make a small suggestion? I think changing the name slightly, adding a quick comment re intent, and and doing the stringification internally would make this a bit easier to grok. What do you think?
getWatchedPropsForItems(items) {
// This lets us compare prevProps and nextProps among items so we can re-render if our items
const { watchedItemProps } = this.props;
// Create fingerprint of each item's watched properties
if(items && items.length && watchedItemProps && watchedItemProps.length) {
return JSON.stringify(items.map(item => {
// Create object of item properties and values
const props = {
key: item.key,
};
watchedItemProps.forEach(prop => props[prop] = item.props[prop]);
return props;
}));
}
return null;
}
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.
@cjcenizal 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.
Nice, thanks!
display: none; // Use mobile versions of selecting and filtering instead | ||
} | ||
|
||
// Not allowing compressed styles in mobile view (for now) |
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.
How about deleting the commented-out styles, and moving this comment up to the .euiTable--responsive
class?
}); | ||
|
||
const columnTitle = ariaLabel ? ariaLabel : children; | ||
const statefulAriaLabel = `Sort ${columnTitle} ${isSortAscending ? 'descending' : 'ascending'}`; |
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.
Looks like these variables are over-indented a bit.
@snide and @cjcenizal thank you for the feedback here are a few responses:
This seems like it was actually a carry-over from the non-mobile version, but I can certainly just hide them completely.
Yes, I just forgot to add the
Yeah, they're 2 separate
Yeah that weird spacing has to do with the
Yes/No, when I added the responsive stuff as optional I forgot to also set the EuiBasicTable responsive prop to default to true.
I agree and I already made a separate ticket: #606
Yeah I've been bouncing back and forth and sideways about where to place these and looking one with all 3 options, I'm thinking that the checkbox should go on the left, actions in the top right, and expander in the bottom right. I'll make that change. |
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.
Code here looks pretty readable. Left some small notes, but it's up to you whether you wanna make the changes.
I would recommend rewriting your example docs intro. The information is good, but I'd format it a little different to say the equiv of...
To make your table work responsively, please make sure you utilize the following additional props:
Right now it's a little unclear that these are additive things you need to add to your table to make them work (at their best) in mobile. Basically that's you're designing a better view.
Looks like this branch may have inadvertently broke the props documentation. I'd love to see how that stuff before this gets in just to see if all the new prop API is clear when browsing it from that view.
animation: $euiAnimSpeedNormal $euiAnimSlightResistance 1 normal forwards growExpandedRow; | ||
} | ||
|
||
@keyframes growExpandedRow { |
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.
We'll need to figure out something better eventually. I did a similar trick with the accordion / sidebar, but it definitely isn't very performant. With all the table stuff it clunks up a bit.
I don't have any better ideas. Think it would have to be a transform scaling trick.
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.
Yeah I'm pushing that all off to a different ticket.
@@ -0,0 +1,195 @@ | |||
@import '../../panel/index'; |
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.
We might want to separate out the mixins we need in panel similar to the way we're doing forms. This might dupe the entire panel css. That way you could just include panel/mixin
.
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.
Yeah it's already separated, I think I just imported index to quickly check usage and forgot to change it to the right file.
// Make each row a Panel | ||
@include euiPanel($selector: 'euiTableRow'); | ||
|
||
.euiTableRow { |
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.
Should this stuff be in table.scss with it's desktop equiv? The folder for /mobile/ mostly deals with new mobile specific components, but the Sass file does a bunch of overwriting of stuff down at the base layer. Usually we've included mobile overwrites in the same files to make it a little easier to read the overwrite.
I'm not tied to it, more just a general question. How do you think we should do this? If we leave it here, I think I'd at least wanna see some comments in the other files telling me where to go.
Also, we've generally used the _index.scss file as a pure import root. Again, don't think it's a big deal, just pointing stuff out and seeing what you think we should do.
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 reason I moved it was because I hate 300 line SASS files. Makes them feel less readable to me. Though, I can at least put it in a _responsive.scss file that's in the table root folder and leave the mobile file for strictly those new components.
You're right about the index file, I'll change that.
@@ -98,6 +103,8 @@ EuiTableHeaderCell.propTypes = { | |||
isSorted: PropTypes.bool, | |||
isSortAscending: PropTypes.bool, | |||
scope: PropTypes.oneOf(['col', 'row', 'colgroup', 'rowgroup']), | |||
isMobileHeader: PropTypes.bool, |
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 add prop docs here. I know you have some stuff in the example, but just nice for the autodocs as well.
@@ -98,6 +103,8 @@ EuiTableHeaderCell.propTypes = { | |||
isSorted: PropTypes.bool, | |||
isSortAscending: PropTypes.bool, | |||
scope: PropTypes.oneOf(['col', 'row', 'colgroup', 'rowgroup']), | |||
isMobileHeader: PropTypes.bool, | |||
hideForMobile: PropTypes.bool, |
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.
Same here.
src/components/table/table_row.js
Outdated
@@ -20,5 +33,9 @@ export const EuiTableRow = ({ children, className, isSelected, ...rest }) => { | |||
EuiTableRow.propTypes = { | |||
children: PropTypes.node, | |||
className: PropTypes.string, | |||
isSelectable: PropTypes.bool, |
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.
Same on all the row props too if you have time.
colSpan: PropTypes.number | ||
colSpan: PropTypes.number, | ||
header: PropTypes.string, | ||
hideForMobile: PropTypes.bool, |
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.
And this set as well.
EuiTableSortMobileItem.propTypes = { | ||
children: PropTypes.node, | ||
className: PropTypes.string, | ||
onSort: PropTypes.func, |
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.
Auto prop docs.
@snide Real quick reply, this branch did not break the width of the props tables. This is a screenshot of the published docs: |
@cchaos Sorry I wasn't more clear. Notice how the live one has bolded items for the props name, and the column seems to be missing in your branch. masterbranch |
Oh yeah good call, I guess I wasn't thinking about the application of using the mobile header just for styling and forgot that it would hide that column in non-mobile. I'll fix. |
@snide Ok, I think I addressed all your comments. |
- Uses `header` prop to add `data-header` to table cell and ouput content on small screens.
- `hideforMobile`: doesn’t display the cell at xSmall breakpoint - `isMobileHeader`: doesn’t display `data-header` attribute but enlarges the text and displays it full width
- add `isSelectable` to a row and it will absolutely position the check box on the far left
…er can be closed. Fix centering of loading error message.
…r ContextMenuPanel when sorted
- Shifted checkbox, expander, and actions around - Hiding actions if a row is selected - Some code cleanup
I can’t remember why I added it (might have been for debugging). I removed it and it didn’t seem to have any ill-consequences.
This reverts commit 03ce998802e6ef73386fc13a592d85e76ec63f4c.
I remembered why, it is to align cell contents in case a cell has no header.
- Fixing missing column in non-mobile of docs props table - Altering docs intro - Adding more props comments - Adding more props tables to responsive and custom (BUG: some components don’t seem to populate a props table)
- Importing panel mixins not index file - Putting table responsive stuff in a _responsive file - Only mobile component stuff in the _mobile.scss imported from it’s index
3b643d2
to
7330bb0
Compare
jenkins test 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 this out with @cchaos in Kibana by using a yarn link
. If you don't use the additional props provided in this PR, the tables can get a little ugly (though no uglier than they are now in mobile). WIth the addition of pseduo-titles it also means people will need to manually provide that content to the custom components if they go the custom table route (as is the case in the index management table in Kibana).
I'm gonna make an issue asking for some engineering help to make some of these things auto-apply so implementors don't need to worry about it, but I think it can wait for a follow up PR. Stuff like hasActions
and isSelectable
feels like stuff that can be automatically added based on the content. Till then, adding two lines to your tables ain't no big deal.
I do think we should probably list it as a Breaking change
just so people are aware of it when scanning the changelog. It doesn't technically break, but listing it as such will make people check this stuff out.
@cjcenizal and @bevacqua should do a similar scan over in cloud when they start using this.
For the immediate we'll just need to make people aware they need to make sure to add these props to their tables to make them awesome in mobile.
Party time? Nice work @cchaos, this was a very hard problem.
This one's a doozy.
Basic initialization of responsive table
header
prop to adddata-header
to table cell and ouput content on small screens.Allowing for custom row headers
hideforMobile
: doesn’t display the cell at xSmall breakpointisMobileHeader
: doesn’t displaydata-header
attribute but enlarges the text and displays it full widthAdding support for selections in mobile
isSelectable
to a row and it will absolutely position the check box on the far leftKeeping pagination on one line (no responsive)
Created mobile context menu for filtering
EuiTableSortMobile
for the whole context menuEuiTableSortMobileItem
for individual buttonsBUG: The items don’t update their render on clickfixedScrolling to top of table when:
Added support for actions in mobile
hasActions
to the BasicTable or Row to properly position the action buttons.Modifying the Custom table example
EuiTableHeaderMobile
to encapsulate multiple small screen only table options (sort/select all, etc…)/mobile
Allowing cells in mobile view to be explicitly 100% wide
isMobileFullWidth
as a prop toEuiTableRowCell
Added support for expanding rows
isExpandedRow
to theEuiTableRow
to get the right class.To Do
Feedback greatly appreciated.
I also welcome the opportunity to pair on this one.