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

Add Tree Grid Component #2181

Closed
wants to merge 19 commits into from
Closed

Conversation

aswinshenoy
Copy link
Contributor

Fixes #1836

CONTRIBUTOR checklist (do not remove)

Please complete for every pull request

  • First-time contributors should sign the Contributor License Agreement. It's a fancy way of saying that you are giving away your contribution to this project. If you haven't before, wait a few minutes and a bot will comment on this pull request with instructions.
  • npm run lint:fix has been run and linting passes.
  • Mocha, Jest (Storyshots), and components/component-docs.json CI tests pass (npm test).
  • Tests have been added for new props to prevent regressions in the future. See readme.
  • Review the appropriate Storybook stories. Open http://localhost:9001/.
  • Review tests are passing in the browser. Open http://localhost:8001/.
  • Review markup conforms to SLDS by looking at DOM snapshot strings.

REVIEWER checklist (do not remove)

  • TravisCI tests pass. This includes linting, Mocha, Jest, Storyshots, and components/component-docs.json tests.
  • Tests have been added for new props to prevent regressions in the future. See readme.
  • Review the appropriate Storybook stories. Open http://localhost:9001/.
  • The Accessibility panel of each Storybook story has 0 violations (aXe). Open http://localhost:9001/.
  • Review tests are passing in the browser. Open http://localhost:8001/.
  • Review markup conforms to SLDS by looking at DOM snapshot strings.
Required only if there are markup / UX changes
  • Add year-first date and commit SHA to last-slds-markup-review in package.json and push.
  • Request a review of the deployed Heroku app by the Salesforce UX Accessibility Team.
  • Add year-first review date, and commit SHA, last-accessibility-review, to package.json and push.
  • While the contributor's branch is checked out, run npm run local-update within locally cloned site repo to confirm the site will function correctly at the next release.

Copy link
Contributor

@kevinparkerson kevinparkerson left a comment

Choose a reason for hiding this comment

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

@aswinshenoy please see if there's a way to solve the rendering issues. I think a containing wrapper with a set height might help fix the extending lines, but I'm unsure. Let us know if you need help!

…react into tree-grid

# Conflicts:
#	components/storybook-stories.js
import TreeGrid from '~/components/tree-grid';
import IconSettings from '~/components/icon-settings';

