Skip to content
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

Merged
merged 11 commits into from Feb 2, 2022
Merged

Adds Pagination to Data Table #1367

merged 11 commits into from Feb 2, 2022

Conversation

joshri
Copy link
Contributor

@joshri joshri commented Jan 28, 2022

Closes: #1361

Adds pagination functionality to the data table + unit tests

tested in react storybook npm run storybook

image

@joshri joshri added the area/ui Issues that require front-end work label Jan 28, 2022
Copy link
Contributor

@jpellizzari jpellizzari left a 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.

ui/components/CommitsTable.tsx Outdated Show resolved Hide resolved
ui/components/DataTable.tsx Outdated Show resolved Hide resolved
Copy link
Contributor

@jpellizzari jpellizzari left a 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.

{ label: "Status", value: "status" },
{ label: "Reason", value: "reason" },
{ label: "Message", value: "message" },
{ label: "type", displayLabel: "Type", value: "type" },
Copy link
Contributor

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.

Copy link
Contributor Author

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.

Copy link
Contributor

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.

Copy link
Contributor Author

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?

Copy link
Contributor

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/DataTable.tsx Outdated Show resolved Hide resolved
ui/components/DataTable.tsx Outdated Show resolved Hide resolved
@bia
Copy link

bia commented Feb 1, 2022

It's beautiful!

Some design-system nits (that @mmoulian and I will prepare better for you in the future)

  • All of the text should be 14px instead of 16pxand 20px, with the title weight semi-bold (not bold)
  • The heading/title which is sorting the table (with the arrow) should change color to Application/text/dark or #1a1a1a
  • could 'No rows' be renamed 'No data'? We're thinking something like this :

Screenshot 2022-02-01 at 14 24 16

(icon svg [here](https://drive.google.com/file/d/1orX5jeBpj25Tepww_ITmcJodcQbZlcKp/view?usp=sharing) )

Copy link
Contributor

@jpellizzari jpellizzari left a 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

{ label: "Status", value: "status" },
{ label: "Reason", value: "reason" },
{ label: "Message", value: "message" },
{ label: "type", displayLabel: "Type", value: "type" },
Copy link
Contributor

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.

@@ -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">
Copy link
Contributor

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?

/** func for skip to start button */
onSkipBack: () => void;
/** onChange func for perPage select */
onSelect: (value) => void;
Copy link
Contributor

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?

Copy link
Contributor Author

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?

Copy link
Contributor

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:

Suggested change
onSelect: (value) => void;
onSelect: (ev: React.SyntheticEvent) => void;

https://github.com/DefinitelyTyped/DefinitelyTyped/blob/14d95eb0fe90f5e0579c49df136cccdfe89b2855/types/react/index.d.ts#L1167

You can also just leave it blank if you don't expect the user to do anything with the arg.

variant="text"
aria-label="skip to first page"
disabled={index === 0}
onClick={() => onSkipBack()}
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
onClick={() => onSkipBack()}
onClick={onSkipBack}

ui/components/__tests__/Pagination.test.tsx Outdated Show resolved Hide resolved
ui/components/__tests__/Pagination.test.tsx Show resolved Hide resolved
expect(onSkipBack).toHaveBeenCalledTimes(1);
fireEvent.click(back);
expect(onBack).toHaveBeenCalledTimes(1);
expect(displayText).toBeTruthy();
Copy link
Contributor

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.

Copy link
Contributor Author

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

Copy link
Contributor

@jpellizzari jpellizzari left a 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

{ label: "Status", value: "status" },
{ label: "Reason", value: "reason" },
{ label: "Message", value: "message" },
{ label: "type", displayLabel: "Type", value: "type" },
Copy link
Contributor

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.

/** func for skip to start button */
onSkipBack: () => void;
/** onChange func for perPage select */
onSelect: (value) => void;
Copy link
Contributor

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:

Suggested change
onSelect: (value) => void;
onSelect: (ev: React.SyntheticEvent) => void;

https://github.com/DefinitelyTyped/DefinitelyTyped/blob/14d95eb0fe90f5e0579c49df136cccdfe89b2855/types/react/index.d.ts#L1167

You can also just leave it blank if you don't expect the user to do anything with the arg.

</div>
);
}

export const DataTable = styled(UnstyledDataTable)`
h2 {
font-size: 14px;
font-weight: 600;
Copy link

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?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmmmm...I feel like I've seen that before, but I just tested it here's the screenshots:

font-weight 800:
image

font-weight 600:
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.

It DEFINITELY changes but it is subtle for sure

@joshri joshri merged commit 0d6fd9c into main Feb 2, 2022
@joshri joshri deleted the 1361-pagination branch February 2, 2022 16:22
jpellizzari pushed a commit that referenced this pull request Mar 3, 2022
* 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/ui Issues that require front-end work
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add Pagination to Data Table
3 participants