Skip to content

Commit

Permalink
Merge pull request #39 from onaio/issue-38-hasChildren
Browse files Browse the repository at this point in the history
Make hasChildren configurable
  • Loading branch information
moshthepitt authored Apr 11, 2019
2 parents 57c4a90 + 2d0762c commit 8ab8b7d
Show file tree
Hide file tree
Showing 10 changed files with 37,831 additions and 18,449 deletions.
94 changes: 63 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,25 @@

This is the home of shared javascript components and utilities for Ona.

## Typescript Support

It is actually recommended to create all new packages using `Typescript`. The instructions above on how to add a new package are all that you need to get started.

In addition to the above instructions, you need to create a `tsconfig.json` file next to the package.json file inside your new package's directory.

The contents of this file should be something like:

```json
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "dist",
"declarationDir": "dist/types"
},
"include": ["src"]
}
```

## Contribution

Contribution is highly encouraged. If you have something - a tool, a component, a useful utility function, etc. - that would be useful to others then by all means please add it to this repository.
Expand Down Expand Up @@ -84,7 +103,7 @@ Here's an example sample `package.json` for a `js`/`jsx` package:
},
"scripts": {
"jest": "jest --coverage --verbose --color",
"transpile": "babel src -d dist --root-mode upward --ignore '**/*.test.js,**/*.test.jsx,**/tests,**/__tests__' --copy-files"
"transpile": "babel src -d dist --root-mode upward --ignore '**/*.test.js,**/*.test.jsx,**/tests,**/__tests__'"
},
// the list of files to be included by npm when the package is published
"files": ["dist"],
Expand Down Expand Up @@ -128,7 +147,7 @@ Here's an example sample `package.json` for a `ts`/`tsx` package:
"scripts": {
"jest": "jest --coverage --verbose --color",
"tsc": "tsc",
"transpile": "babel src -d dist --root-mode upward --extensions '.ts,.tsx' --ignore '**/*.test.ts,**/*.test.tsx,**/tests,**/__tests__' --copy-files"
"transpile": "babel src -d dist --root-mode upward --extensions '.ts,.tsx' --ignore '**/*.test.ts,**/*.test.tsx,**/tests,**/__tests__'"
},
// the list of files to be included by npm when the package is published
"files": ["dist"],
Expand Down Expand Up @@ -192,55 +211,68 @@ Your transpiled package is saved in the `dist` directory within each package. No

## Publishing

Assuming that you have the `js-tools` repo cloned locally, switch to the `master` branch and proceed:
### Prepare for publishing

Before we publish our packages, we need to prepare them. Currently, this means we need to do two things: generating Typescript type delcaration files, and transpiling the code.

First, tag releases for Github - this will tag releases on Github and create a changelog for all updated packages:
You will need to switch to the package that you want to publish by running

```sh
lerna version --github-release --conventional-commits
cd packages/SomePackage
```

Next clean your `dist` folders locally to remove old files:
Transpile the package - this will create the distribution-ready files:

The command to do this depends on whether the package uses javascript or Typescript.

```sh
yarn clean-build
# javascript package
babel src -d dist --root-mode upward --ignore '**/*.test.js,**/*.test.jsx,**/tests,**/__tests__'

# typescript package
yarn babel src -d dist --root-mode upward --extensions '.ts,.tsx' --ignore '**/*.test.ts,**/*.test.tsx,**/tests,**/__tests__'
```

Generate type declaration files for packages written in Typescript:
> Note that you may need to compy non-js/non-typescript files to the `dist` directory manually e.g. css files
```sh
lerna run tsc
```
Once this is done, commit any changes to the `dist` folder.

Transpile the packages - this will create the distribution-ready files for all packages:
Next, generate type declaration files for packages written in Typescript:

```sh
lerna run transpile
yarn tsc
```

Finally, publish the packages to the `npm` registry:
Once this is done, commit changes to the `types` folder. You may have to ignore some stubborn linter warnings.

```sh
lerna publish from-git
```
---

