Merge pull request #132 from coreui/dev-lazy-loading

v2.1.1
This commit is contained in:
xidedix 2018-11-20 23:16:02 +01:00 committed by GitHub
commit 7489ecb164
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 179 additions and 252 deletions

View File

@ -1,5 +1,19 @@
## [CoreUI](https://coreui.io/) for [react](./REACT.md) changelog
##### `v2.1.1`
- refactor(App.js): code splitting with `react-loadable` (waiting for release of `react-router-dom`)
- refactor(routes.js): code splitting with `React.lazy`, remove `react-loadable`
- refactor(DefaultLayout): code splitting with `React.lazy` Aside, Footer, Header, routes
- refactor(Dashboard): tweak lazy and Suspense for Widget03
- refactor(Login): add router link to `Register` button
- refactor(Register): add margins to social-media buttons
- chore: disable eslint warning for href="#" attribute
- chore: update `@coreui/coreui` to `^2.1.1`
- chore: update `enzyme-adapter-react-16` to `1.7.0`
- chore: update `react` to `16.6.3`
- chore: update `react-dom` to `16.6.3`
- chore: update `react-test-renderer` to `16.6.3`
##### `v2.1.0`
- feat(SidebarNav): navLink `attributes` - optional JS object with valid JS API naming:
- valid attributes: `rel`, `target`, `hidden`, `disabled`, etc...

View File

@ -1,6 +1,6 @@
{
"name": "@coreui/coreui-free-react-admin-template",
"version": "2.1.0",
"version": "2.1.1",
"description": "CoreUI React Open Source Bootstrap 4 Admin Template",
"author": "Łukasz Holeczek",
"homepage": "https://coreui.io",
@ -12,7 +12,7 @@
"url": "git@github.com:coreui/coreui-free-react-admin-template.git"
},
"dependencies": {
"@coreui/coreui": "^2.1.0",
"@coreui/coreui": "^2.1.1",
"@coreui/coreui-plugin-chartjs-custom-tooltips": "^1.2.0",
"@coreui/icons": "0.3.0",
"@coreui/react": "^2.1.0",
@ -21,19 +21,19 @@
"classnames": "^2.2.6",
"core-js": "^2.5.7",
"enzyme": "^3.7.0",
"enzyme-adapter-react-16": "^1.6.0",
"enzyme-adapter-react-16": "^1.7.0",
"flag-icon-css": "^3.2.1",
"font-awesome": "^4.7.0",
"node-sass": "^4.10.0",
"prop-types": "^15.6.2",
"react": "^16.6.1",
"react": "^16.6.3",
"react-app-polyfill": "^0.1.3",
"react-chartjs-2": "^2.7.2",
"react-dom": "^16.6.1",
"react-dom": "^16.6.3",
"react-loadable": "^5.5.0",
"react-router-config": "^4.4.0-beta.6",
"react-router-dom": "^4.3.1",
"react-test-renderer": "^16.6.1",
"react-test-renderer": "^16.6.3",
"reactstrap": "^6.5.0",
"simple-line-icons": "^2.4.1"
},

View File

