Skip to content

Commit

Permalink
Add actions and loading
Browse files Browse the repository at this point in the history
  • Loading branch information
djhi committed Oct 3, 2019
1 parent 0bc393e commit 2e211cd
Show file tree
Hide file tree
Showing 8 changed files with 279 additions and 20 deletions.
42 changes: 28 additions & 14 deletions packages/ra-tree-core/src/TreeController.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import { Component, ReactElement, ComponentType } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import compose from 'recompose/compose';
import inflection from 'inflection';
import { Identifier, withTranslate, Translate } from 'ra-core';
import { getTreeRootNodes } from './selectors';
import {
crudGetTreeRootNodes as crudGetTreeRootNodesAction,
closeNode as closeNodeAction,
expandNode as expandNodeAction,
toggleNode as toggleNodeAction,
} from './actions';
import { Identifier } from 'ra-core';

export type NodeFunction = (nodeId: Identifier) => void;

Expand Down Expand Up @@ -41,6 +43,7 @@ interface InjectedProps {
hasList: boolean;
hasShow: boolean;
resource: string;
translate: Translate;
}

interface StateProps {
Expand Down Expand Up @@ -106,12 +109,24 @@ export class TreeControllerView extends Component<
expandNode,
parentSource,
resource,
toggleNode,
rootNodes,
toggleNode,
translate,
...props
} = this.props;

const resourceName = translate(`resources.${resource}.name`, {
smart_count: 2,
_: inflection.humanize(inflection.pluralize(resource)),
});
const defaultTitle = translate('ra.page.list', {
name: resourceName,
});

console.log({ loading: props.loading });