You may want to checkout documentation for the [`lerna version`](https://github.com/lerna/lerna/tree/master/commands/version) and [`lerna publish`](https://github.com/lerna/lerna/tree/master/commands/publish) commands.
Once you have done the above, you would then push your changes, have your code reviewed and eventually merged to master before you proceed.

## Typescript Support
### Actually publish

It is actually recommended to create all new packages using `Typescript`. The instructions above on how to add a new package are all that you need to get started.
Assuming that you have the `js-tools` repo cloned locally, switch to the `master` branch and proceed:

In addition to the above instructions, you need to create a `tsconfig.json` file next to the package.json file inside your new package's directory.
1. To authenticate with Github, you need to define the following environment variable:

The contents of this file should be something like:
> _GH_TOKEN_ (required) - Your GitHub authentication token (under Settings > Developer settings > Personal access tokens)
```json
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "dist",
"declarationDir": "dist/types"
},
"include": ["src"]
}
2. Next, tag releases on Github and create a changelog for all updated packages:

```sh
lerna version --github-release --conventional-commits
```

3. At this point, we are ready to publish to `npm`. You would, of course, need to log in to npm first:

```sh
npm login
```

4. Finally, publish the packages to the `npm` registry:

```sh
lerna publish from-git
```

You may want to checkout documentation for the [`lerna version`](https://github.com/lerna/lerna/tree/master/commands/version) and [`lerna publish`](https://github.com/lerna/lerna/tree/master/commands/publish) commands.
66 changes: 66 additions & 0 deletions packages/DrillDownTable/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,30 @@ When the table is rendered, you can click anywhere on a row to drill down to the

This is a component responsible for rendering the cell in which the `linkerField` (above) is found. By default it just adds a caret to show if you can drill down on a row of data or not. However you can supply your own component that renders whatever else you may want - for example instead of a caret you may want to show a link. Have a look at [`DropDownCell`](src/helpers/DropDownCell.tsx) for an example of how this component might look at.

#### extraCellProps

This is an object that represents extra props to be given to the `CellComponent` (above).

#### useDrillDownTrProps

By default `DrillDownTable` allows you to click on any row to drill-down to the next hierarchical level of data. This is achieved by having a [custom geTrProps](https://github.com/tannerlinsley/react-table/tree/v6#props) built into `DrillDownTable`. You can turn this off by setting `useDrillDownTrProps` to be `false`.

#### hasChildren

This is a function that returns a `boolean` indicating whether or not a row of data has children i.e. should you be able to drill down using the given row?

A sample `hasChildren` function looks like so:

```ts
export function hasChildrenFunc(
currentObject: RowInfo | CellInfo,
parentIdList: number[] | string[],
idField: string | number = 'id'
) {
return parentIdList.includes(currentObject.original[idField]);
}
```

### Code examples

Simplest example:
Expand Down Expand Up @@ -155,3 +175,49 @@ const props = {
};
<DrillDownTable {...props} />;
```

Use a custom `CellComponent` and `extraCellProps`.

```tsx
interface NewCellComponentProps extends DropDownCellProps {
urlPath: string;
caret: string;
}

const NewCellComponent: React.ElementType = (props: NewCellComponentProps) => {
const { cellValue, hasChildren, urlPath, caret } = props;
return (
<div>
<span>
{hasChildren ? (
<a href={urlPath}>
{cellValue} {caret}
</a>
) : (
cellValue
)}
</span>
</div>
);
};

const props = {
CellComponent: NewCellComponent,
data,
extraCellProps: { urlPath: 'http://example.com', caret: <span>&#43;</span> }
};
<DrillDownTable {...props} />;
```

Use custom `hasChildren`

```tsx
import 'react-table/react-table.css';
import DrillDownTable from '@onaio/drill-down-table/';

const props = {
data: data,
hasChildren: (item, parents, idfield) => item.original[idfield] === 10
};
<DrillDownTable {...props} />;
```
31 changes: 18 additions & 13 deletions packages/DrillDownTable/dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.hasChildrenFunc = hasChildrenFunc;
Object.defineProperty(exports, "DropDownCell", {
enumerable: true,
get: function get() {
Expand Down Expand Up @@ -47,8 +48,14 @@ var _DropDownCell = _interopRequireWildcard(require("./helpers/DropDownCell"));

var _WithHeaders = _interopRequireWildcard(require("./WithHeaders"));

function hasChildrenFunc(currentObject, parentIdList) {
var idField = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'id';
return parentIdList.includes(currentObject.original[idField]);
}

function DrillDownTable(props) {
var data = props.data,
hasChildren = props.hasChildren,
parentIdentifierField = props.parentIdentifierField,
useDrillDownTrProps = props.useDrillDownTrProps;
var columns = (0, _WithHeaders.getColumns)(props);
Expand All @@ -74,7 +81,7 @@ function DrillDownTable(props) {
setPreviousParentId = _useState8[1];

(0, _react.useEffect)(function () {
if (props.rootParentId !== currentParentId) {
if (props.rootParentId != null && props.rootParentId !== currentParentId) {
setPreviousParentId(currentParentId);
setCurrentParentId(props.rootParentId);
}
Expand Down Expand Up @@ -104,16 +111,6 @@ function DrillDownTable(props) {
return data;
}

function hasChildren(row) {
var identifierField = props.identifierField;

if (identifierField && parentNodes && parentNodes.includes(row.original[identifierField])) {
return true;
}

return false;
}

var drillDownTrProps = function drillDownTrProps(row, instance) {
var getTrProps = props.getTrProps;

Expand All @@ -124,7 +121,7 @@ function DrillDownTable(props) {
return {
onClick: function onClick() {
if (props.identifierField && props.parentIdentifierField) {
if (hasChildren(instance)) {
if (hasChildren && hasChildren(instance, parentNodes, props.identifierField) === true) {
var newParentId = instance.original[props.identifierField];
var oldParentId = instance.original[props.parentIdentifierField];
setCurrentParentId(newParentId);
Expand All @@ -149,9 +146,16 @@ function DrillDownTable(props) {
if (el.accessor === linkerField) {
el.Cell = function (cell) {
if (CellComponent !== undefined) {
var _identifierField = props.identifierField;
var thisCellHasChildren = false;

if (hasChildren && _identifierField && hasChildren(cell, parentNodes, _identifierField)) {
thisCellHasChildren = true;
}

var cellProps = {
cellValue: cell.value,
hasChildren: hasChildren(cell)
hasChildren: thisCellHasChildren
};

if (extraCellProps !== undefined) {
Expand Down Expand Up @@ -187,6 +191,7 @@ function DrillDownTable(props) {

DrillDownTable.defaultProps = {
CellComponent: _DropDownCell.default,
hasChildren: hasChildrenFunc,
identifierField: _constants.ID,
linkerField: _constants.ID,
parentIdentifierField: _constants.PARENT_ID,
Expand Down
16 changes: 15 additions & 1 deletion packages/DrillDownTable/dist/types/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,26 @@
import React from 'react';
import { TableProps } from 'react-table';
import { CellInfo, RowInfo, TableProps } from 'react-table';
import './DrillDownTable.css';
import DropDownCell, { DropDownCellProps } from './helpers/DropDownCell';
import { FlexObject } from './helpers/utils';
import WithHeaders, { getColumns } from './WithHeaders';
/** Type definition for hasChildrenFunc */
export declare type hasChildrenFuncType = (
currentObject: RowInfo | CellInfo,
parentIdList: number[] | string[],
idField: string | number
) => boolean;
/** Check if a row of data has children */
export declare function hasChildrenFunc(
currentObject: RowInfo | CellInfo,
parentIdList: number[] | string[],
idField?: string | number
): boolean;
/** Interface to define props of Drill down table */
export interface DrillDownProps<T> extends Partial<TableProps<T>> {
CellComponent: React.ElementType;
extraCellProps?: FlexObject;
hasChildren?: hasChildrenFuncType;
identifierField?: string;
linkerField?: string;
parentIdentifierField?: string;
Expand All @@ -22,6 +35,7 @@ declare function DrillDownTable<T>(props: Partial<DrillDownProps<T>>): JSX.Eleme
declare namespace DrillDownTable {
var defaultProps: {
CellComponent: React.ElementType<any>;
hasChildren: typeof hasChildrenFunc;
identifierField: string;
linkerField: string;
parentIdentifierField: string;
Expand Down
Loading

0 comments on commit 8ab8b7d

Please sign in to comment.