const data = {
Copy link
Contributor

Choose a reason for hiding this comment

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

If there were no nested rows, then a dev would use a DataTable. I don't think we need this example and base should be nested.

import TreeGrid from '~/components/tree-grid';
import IconSettings from '~/components/icon-settings';

const data = {
Copy link
Contributor

Choose a reason for hiding this comment

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

The columns should be child components. See DataTable component.

Copy link
Contributor

Choose a reason for hiding this comment

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

Here is the Lightning component data for instance.

({ // eslint-disable-line
    init: function (cmp) {
        var columns = [
            {
                type: 'text',
                fieldName: 'accountName',
                label: 'Account Name',
                initialWidth: 300
            },
            {
                type: 'number',
                fieldName: 'employees',
                label: 'Employees'
            },
            {
                type: 'phone',
                fieldName: 'phone',
                label: 'Phone Number'
            },
            {
                type: 'url',
                fieldName: 'accountOwner',
                label: 'Account Owner',
                typeAttributes: {
                    label: { fieldName: 'accountOwnerName' }
                }
            },
            {
                type: 'text',
                fieldName: 'billingCity',
                label: 'Billing City'
            }
        ];

        cmp.set('v.gridColumns', columns);

        // data
        var nestedData = [
            {
                "name": "123555",
                "accountName": "Rewis Inc",
                "employees": 3100,
                "phone": "837-555-1212",
                "accountOwner": "http://example.com/jane-doe",
                "accountOwnerName": "Jane Doe",
                "billingCity": "Phoeniz, AZ"
            },

            {
                "name": "123556",
                "accountName": "Acme Corporation",
                "employees": 10000,
                "phone": "837-555-1212",
                "accountOwner": "http://example.com/john-doe",
                "accountOwnerName": "John Doe",
                "billingCity": "San Francisco, CA",
                "_children": [
                    {
                        "name": "123556-A",
                        "accountName": "Acme Corporation (Bay Area)",
                        "employees": 3000,
                        "phone": "837-555-1212",
                        "accountOwner": "http://example.com/john-doe",
                        "accountOwnerName": "John Doe",
                        "billingCity": "New York, NY",
                        "_children": [
                            {
                                "name": "123556-A-A",
                                "accountName": "Acme Corporation (Oakland)",
                                "employees": 745,
                                "phone": "837-555-1212",
                                "accountOwner": "http://example.com/john-doe",
                                "accountOwnerName": "John Doe",
                                "billingCity": "New York, NY"
                            },
                            {
                                "name": "123556-A-B",
                                "accountName": "Acme Corporation (San Francisco)",
                                "employees": 578,
                                "phone": "837-555-1212",
                                "accountOwner": "http://example.com/jane-doe",
                                "accountOwnerName": "Jane Doe",
                                "billingCity": "Los Angeles, CA"
                            }
                        ]
                    },

                    {
                        "name": "123556-B",
                        "accountName": "Acme Corporation (East)",
                        "employees": 430,
                        "phone": "837-555-1212",
                        "accountOwner": "http://example.com/john-doe",
                        "accountOwnerName": "John Doe",
                        "billingCity": "San Francisco, CA",
                        "_children": [
                            {
                                "name": "123556-B-A",
                                "accountName": "Acme Corporation (NY)",
                                "employees": 1210,
                                "phone": "837-555-1212",
                                "accountOwner": "http://example.com/jane-doe",
                                "accountOwnerName": "Jane Doe",
                                "billingCity": "New York, NY"
                            },
                            {
                                "name": "123556-B-B",
                                "accountName": "Acme Corporation (VA)",
                                "employees": 410,
                                "phone": "837-555-1212",
                                "accountOwner": "http://example.com/john-doe",
                                "accountOwnerName": "John Doe",
                                "billingCity": "New York, NY",
                                "_children": [
                                    {
                                        "name": "123556-B-B-A",
                                        "accountName": "Allied Technologies",
                                        "employees": 390,
                                        "phone": "837-555-1212",
                                        "accountOwner": "http://example.com/jane-doe",
                                        "accountOwnerName": "Jane Doe",
                                        "billingCity": "Los Angeles, CA",
                                        "_children": [
                                            {
                                                "name": "123556-B-B-A-A",
                                                "accountName": "Allied Technologies (UV)",
                                                "employees": 270,
                                                "phone": "837-555-1212",
                                                "accountOwner": "http://example.com/john-doe",
                                                "accountOwnerName": "John Doe",
                                                "billingCity": "San Francisco, CA"
                                            }
                                        ]
                                    }
                                ]
                            }
                        ]
                    }
                ]
            },

            {
                "name": "123557",
                "accountName": "Rhode Enterprises",
                "employees": 6000,
                "phone": "837-555-1212",
                "accountOwner": "http://example.com/john-doe",
                "accountOwnerName": "John Doe",
                "billingCity": "New York, NY",
                "_children": [
                    {
                        "name": "123557-A",
                        "accountName": "Rhode Enterprises (UCA)",
                        "employees": 2540,
                        "phone": "837-555-1212",
                        "accountOwner": "http://example.com/john-doe",
                        "accountOwnerName": "John Doe",
                        "billingCity": "New York, NY"
                    }
                ]
            },

            {
                "name": "123558",
                "accountName": "Tech Labs",
                "employees": 1856,
                "phone": "837-555-1212",
                "accountOwner": "http://example.com/john-doe",
                "accountOwnerName": "John Doe",
                "billingCity": "New York, NY",
                "_children": [
                    {
                        "name": "123558-A",
                        "accountName": "Opportunity Resources Inc",
                        "employees": 1934,
                        "phone": "837-555-1212",
                        "accountOwner": "http://example.com/john-doe",
                        "accountOwnerName": "John Doe",
                        "billingCity": "Los Angeles, CA"
                    }
                ]
            }
        ];

        cmp.set('v.gridData', nestedData);


        var expandedRows = ["123556", "123556-A", "123556-B", "123556-B-B", "123557"];

        cmp.set('v.gridExpandedRows', expandedRows);
    }
}); // eslint-disable-line

Copy link
Contributor

Choose a reason for hiding this comment

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

The data should be very similar. I would change _children to nodes align with Tree component. Please review Tree data https://github.com/salesforce/design-system-react/blob/master/utilities/sample-data/tree/nodes-base.jsx#L2

},
{
id: '2',
childOpen: true,
Copy link
Contributor

Choose a reason for hiding this comment

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

The Tree keys are:

	 *   expanded: string,
	 *   id: string,
	 *   label: string or node,
	 *   selected: string,
	 *   type: string,
	 *   nodes: array

},
{
label: 'Jane Doe',
href: 'javascript:void(0);',
Copy link
Contributor

@interactivellama interactivellama Aug 7, 2019

Choose a reason for hiding this comment

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

The default cell render should be just a string. If you'd like to scope this project to only output strings I'm cool with that. We can add custom rendering later

DataTable has a CustomCell render that receives the tree data as props. The CustomCell is the child of the Column child. See https://github.com/salesforce/design-system-react/blob/master/components/data-table/__examples__/advanced.jsx#L10

/* Copyright (c) 2015-present, salesforce.com, inc. All rights reserved */
/* Licensed under BSD 3-Clause - see LICENSE.txt or git.io/sfdc-license */

// Implements the [Welcome Mat design pattern](https://lightningdesignsystem.com/components/welcome-mat/) in React.
Copy link
Contributor

Choose a reason for hiding this comment

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

Typo

*/
id: PropTypes.string,

labels: PropTypes.shape({
Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Contributor

Choose a reason for hiding this comment

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

This is still outstanding. ^

Copy link
Contributor

Choose a reason for hiding this comment

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

oh, sorry, it's duplicate now. Please remove chooseRow, selectAll.

'slds-table_bordered',
'slds-table_edit',
'slds-table_fixed-layout',
'slds-table_resizable-cols',
Copy link
Contributor

Choose a reason for hiding this comment

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

Unless you are implementing resizable, this might need to be removed. I'd recommend not implementing it. It's not in the current Data either. Column width on the other hand is needed.

)
)}
<td role="gridcell" style={{ width: '3.25rem' }}>
<Button
Copy link
Contributor

Choose a reason for hiding this comment

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

This component should accept a TreeRowActions component as a child.

@interactivellama
Copy link
Contributor

interactivellama commented Aug 7, 2019

Typically, this component is going to have a fixed header, but if you want to descope that for now I'm OK with that. This comments means this is OK (no scrolling): http://design-system-react-components.herokuapp.com/?path=/story/sldsdatatable--advanced-fixed-layout

but you don't have to do this: http://design-system-react-components.herokuapp.com/?path=/story/sldsdatatable--fixed-header

@interactivellama
Copy link
Contributor

I will try to get you a new props proposal by tomorrow, but feel free to ask questions tonight and maybe we can discuss tomorrow in the meeting.

@interactivellama
Copy link
Contributor

So far this is what I have:

/* 
Optional:
* Inline editing and sorting of columns are not supported by the Lightning Component https://developer.salesforce.com/docs/component-library/bundle/lightning:treeGrid/documentation
* Column options is not needed
*/

// ### Prop Types
const propTypes = {
  /**
   * **Assistive text for accessibility.**
   * This object is merged with the default props object on every render.
   * * `actionsHeader`: Text for heading of actions column
   * * `columnSort`: Text for sort action on table column header
   * * `columnSortedAscending`: Text announced once a column is sorted in ascending order
   * * `columnSortedDescending`: Text announced once a column is sorted in descending order
   * * `selectAllRows`: Text for select all checkbox within the table header
   * * `selectRow`: Text for select row
   */
  assistiveText: PropTypes.shape({
    actionsHeader: PropTypes.string,
    // columnSort: PropTypes.string,
    // columnSortedAscending: PropTypes.string,
    // columnSortedDescending: PropTypes.string,
    selectAllRows: PropTypes.string,
    selectRow: PropTypes.string
  }),
  /**
   * Provide children of the type `<DataTableColumn />` to define the structure of the data being represented and children of the type `<DataTableRowActions />` to define a menu which will be rendered for each item in the grid. Use a _higher-order component_ to customize a data table cell that will override the default cell rendering. `CustomDataTableCell` must have the same `displayName` as `DataTableCell` or it will be ignored. If you want complete control of the HTML, including the wrapping `td`, you don't have to use `DataTableCell`.
   * ```
   * import DataTableCell from 'design-system-react/data-table/cell';
   * const CustomDataTableCell = ({ children, ...props }) => (
   *   <DataTableCell {...props} >
   *   <a href="javascript:void(0);">{children}</a>
   *   </DataTableCell>
   * );
   * CustomDataTableCell.displayName = DataTableCell.displayName;
   *
   * <TreeGrid>
   *   <TreeGridColumn />
   *   <TreeGridColumn>
   *   <TreeGridCustomCell />
   *   </TreeGridColumn>
   *   <TreeGridRowActions />
   * </TreeGrid>
   * ```
   */
  children: PropTypes.node,
  /**
   * Class names to be added to the table.
   */
  className: PropTypes.oneOfType([
    PropTypes.array,
    PropTypes.object,
    PropTypes.string
  ]),
  // this function is how child rows can be fetched asyncronously from the server
  // For this project it can be the default and use `forceUpdate` if you would like. Otherwise, please review Tree and https://github.com/paularmstrong/normalizr This concept took me a while to understand, but the gist is that you flatten all the nested data into an array and link the data via object keys. This is how normalized databases work with tree data.
  getNodes: node => node.nodes,
  /**
   * A unique ID is needed in order to support keyboard navigation and ARIA support.
   */
  id: PropTypes.string,
  /**
   * The collection of items to render in the table. This is an array of objects with each object having keys that correspond with the  `property` prop of each `DataTableColumn`.
   */
  nodes: PropTypes.arrayOf(
    PropTypes.shape({
      id: PropTypes.string.isRequired
    })
  ).isRequired,
  /**
   * This function triggers when a row is expanded
   */
  onExpandRow: PropTypes.func.isRequired,
  /**
   * This function fires when the selection of rows changes. This component passes in `event, { selection }` to the function. `selection` is an array of objects from the `items` prop.
   */
  onRowChange: PropTypes.func,
  /**
   * Specifies a row selection UX pattern.
   * * `multiple`: This is the default
   * * `single`: Single row selection.
   * _This prop used to be a `boolean`, a `true` value will be considered `checkbox` for backwards compatibility._
   */
  selectRows: PropTypes.oneOf(["single", "multiple"]),
  /**
   * TreeGrids have horizontal borders by default. This removes them.
   */
  unborderedRow: PropTypes.bool
};

const test = (
  <TreeGrid
    assistiveText={{
      actionsHeader: "actions",
      columnSort: "sort this column",
      columnSortedAscending: "asc",
      columnSortedDescending: "desc",
      selectAllRows: "all rows",
      selectRow: "select this row"
    }}
    getNodes={this.getNodes()}
    id="TreeGridExample"
    onRowChange={this.handleChanged}
    onExpandRow={this.handleExpandRow}
    onSort={this.handleSort}
  >
    <TreeGridColumn
      label="Name"
      property="opportunityName"
    >
      <CustomTreeGridCell />
    </TreeGridColumn>
    <TreeGridColumn label="Account Name" property="accountName" />
    <TreeGridColumn label="Close Date" property="closeDate" />
    <TreeGridColumn label="Stage" property="stage" />
    <TreeGridColumn
      label="Confidence"
      property="confidence"
    />
    <TreeGridColumn label="Amount" property="amount" />
    <TreeGridColumn label="Contact" property="contact">
      <CustomTreeGridCell />
    </TreeGridColumn>
    <TreeGridRowActions
      options={[
        {
          id: 0,
          label: "Add to Group",
          value: "1"
        },
        {
          id: 1,
          label: "Publish",
          value: "2"
        },
        {
          id: 2,
          label: "Third of Seven",
          value: "3"
        },
        {
          id: 3,
          label: "Fourth of Seven",
          value: "4"
        },
        {
          id: 4,
          label: "Fifth of Seven",
          value: "5"
        },
        {
          id: 5,
          label: "Sixth of Seven",
          value: "6"
        },
        {
          id: 6,
          label: "Seventh of Seven",
          value: "7"
        }
      ]}
      menuPosition="overflowBoundaryElement"
      onAction={this.handleRowAction}
    />
  </TreeGrid>
);

@interactivellama interactivellama temporarily deployed to design-system-react-co-pr-2181 August 9, 2019 20:58 Inactive
@interactivellama interactivellama temporarily deployed to design-system-react-co-pr-2181 August 13, 2019 19:19 Inactive
@interactivellama interactivellama temporarily deployed to design-system-react-co-pr-2181 August 16, 2019 17:23 Inactive
@interactivellama interactivellama temporarily deployed to design-system-react-co-pr-2181 September 12, 2019 06:43 Inactive
@aswinshenoy
Copy link
Contributor Author

aswinshenoy commented Sep 12, 2019

In the single select variant, I have used onClick of the row for selection, but that causes the expansion button inside the row (onExpand) to also trigger causing expansion & selection together.

It would be better if could adopt the following Datatable single select design pattern for Treegrid against the current SLDS pattern.
image
instead of
image

@interactivellama interactivellama temporarily deployed to design-system-react-co-pr-2181 September 12, 2019 07:27 Inactive
@interactivellama interactivellama temporarily deployed to design-system-react-co-pr-2181 September 12, 2019 08:32 Inactive
@interactivellama
Copy link
Contributor

Screen Shot 2019-09-12 at 9 21 34 AM

does the indeterminate state only apply to the top-level and not for rows

Yes. That's correct. Please think of the selection as flat even if the data is hierarchal--therefore only use indeterminate on the "Select All" checkbox which is how DataTable works.

the consumers are free to change the logic as they wish, and we shouldn't be worrying to much

Yes. That's correct. There are some differing opinions on the select all interaction pattern. I'd would like to see Select All select all the rows in the table (even the hidden ones). Since updating the data would be handled in the example code anyway, if that pattern changes in the future, it's not a big deal--we'd just update the example--but it's good to provide a good default, because everyone loves to copy and paste! 😄

One way to think about this mash up of a DataTable and Tree here at Salesforce is that it's often a database union of a table with itself. That is take the ACCOUNTS table and merge it with same ACCOUNTS table based on COLUMN A which have the same value, so the data is visibly hierarchal, but you could also, flatten the data and add a column that "links the child/parent relationships." Another way to think of it is as file tree. Selection of a folder is not visible UI selection of the children.

@interactivellama
Copy link
Contributor

As for clicking the row, in the Tree there is selection and example in separate DOM nodes. What is the difference here?

We need to keep single selection and simply a treegrid and not the merger of a DataTable and a TreeGrid that is the multiple selection variant. onRowExpand should only be triggered by the expand button or keyboard keys. Maybe an event trap needs to be present? https://github.com/salesforce/design-system-react/blob/master/components/tree/private/render-branch.jsx#L84

@aswinshenoy
Copy link
Contributor Author

I am still unable to fix the issue of moreActionsDropdown passed in of column getting overlapped by the rows. I tried playing around with z-index, but doesn't seem to work :( Can you please guide me on this @interactivellama?

image

@interactivellama interactivellama temporarily deployed to design-system-react-co-pr-2181 September 13, 2019 18:46 Inactive
@aswinshenoy
Copy link
Contributor Author

aswinshenoy commented Sep 13, 2019

I have used event trap for selection and expansion handlers, and everything seems to be working fine now. In case of the checkbox, I had made the example exactly as you had said, so it didn't require any changes.

I am yet to touch the switching part between Navigation Mode <-> Selection Mode. As far as I learnt: -

  1. Pressing Right once should expand
  2. Pressing Right once again should switch mode to navigation
  3. Pressing Left in the left-most cell on navigation mode will switch it back to selection mode

However, I have a slight confusion, regarding what objects will be focused
a. should all columns be focused/hovered one after other using is-hovered ? - https://www.lightningdesignsystem.com/components/tree-grid/#Item-Hovered
b. should only the columns with actions like links allowed to be hovered? (I don't know how we will identify it though)

I think we would be going with hovering each and every column in row (maybe except columns with some hoverDisabled prop)?

PS: I will start with browser testing later today, as rendering and functionality is almost done :)

@interactivellama interactivellama temporarily deployed to design-system-react-co-pr-2181 September 13, 2019 19:40 Inactive
@stale
Copy link

stale bot commented Nov 12, 2019

This issue has been automatically marked as stale, because it has not had recent activity. It will be closed if no further activity occurs. Maintainers are responsible for tech debt and project health. This is most likely a new components or component feature request. Please submit a pull request for or request feedback on this feature. Thank you.

@stale stale bot added the stale label Nov 12, 2019
@stale stale bot closed this Nov 20, 2019
@stale stale bot removed the stale label Jul 14, 2020
@interactivellama interactivellama temporarily deployed to design-system-react-co-pr-2181 July 14, 2020 18:28 Inactive
@stale
Copy link

stale bot commented Sep 12, 2020

This issue has been automatically marked as stale, because it has not had recent activity. It will be closed if no further activity occurs. Maintainers are responsible for tech debt and project health. This is most likely a new components or component feature request. Please submit a pull request for or request feedback on this feature. Thank you.

@stale stale bot added the stale label Sep 12, 2020
@stale stale bot closed this Sep 20, 2020
@stale stale bot removed the stale label Sep 22, 2020
@stale
Copy link

stale bot commented Dec 19, 2020

This issue has been automatically marked as stale, because it has not had recent activity. It will be closed if no further activity occurs. Maintainers are responsible for tech debt and project health. This is most likely a new components or component feature request. Please submit a pull request for or request feedback on this feature. Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add Tree Grid component
3 participants