return children({
defaultTitle,
parentSource,
nodes: rootNodes,
closeNode: this.handleCloseNode,
Expand All @@ -129,18 +144,17 @@ const mapStateToProps = (state, { resource }) => ({
version: state.admin.ui.viewVersion,
});

const TreeController = connect<
StateProps,
DispatchProps,
Props & InjectedProps
>(
mapStateToProps,
{
crudGetTreeRootNodes: crudGetTreeRootNodesAction,
closeNode: closeNodeAction,
expandNode: expandNodeAction,
toggleNode: toggleNodeAction,
}
const TreeController = compose<any, Props>(
connect(
mapStateToProps,
{
crudGetTreeRootNodes: crudGetTreeRootNodesAction,
closeNode: closeNodeAction,
expandNode: expandNodeAction,
toggleNode: toggleNodeAction,
}
),
withTranslate
)(TreeControllerView);

TreeController.defaultProps = {
Expand Down
Empty file.
95 changes: 92 additions & 3 deletions packages/ra-tree-ui-materialui/src/TreeList.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,97 @@
import React from 'react';
import React, { cloneElement } from 'react';
import classnames from 'classnames';
import Card from '@material-ui/core/Card';
import { createStyles } from '@material-ui/core/styles';
import { Title } from 'ra-ui-materialui';

import TreeNodeList from './TreeNodeList';
import TreeListLoading from './TreeListLoading';
import TreeListActions from './TreeListActions';
import TreeListToolbar from './TreeListToolbar';

const TreeList = ({ children, ...props }) => (
<TreeNodeList {...props}>{children}</TreeNodeList>
const TreeList = ({
actions = <TreeListActions />,
aside,
children,
className,
classes,
defaultTitle,
exporter,
filter,
loading,
title,
version,
...props
}) => (
<div
className={classnames('tree-page', classes.root, className)}
{...sanitizeRestProps(props)}
>
<Title title={title} defaultTitle={defaultTitle} />
<Card className={classes.card}>
{actions && (
<TreeListToolbar
{...props}
actions={actions}
exporter={exporter}
permanentFilter={filter}
/>
)}
{loading && props.nodes.length === 0 ? (
<TreeListLoading />
) : (
<div key={version}>
<TreeNodeList {...props}>{children}</TreeNodeList>
</div>
)}
</Card>
{aside && cloneElement(aside, props)}
</div>
);

export default TreeList;

export const styles = createStyles({
root: {
display: 'flex',
flex: 1,
},
card: {
position: 'relative',
flex: '1 1 auto',
},
actions: {
zIndex: 2,
display: 'flex',
justifyContent: 'flex-end',
flexWrap: 'wrap',
},
noResults: { padding: 20 },
});

const sanitizeRestProps = ({
basePath,
children,
classes,
closeNode,
data,
expandNode,
hasCreate,
hasEdit,
hasList,
hasShow,
history,
loading,
locale,
location,
match,
nodes,
options,
parentSource,
permissions,
positionSource,
resource,
toggleNode,
version,
...rest
}: any) => rest;
48 changes: 48 additions & 0 deletions packages/ra-tree-ui-materialui/src/TreeListActions.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import React from 'react';
import PropTypes from 'prop-types';
import onlyUpdateForKeys from 'recompose/onlyUpdateForKeys';
import { sanitizeListRestProps } from 'ra-core';
import { CardActions, CreateButton, ExportButton } from 'react-admin';

const TreeListActions = ({
basePath,
className,
closeNode,
currentSort,
expandNode,
exporter,
hasCreate,
hasEdit,
hasList,
hasShow,
parentSource,
permanentFilter,
positionSource,
resource,
toggleNode,
total,
...rest
}) => (
<CardActions className={className} {...sanitizeListRestProps(rest)}>
{hasCreate && <CreateButton basePath={basePath} />}
{exporter !== false && (
<ExportButton
disabled={total === 0}
resource={resource}
sort={currentSort}
filter={permanentFilter}
exporter={exporter}
/>
)}
</CardActions>
);

TreeListActions.propTypes = {
basePath: PropTypes.string,
className: PropTypes.string,
exporter: PropTypes.oneOfType([PropTypes.func, PropTypes.bool]),
hasCreate: PropTypes.bool,
resource: PropTypes.string,
};

export default onlyUpdateForKeys(['resource'])(TreeListActions);
63 changes: 63 additions & 0 deletions packages/ra-tree-ui-materialui/src/TreeListLoading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import React from 'react';
import List from '@material-ui/core/List';
import { createStyles, withStyles } from '@material-ui/core/styles';
import TreeNode from './TreeNode';

const times = (nbChildren, fn) =>
Array.from({ length: nbChildren }, (_, key) => fn(key));

const DummyRecord = {};

const TreeListLoading = ({ nbFakeLines = 5, ...props }) => (
<List dense disablePadding {...sanitizeRestProps(props)}>
{times(nbFakeLines, key => (
// @ts-ignore
<TreeNode key={key} record={DummyRecord} {...props}>
<Placeholder />
</TreeNode>
))}
</List>
);

export default TreeListLoading;

const sanitizeRestProps = ({
basePath,
children,
classes,
closeNode,
data,
expandNode,
hasCreate,
hasEdit,
hasList,
hasShow,
history,
loading,
locale,
location,
match,
nodes,
options,
parentSource,
permissions,
positionSource,
resource,
toggleNode,
version,
...rest
}: any) => rest;

const RawPlaceholder = ({ classes }) => (
<div className={classes.root}>&nbsp;</div>
);

const styles = theme =>
createStyles({
root: {
backgroundColor: theme.palette.grey[300],
width: 256,
},
});

const Placeholder = withStyles(styles)(RawPlaceholder);
44 changes: 44 additions & 0 deletions packages/ra-tree-ui-materialui/src/TreeListToolbar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import React from 'react';
import PropTypes from 'prop-types';
import Toolbar from '@material-ui/core/Toolbar';
import { withStyles, createStyles } from '@material-ui/core/styles';

const styles = createStyles({
toolbar: {
justifyContent: 'space-between',
},
});

const TreeListToolbar = ({
classes,
filters,
permanentFilter, // set in the List component by the developer
actions,
exporter,
...rest
}) => (
<Toolbar className={classes.toolbar}>
<span />
{actions &&
React.cloneElement(actions, {
...rest,
className: classes.actions,
exporter,
permanentFilter,
...actions.props,
})}
</Toolbar>
);

TreeListToolbar.propTypes = {
classes: PropTypes.object,
permanentFilter: PropTypes.object,
actions: PropTypes.element,
exporter: PropTypes.oneOfType([PropTypes.func, PropTypes.bool]),
};

TreeListToolbar.defaultProps = {
classes: {},
};

export default withStyles(styles)(TreeListToolbar);
4 changes: 2 additions & 2 deletions packages/ra-tree-ui-materialui/src/TreeNode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ class TreeNode extends Component<Props & WithStyles<typeof styles>> {
<div className={classes.icon}>
<CircularProgress size="1em" />
</div>
) : nodes.length === 0 ? (
) : !nodes || nodes.length === 0 ? (
<div className={classes.icon}>
<KeyboardArrowRight />
</div>
Expand Down Expand Up @@ -183,7 +183,7 @@ const styles = (theme: Theme): StyleRules => ({
container: {
alignItems: 'center',
display: 'inline-flex',
justifyContent: 'baseline',
justifyContent: 'center',
verticalAlign: 'middle',
},
content: {
Expand Down
3 changes: 2 additions & 1 deletion packages/ra-tree-ui-materialui/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Tree from './Tree';
import TreeNode from './TreeNode';
import TreeList from './TreeList';
export { TreeNode, Tree, TreeList };
import TreeListLoading from './TreeListLoading';
export { TreeNode, Tree, TreeList, TreeListLoading };
export * from 'ra-tree-core';

0 comments on commit 2e211cd

Please sign in to comment.