@ -1,25 +1,50 @@
import React, { Component } from 'react';
import { HashRouter, Route, Switch } from 'react-router-dom';
// import { renderRoutes } from 'react-router-config';
import Loadable from 'react-loadable';
import './App.scss';
// Containers
import { DefaultLayout } from './containers';
// Pages
import { Login, Page404, Page500, Register } from './views/Pages';
const loading = () => <div className="animated fadeIn pt-3 text-center">Loading...</div>;
// import { renderRoutes } from 'react-router-config';
// Containers
const DefaultLayout = Loadable({
loader: () => import('./containers/DefaultLayout'),
loading
});
// Pages
const Login = Loadable({
loader: () => import('./views/Pages/Login'),
loading
});
const Register = Loadable({
loader: () => import('./views/Pages/Register'),
loading
});
const Page404 = Loadable({
loader: () => import('./views/Pages/Page404'),
loading
});
const Page500 = Loadable({
loader: () => import('./views/Pages/Page500'),
loading
});
class App extends Component {
render() {
return (
<HashRouter>
<Switch>
<Route exact path="/login" name="Login Page" component={Login} />
<Route exact path="/register" name="Register Page" component={Register} />
<Route exact path="/404" name="Page 404" component={Page404} />
<Route exact path="/500" name="Page 500" component={Page500} />
<Route path="/" name="Home" component={DefaultLayout} />
</Switch>
<Switch>
<Route exact path="/login" name="Login Page" component={Login} />
<Route exact path="/register" name="Register Page" component={Register} />
<Route exact path="/404" name="Page 404" component={Page404} />
<Route exact path="/500" name="Page 500" component={Page500} />
<Route path="/" name="Home" component={DefaultLayout} />
</Switch>
</HashRouter>
);
}

View File

@ -1,4 +1,5 @@
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import { Badge, DropdownItem, DropdownMenu, DropdownToggle, Nav, NavItem, NavLink } from 'reactstrap';
import PropTypes from 'prop-types';
@ -32,7 +33,7 @@ class DefaultHeader extends Component {
<NavLink href="/">Dashboard</NavLink>
</NavItem>
<NavItem className="px-3">
<NavLink href="#/users">Users</NavLink>
<Link to="/users">Users</Link>
</NavItem>
<NavItem className="px-3">
<NavLink href="#">Settings</NavLink>
@ -50,7 +51,7 @@ class DefaultHeader extends Component {
</NavItem>
<AppHeaderDropdown direction="down">
<DropdownToggle nav>
<img src={'assets/img/avatars/6.jpg'} className="img-avatar" alt="admin@bootstrapmaster.com" />
<img src={'../../assets/img/avatars/6.jpg'} className="img-avatar" alt="admin@bootstrapmaster.com" />
</DropdownToggle>
<DropdownMenu right style={{ right: 'auto' }}>
<DropdownItem header tag="div" className="text-center"><strong>Account</strong></DropdownItem>
@ -65,7 +66,7 @@ class DefaultHeader extends Component {
<DropdownItem><i className="fa fa-file"></i> Projects<Badge color="primary">42</Badge></DropdownItem>
<DropdownItem divider />
<DropdownItem><i className="fa fa-shield"></i> Lock Account</DropdownItem>
<DropdownItem><i className="fa fa-lock"></i> Logout</DropdownItem>
<DropdownItem onClick={e => this.props.onLogout(e)}><i className="fa fa-lock"></i> Logout</DropdownItem>
</DropdownMenu>
</AppHeaderDropdown>
</Nav>

View File

@ -1,4 +1,4 @@
import React, { Component } from 'react';
import React, { Component, Suspense } from 'react';
import { Redirect, Route, Switch } from 'react-router-dom';
import { Container } from 'reactstrap';
@ -18,46 +18,70 @@ import {
import navigation from '../../_nav';
// routes config
import routes from '../../routes';
import DefaultAside from './DefaultAside';
import DefaultFooter from './DefaultFooter';
import DefaultHeader from './DefaultHeader';
const DefaultAside = React.lazy(() => import('./DefaultAside'));
const DefaultFooter = React.lazy(() => import('./DefaultFooter'));
const DefaultHeader = React.lazy(() => import('./DefaultHeader'));
class DefaultLayout extends Component {
loading = () => <div className="animated fadeIn pt-1 text-center">Loading...</div>
signOut(e) {
e.preventDefault()
this.props.history.push('/login')
}
render() {
return (
<div className="app">
<AppHeader fixed>
<DefaultHeader />
<Suspense fallback={this.loading()}>
<DefaultHeader onLogout={e=>this.signOut(e)}/>
</Suspense>
</AppHeader>
<div className="app-body">
<AppSidebar fixed display="lg">
<AppSidebarHeader />
<AppSidebarForm />
<Suspense>
<AppSidebarNav navConfig={navigation} {...this.props} />
</Suspense>
<AppSidebarFooter />
<AppSidebarMinimizer />
</AppSidebar>
<main className="main">
<AppBreadcrumb appRoutes={routes}/>
<Container fluid>
<Switch>
{routes.map((route, idx) => {
return route.component ? (<Route key={idx} path={route.path} exact={route.exact} name={route.name} render={props => (
<route.component {...props} />
)} />)
: (null);
},
)}
<Redirect from="/" to="/dashboard" />
</Switch>
<Suspense fallback={this.loading()}>
<Switch>
{routes.map((route, idx) => {
return route.component ? (
<Route
key={idx}
path={route.path}
exact={route.exact}
name={route.name}
render={props => (
<route.component {...props} />
)} />
) : (null);
})}
<Redirect from="/" to="/dashboard" />
</Switch>
</Suspense>
</Container>
</main>
<AppAside fixed>
<DefaultAside />
<Suspense fallback={this.loading()}>
<DefaultAside />
</Suspense>
</AppAside>
</div>
<AppFooter>
<DefaultFooter />
<Suspense fallback={this.loading()}>
<DefaultFooter />
</Suspense>
</AppFooter>
</div>
);

View File

@ -1,188 +1,41 @@
import React from 'react';
import Loadable from 'react-loadable'
import DefaultLayout from './containers/DefaultLayout';
function Loading() {
return <div>Loading...</div>;
}
const Breadcrumbs = Loadable({
loader: () => import('./views/Base/Breadcrumbs'),
loading: Loading,
});
const Cards = Loadable({
loader: () => import('./views/Base/Cards'),
loading: Loading,
});
const Carousels = Loadable({
loader: () => import('./views/Base/Carousels'),
loading: Loading,
});
const Collapses = Loadable({
loader: () => import('./views/Base/Collapses'),
loading: Loading,
});
const Dropdowns = Loadable({
loader: () => import('./views/Base/Dropdowns'),
loading: Loading,
});
const Forms = Loadable({
loader: () => import('./views/Base/Forms'),
loading: Loading,
});
const Jumbotrons = Loadable({
loader: () => import('./views/Base/Jumbotrons'),
loading: Loading,
});
const ListGroups = Loadable({
loader: () => import('./views/Base/ListGroups'),
loading: Loading,
});
const Navbars = Loadable({
loader: () => import('./views/Base/Navbars'),
loading: Loading,
});
const Navs = Loadable({
loader: () => import('./views/Base/Navs'),
loading: Loading,
});
const Paginations = Loadable({
loader: () => import('./views/Base/Paginations'),
loading: Loading,
});
const Popovers = Loadable({
loader: () => import('./views/Base/Popovers'),
loading: Loading,
});
const ProgressBar = Loadable({
loader: () => import('./views/Base/ProgressBar'),
loading: Loading,
});
const Switches = Loadable({
loader: () => import('./views/Base/Switches'),
loading: Loading,
});
const Tables = Loadable({
loader: () => import('./views/Base/Tables'),
loading: Loading,
});
const Tabs = Loadable({
loader: () => import('./views/Base/Tabs'),
loading: Loading,
});
const Tooltips = Loadable({
loader: () => import('./views/Base/Tooltips'),
loading: Loading,
});
const BrandButtons = Loadable({
loader: () => import('./views/Buttons/BrandButtons'),
loading: Loading,
});
const ButtonDropdowns = Loadable({
loader: () => import('./views/Buttons/ButtonDropdowns'),
loading: Loading,
});
const ButtonGroups = Loadable({
loader: () => import('./views/Buttons/ButtonGroups'),
loading: Loading,
});
const Buttons = Loadable({
loader: () => import('./views/Buttons/Buttons'),
loading: Loading,
});
const Charts = Loadable({
loader: () => import('./views/Charts'),
loading: Loading,
});
const Dashboard = Loadable({
loader: () => import('./views/Dashboard'),
loading: Loading,
});
const CoreUIIcons = Loadable({
loader: () => import('./views/Icons/CoreUIIcons'),
loading: Loading,
});
const Flags = Loadable({
loader: () => import('./views/Icons/Flags'),
loading: Loading,
});
const FontAwesome = Loadable({
loader: () => import('./views/Icons/FontAwesome'),
loading: Loading,
});
const SimpleLineIcons = Loadable({
loader: () => import('./views/Icons/SimpleLineIcons'),
loading: Loading,
});
const Alerts = Loadable({
loader: () => import('./views/Notifications/Alerts'),
loading: Loading,
});
const Badges = Loadable({
loader: () => import('./views/Notifications/Badges'),
loading: Loading,
});
const Modals = Loadable({
loader: () => import('./views/Notifications/Modals'),
loading: Loading,
});
const Colors = Loadable({
loader: () => import('./views/Theme/Colors'),
loading: Loading,
});
const Typography = Loadable({
loader: () => import('./views/Theme/Typography'),
loading: Loading,
});
const Widgets = Loadable({
loader: () => import('./views/Widgets/Widgets'),
loading: Loading,
});
const Users = Loadable({
loader: () => import('./views/Users/Users'),
loading: Loading,
});
const User = Loadable({
loader: () => import('./views/Users/User'),
loading: Loading,
});
const Breadcrumbs = React.lazy(() => import('./views/Base/Breadcrumbs'));
const Cards = React.lazy(() => import('./views/Base/Cards'));
const Carousels = React.lazy(() => import('./views/Base/Carousels'));
const Collapses = React.lazy(() => import('./views/Base/Collapses'));
const Dropdowns = React.lazy(() => import('./views/Base/Dropdowns'));
const Forms = React.lazy(() => import('./views/Base/Forms'));
const Jumbotrons = React.lazy(() => import('./views/Base/Jumbotrons'));
const ListGroups = React.lazy(() => import('./views/Base/ListGroups'));
const Navbars = React.lazy(() => import('./views/Base/Navbars'));
const Navs = React.lazy(() => import('./views/Base/Navs'));
const Paginations = React.lazy(() => import('./views/Base/Paginations'));
const Popovers = React.lazy(() => import('./views/Base/Popovers'));
const ProgressBar = React.lazy(() => import('./views/Base/ProgressBar'));
const Switches = React.lazy(() => import('./views/Base/Switches'));
const Tables = React.lazy(() => import('./views/Base/Tables'));
const Tabs = React.lazy(() => import('./views/Base/Tabs'));
const Tooltips = React.lazy(() => import('./views/Base/Tooltips'));
const BrandButtons = React.lazy(() => import('./views/Buttons/BrandButtons'));
const ButtonDropdowns = React.lazy(() => import('./views/Buttons/ButtonDropdowns'));
const ButtonGroups = React.lazy(() => import('./views/Buttons/ButtonGroups'));
const Buttons = React.lazy(() => import('./views/Buttons/Buttons'));
const Charts = React.lazy(() => import('./views/Charts'));
const Dashboard = React.lazy(() => import('./views/Dashboard'));
const CoreUIIcons = React.lazy(() => import('./views/Icons/CoreUIIcons'));
const Flags = React.lazy(() => import('./views/Icons/Flags'));
const FontAwesome = React.lazy(() => import('./views/Icons/FontAwesome'));
const SimpleLineIcons = React.lazy(() => import('./views/Icons/SimpleLineIcons'));
const Alerts = React.lazy(() => import('./views/Notifications/Alerts'));
const Badges = React.lazy(() => import('./views/Notifications/Badges'));
const Modals = React.lazy(() => import('./views/Notifications/Modals'));
const Colors = React.lazy(() => import('./views/Theme/Colors'));
const Typography = React.lazy(() => import('./views/Theme/Typography'));
const Widgets = React.lazy(() => import('./views/Widgets/Widgets'));
const Users = React.lazy(() => import('./views/Users/Users'));
const User = React.lazy(() => import('./views/Users/User'));
// https://github.com/ReactTraining/react-router/tree/master/packages/react-router-config
const routes = [

View File

@ -21,11 +21,14 @@ class Breadcrumbs extends Component {
<BreadcrumbItem active>Home</BreadcrumbItem>
</Breadcrumb>
<Breadcrumb>
{/*eslint-disable-next-line*/}
<BreadcrumbItem><a href="#">Home</a></BreadcrumbItem>
<BreadcrumbItem active>Library</BreadcrumbItem>
</Breadcrumb>
<Breadcrumb>
{/*eslint-disable-next-line*/}
<BreadcrumbItem><a href="#">Home</a></BreadcrumbItem>
{/* eslint-disable-next-line*/}
<BreadcrumbItem><a href="#">Library</a></BreadcrumbItem>
<BreadcrumbItem active>Data</BreadcrumbItem>
</Breadcrumb>

View File

@ -388,8 +388,11 @@ class Cards extends Component {
<CardHeader>
Card actions
<div className="card-header-actions">
{/*eslint-disable-next-line*/}
<a href="#" className="card-header-action btn btn-setting"><i className="icon-settings"></i></a>
{/*eslint-disable-next-line*/}
<a className="card-header-action btn btn-minimize" data-target="#collapseExample" onClick={this.toggle}><i className="icon-arrow-up"></i></a>
{/*eslint-disable-next-line*/}
<a className="card-header-action btn btn-close" onClick={this.toggleFade}><i className="icon-close"></i></a>
</div>
</CardHeader>

View File

@ -82,6 +82,7 @@ class Tooltips extends Component {
</div>
</CardHeader>
<CardBody>
{/*eslint-disable-next-line*/}
<p>Somewhere in here is a <a href="#" id="TooltipExample">tooltip</a>.</p>
<Tooltip placement="right" isOpen={this.state.tooltipOpen[0]} target="TooltipExample" toggle={() => {this.toggle(0);}}>
Hello world!
@ -94,6 +95,7 @@ class Tooltips extends Component {
<small> disable autohide</small>
</CardHeader>
<CardBody>
{/*eslint-disable-next-line*/}
<p>Sometimes you need to allow users to select text within a <a href="#" id="DisabledAutoHideExample">tooltip</a>.</p>
<Tooltip placement="top" isOpen={this.state.tooltipOpen[1]} autohide={false} target="DisabledAutoHideExample" toggle={() => {this.toggle(1);}}>
Try to select this text!
@ -117,6 +119,7 @@ class Tooltips extends Component {
<small> uncontrolled</small>
</CardHeader>
<CardBody>
{/*eslint-disable-next-line*/}
<p>Somewhere in here is a <a href="#" id="UncontrolledTooltipExample">tooltip</a>.</p>
<UncontrolledTooltip placement="right" target="UncontrolledTooltipExample">
Hello world!
@ -128,4 +131,4 @@ class Tooltips extends Component {
}
}
export default Tooltips;
export default Tooltips;

View File

@ -23,9 +23,7 @@ import {
import { CustomTooltips } from '@coreui/coreui-plugin-chartjs-custom-tooltips';
import { getStyle, hexToRgba } from '@coreui/coreui/dist/js/coreui-utilities'
// import Widget03 from '../../views/Widgets/Widget03'
const Widget03 = lazy(() => import('../../views/Widgets/Widget03'));
const Loading = () => <div>Loading...</div>
const brandPrimary = getStyle('--primary')
const brandSuccess = getStyle('--success')
@ -479,6 +477,8 @@ class Dashboard extends Component {
});
}
loading = () => <div className="animated fadeIn pt-1 text-center">Loading...</div>
render() {
return (
@ -640,7 +640,7 @@ class Dashboard extends Component {
<Row>
<Col xs="6" sm="6" lg="3">
<Suspense fallback={Loading()}>
<Suspense fallback={this.loading()}>
<Widget03 dataBox={() => ({ variant: 'facebook', friends: '89k', feeds: '459' })} >
<div className="chart-wrapper">
<Line data={makeSocialBoxData(0)} options={socialChartOpts} height={90} />
@ -650,7 +650,7 @@ class Dashboard extends Component {
</Col>
<Col xs="6" sm="6" lg="3">
<Suspense fallback={Loading()}>
<Suspense fallback={this.loading()}>
<Widget03 dataBox={() => ({ variant: 'twitter', followers: '973k', tweets: '1.792' })} >
<div className="chart-wrapper">
<Line data={makeSocialBoxData(1)} options={socialChartOpts} height={90} />
@ -660,7 +660,7 @@ class Dashboard extends Component {
</Col>
<Col xs="6" sm="6" lg="3">
<Suspense fallback={Loading()}>
<Suspense fallback={this.loading()}>
<Widget03 dataBox={() => ({ variant: 'linkedin', contacts: '500+', feeds: '292' })} >
<div className="chart-wrapper">
<Line data={makeSocialBoxData(2)} options={socialChartOpts} height={90} />
@ -670,24 +670,13 @@ class Dashboard extends Component {
</Col>
<Col xs="6" sm="6" lg="3">
<div className="brand-card">
<div className="brand-card-header bg-google-plus">
<i className="fa fa-google-plus"></i>
<Suspense fallback={this.loading()}>
<Widget03 dataBox={() => ({ variant: 'google-plus', followers: '894', circles: '92' })} >
<div className="chart-wrapper">
<Line data={makeSocialBoxData(3)} options={socialChartOpts} height={90} />
</div>
</div>
<div className="brand-card-body">
<div>
<div className="text-value">894</div>
<div className="text-uppercase text-muted small">followers</div>
</div>
<div>
<div className="text-value">92</div>
<div className="text-uppercase text-muted small">circles</div>
</div>
</div>
</div>
</Widget03>
</Suspense>
</Col>
</Row>

View File

@ -66,27 +66,35 @@ class Alerts extends Component {
</CardHeader>
<CardBody>
<Alert color="primary">
{/*eslint-disable-next-line*/}
This is a primary alert with <a href="#" className="alert-link">an example link</a>. Give it a click if you like.
</Alert>
<Alert color="secondary">
{/*eslint-disable-next-line*/}
This is a secondary alert with <a href="#" className="alert-link">an example link</a>. Give it a click if you like.
</Alert>
<Alert color="success">
{/*eslint-disable-next-line*/}
This is a success alert with <a href="#" className="alert-link">an example link</a>. Give it a click if you like.
</Alert>
<Alert color="danger">
{/*eslint-disable-next-line*/}
This is a danger alert with <a href="#" className="alert-link">an example link</a>. Give it a click if you like.
</Alert>
<Alert color="warning">
{/*eslint-disable-next-line*/}
This is a warning alert with <a href="#" className="alert-link">an example link</a>. Give it a click if you like.
</Alert>
<Alert color="info">
{/*eslint-disable-next-line*/}
This is a info alert with <a href="#" className="alert-link">an example link</a>. Give it a click if you like.
</Alert>
<Alert color="light">
{/*eslint-disable-next-line*/}
This is a light alert with <a href="#" className="alert-link">an example link</a>. Give it a click if you like.
</Alert>
<Alert color="dark">
{/*eslint-disable-next-line*/}
This is a dark alert with <a href="#" className="alert-link">an example link</a>. Give it a click if you like.
</Alert>
</CardBody>

View File

@ -1,4 +1,5 @@
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import { Button, Card, CardBody, CardGroup, Col, Container, Form, Input, InputGroup, InputGroupAddon, InputGroupText, Row } from 'reactstrap';
class Login extends Component {
@ -41,13 +42,15 @@ class Login extends Component {
</Form>
</CardBody>
</Card>
<Card className="text-white bg-primary py-5 d-md-down-none" style={{ width: 44 + '%' }}>
<Card className="text-white bg-primary py-5 d-md-down-none" style={{ width: '44%' }}>
<CardBody className="text-center">
<div>
<h2>Sign up</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut
labore et dolore magna aliqua.</p>
<Button color="primary" className="mt-3" active>Register Now!</Button>
<Link to="/register">
<Button color="primary" className="mt-3" active tabIndex={-1}>Register Now!</Button>
</Link>
</div>
</CardBody>
</Card>

View File

@ -7,7 +7,7 @@ class Register extends Component {
<div className="app flex-row align-items-center">
<Container>
<Row className="justify-content-center">
<Col md="6">
<Col md="9" lg="7" xl="6">
<Card className="mx-4">
<CardBody className="p-4">
<Form>
@ -49,10 +49,10 @@ class Register extends Component {
<CardFooter className="p-4">
<Row>
<Col xs="12" sm="6">
<Button className="btn-facebook" block><span>facebook</span></Button>
<Button className="btn-facebook mb-1" block><span>facebook</span></Button>
</Col>
<Col xs="12" sm="6">
<Button className="btn-twitter" block><span>twitter</span></Button>
<Button className="btn-twitter mb-1" block><span>twitter</span></Button>
</Col>
</Row>
</CardFooter>

View File

@ -1,11 +1,12 @@
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import { Badge, Card, CardBody, CardHeader, Col, Row, Table } from 'reactstrap';
import usersData from './UsersData'
function UserRow(props) {
const user = props.user
const userLink = `#/users/${user.id}`
const userLink = `/users/${user.id}`
const getBadge = (status) => {
return status === 'Active' ? 'success' :
@ -17,11 +18,11 @@ function UserRow(props) {
return (
<tr key={user.id.toString()}>
<th scope="row"><a href={userLink}>{user.id}</a></th>
<td><a href={userLink}>{user.name}</a></td>
<td>{user.registered}</td>
<td>{user.role}</td>
<td><Badge href={userLink} color={getBadge(user.status)}>{user.status}</Badge></td>
<th scope="row"><Link to={userLink}>{user.id}</Link></th>
<td><Link to={userLink}>{user.name}</Link></td>
<td>{user.registered}</td>
<td>{user.role}</td>
<td><Link to={userLink}><Badge color={getBadge(user.status)}>{user.status}</Badge></Link></td>
</tr>
)
}