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
Adds Pagination to Data Table #1367
Conversation
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.
One thing we need to keep in mind is what pagination is used for on the back end; we use pagination to show a subset of all rows in the database.
When the controls are clicked, we need to fetch the next page from the back-end, then show that data in the table.
Instead of paging in the front end, we can simplify the logic a bit to just have click handlers and let the component that wraps the <DataTable />
figure out how to fetch the page.
Let me know if this makes sense or if you want to discuss on a call.
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 I see a way to make this API a little nicer. What about:
function MyComponent() {
const handleForward = () => {
console.log("forward!");
};
const handleBack = () => {
console.log("back");
};
return (
<DataTable rows={[]} fields={[]}>
<PaginationControls onForward={handleForward} onBack={handleBack} />
</DataTable>
);
}
Or, if you don't like having the controls as children, what about as a prop:
function MyComponent() {
const handleForward = () => {
console.log("forward!");
};
const handleBack = () => {
console.log("back");
};
return (
<DataTable
rows={[]}
fields={[]}
paginationControls={
<PaginationControls onForward={handleForward} onBack={handleBack} />
}
/>
);
}
This lifts the controls up and you avoid prop drilling.
ui/components/ConditionsTable.tsx
Outdated
{ label: "Status", value: "status" }, | ||
{ label: "Reason", value: "reason" }, | ||
{ label: "Message", value: "message" }, | ||
{ label: "type", displayLabel: "Type", value: "type" }, |
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 shouldn't be a label
and displayLabel
prop here; label
is already mean to give control over what gets displayed.
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 the _.sort function to work the labels have to be all lowercase to match the fields on the rows which meant of lot of string.toLowerCase()-ing which I h8ed.
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 go with string.toLowerCase()
myself. As it is in this PR, it is a leaky abstraction, and you are asking the user to think about how the sorting logic works.
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 only other thing that's coming to mind is if someone wants to sort columns with a label that won't match when it's shifted to lowercase. Like "Last Commit" with last_commit
as the key. It makes those columns not sortable right?
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.
You can do stuff like _.lowerCase(_.snakeCase(string))
if you want to normalize the values. I would have to see the full filtering implementation to say for sure.
It's beautiful! Some design-system nits (that @mmoulian and I will prepare better for you in the future)
|
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 good, save for the blockers around displayLabel
and <Link />
text sizes
ui/components/ConditionsTable.tsx
Outdated
{ label: "Status", value: "status" }, | ||
{ label: "Reason", value: "reason" }, | ||
{ label: "Message", value: "message" }, | ||
{ label: "type", displayLabel: "Type", value: "type" }, |
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 go with string.toLowerCase()
myself. As it is in this PR, it is a leaky abstraction, and you are asking the user to think about how the sorting logic works.
ui/components/Link.tsx
Outdated
@@ -13,7 +13,11 @@ type Props = { | |||
}; | |||
|
|||
function Link({ children, href, className, to = "", newTab, ...props }: Props) { | |||
const txt = <Text color="primary">{children}</Text>; | |||
const txt = ( | |||
<Text size="small" color="primary"> |
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 want to change all <Link />
components to have small text?
ui/components/Pagination.tsx
Outdated
/** func for skip to start button */ | ||
onSkipBack: () => void; | ||
/** onChange func for perPage select */ | ||
onSelect: (value) => void; |
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.
Let's give this value
a type. Is it a string? Number?
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's an event, and it needs to always be an event right? Is there a way to express that in Typescript?
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.
Something like React.SyntheticEvent
or some such:
onSelect: (value) => void; | |
onSelect: (ev: React.SyntheticEvent) => void; |
You can also just leave it blank if you don't expect the user to do anything with the arg.
ui/components/Pagination.tsx
Outdated
variant="text" | ||
aria-label="skip to first page" | ||
disabled={index === 0} | ||
onClick={() => onSkipBack()} |
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.
onClick={() => onSkipBack()} | |
onClick={onSkipBack} |
expect(onSkipBack).toHaveBeenCalledTimes(1); | ||
fireEvent.click(back); | ||
expect(onBack).toHaveBeenCalledTimes(1); | ||
expect(displayText).toBeTruthy(); |
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.
What should this display text actually be? .toBeTruthy()
will return ok on literally any string.
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.
Yes but the test will fail if it does not match /6 - 6 out of 10/ because it won't find the string at all
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.
LGTM, save for the displayLabel
thing
ui/components/ConditionsTable.tsx
Outdated
{ label: "Status", value: "status" }, | ||
{ label: "Reason", value: "reason" }, | ||
{ label: "Message", value: "message" }, | ||
{ label: "type", displayLabel: "Type", value: "type" }, |
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.
You can do stuff like _.lowerCase(_.snakeCase(string))
if you want to normalize the values. I would have to see the full filtering implementation to say for sure.
ui/components/Pagination.tsx
Outdated
/** func for skip to start button */ | ||
onSkipBack: () => void; | ||
/** onChange func for perPage select */ | ||
onSelect: (value) => void; |
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.
Something like React.SyntheticEvent
or some such:
onSelect: (value) => void; | |
onSelect: (ev: React.SyntheticEvent) => void; |
You can also just leave it blank if you don't expect the user to do anything with the arg.
…nk size in data table + other small fixes
</div> | ||
); | ||
} | ||
|
||
export const DataTable = styled(UnstyledDataTable)` | ||
h2 { | ||
font-size: 14px; | ||
font-weight: 600; |
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 have played around with this in the inspector and for me this only renders bold (> 600) or regular (<600) – is semi-bold Proxima Nova not getting imported somewhere?
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.
It DEFINITELY changes but it is subtle for sure
* pagination added * added tests * added displayLabel key to fields to avoid manipulating string in data table * added display label field to data table story * display label fix in commits table * woke up in a cold sweat realizing that the indexing for the text was wrong so I fixed it * redo w/o tests * redo two with tests * data table styling changes * removed displayLabel and added textProps to Link in order to alter link size in data table + other small fixes * got rid of TextProps it was bad
Closes: #1361
Adds pagination functionality to the data table + unit tests
tested in react storybook
npm run storybook