mirror of
https://github.com/alice-lg/alice-lg.git
synced 2024-05-11 05:55:03 +00:00
280 lines
7.8 KiB
JavaScript
280 lines
7.8 KiB
JavaScript
|
|
import React from 'react'
|
|
import {connect} from 'react-redux'
|
|
|
|
import {Link} from 'react-router'
|
|
|
|
import RoutesTable from './table'
|
|
import {RoutesPaginator,
|
|
RoutesPaginationInfo} from './pagination'
|
|
|
|
import {fetchRoutesReceived,
|
|
fetchRoutesFiltered,
|
|
fetchRoutesNotExported} from './actions'
|
|
|
|
import {makeLinkProps} from './urls'
|
|
|
|
// Constants
|
|
import {ROUTES_RECEIVED,
|
|
ROUTES_FILTERED,
|
|
ROUTES_NOT_EXPORTED} from './actions';
|
|
|
|
|
|
export const RoutesHeader = (props) => {
|
|
const type = props.type;
|
|
const rtype = {
|
|
[ROUTES_RECEIVED]: "accepted",
|
|
[ROUTES_FILTERED]: "filtered",
|
|
[ROUTES_NOT_EXPORTED]: "not exported"
|
|
}[type];
|
|
let stype = type;
|
|
if (stype == ROUTES_NOT_EXPORTED) {
|
|
stype = 'not-exported'; // *sigh*
|
|
}
|
|
const cls = `card-header card-header-routes ${stype}`;
|
|
return (<p className={cls}>Routes {rtype}</p>);
|
|
};
|
|
|
|
/*
|
|
* Render a RoutesView:
|
|
* The routes view is a composit of:
|
|
* - A header
|
|
* - The Routes Table
|
|
* - A Paginator
|
|
*/
|
|
|
|
class RoutesView extends React.Component {
|
|
|
|
constructor(props) {
|
|
super(props);
|
|
}
|
|
|
|
dispatchFetchRoutes() {
|
|
const type = this.props.type;
|
|
|
|
// Depending on the component's configuration, dispatch
|
|
// routes fetching
|
|
const fetchRoutes = {
|
|
[ROUTES_RECEIVED]: fetchRoutesReceived,
|
|
[ROUTES_FILTERED]: fetchRoutesFiltered,
|
|
[ROUTES_NOT_EXPORTED]: fetchRoutesNotExported,
|
|
}[type];
|
|
|
|
// Gather required params
|
|
const params = this.props.routes[type];
|
|
const rsId = this.props.routeserverId;
|
|
const pId = this.props.protocolId;
|
|
const query = this.props.filterQuery;
|
|
|
|
// Make request
|
|
|
|
// Handle special case, when on demand loading is enabled,
|
|
// we defer this dispatch, until an user interaction.
|
|
if (!params.loadRoutes) {
|
|
return; // We are done here.
|
|
}
|
|
|
|
// Otherwise, just dispatch the request:
|
|
this.props.dispatch(fetchRoutes(rsId, pId, params.page, query));
|
|
}
|
|
|
|
/*
|
|
* Diff props and this.props to check if we need to
|
|
* dispatch another fetch routes
|
|
*/
|
|
routesNeedFetch(props) {
|
|
const type = this.props.type;
|
|
const nextParams = this.props.routes[type];
|
|
const params = props.routes[type]; // Previous props
|
|
|
|
if (this.props.filterQuery != props.filterQuery || // Pagination
|
|
params.page != nextParams.page || // Query
|
|
params.loadRoutes != nextParams.loadRoutes || // Defered loading
|
|
props.protocolId != this.props.protocolId // Switch related peers
|
|
) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
componentDidMount() {
|
|
this.dispatchFetchRoutes();
|
|
}
|
|
|
|
componentDidUpdate(prevProps) {
|
|
const scrollAnchor = this.refs.scrollAnchor;
|
|
|
|
if (this.routesNeedFetch(prevProps)) {
|
|
this.dispatchFetchRoutes();
|
|
|
|
if (scrollAnchor) {
|
|
scrollAnchor.scrollIntoView({
|
|
behaviour: "smooth",
|
|
block: "start",
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
render() {
|
|
const type = this.props.type;
|
|
const state = this.props.routes[type];
|
|
const queryParam = {
|
|
[ROUTES_RECEIVED]: "pr",
|
|
[ROUTES_FILTERED]: "pf",
|
|
[ROUTES_NOT_EXPORTED]: "pn",
|
|
}[type];
|
|
const name = {
|
|
[ROUTES_RECEIVED]: "routes-received",
|
|
[ROUTES_FILTERED]: "routes-filtered",
|
|
[ROUTES_NOT_EXPORTED]: "routes-not-exported",
|
|
}[type];
|
|
|
|
if (!state.loadRoutes) {
|
|
// In case it was not yet requested, render a trigger
|
|
// and defer routesFetching until a user interaction has
|
|
// occured.
|
|
return this.renderLoadTrigger();
|
|
}
|
|
|
|
if (state.loading) {
|
|
return null;
|
|
}
|
|
|
|
if (state.totalResults == 0) {
|
|
return null;
|
|
}
|
|
|
|
// Render the routes card
|
|
return (
|
|
<div className={`card routes-view ${name}`}>
|
|
<div className="row">
|
|
<div className="col-md-6 routes-header-container">
|
|
<a name={name} id={name} ref="scrollAnchor">
|
|
<RoutesHeader type={type} />
|
|
</a>
|
|
</div>
|
|
<div className="col-md-6">
|
|
<RoutesPaginationInfo page={state.page}
|
|
pageSize={state.pageSize}
|
|
totalPages={state.totalPages}
|
|
totalResults={state.totalResults} />
|
|
</div>
|
|
</div>
|
|
<RoutesTable type={type}
|
|
routes={state.routes}
|
|
routeserverId={this.props.routeserverId} />
|
|
<center>
|
|
<RoutesPaginator page={state.page} totalPages={state.totalPages}
|
|
queryParam={queryParam}
|
|
anchor={name} />
|
|
</center>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
renderLoadTrigger() {
|
|
const type = this.props.type;
|
|
const state = this.props.routes[type];
|
|
const name = {
|
|
[ROUTES_RECEIVED]: "routes-received",
|
|
[ROUTES_FILTERED]: "routes-filtered",
|
|
[ROUTES_NOT_EXPORTED]: "routes-not-exported",
|
|
}[type];
|
|
|
|
|
|
// This is an artificial delay, to make the user wait until
|
|
// filtered and recieved routes are fetched
|
|
if (!state.otherLoaded) {
|
|
return null;
|
|
}
|
|
|
|
const linkProps = makeLinkProps({
|
|
loadNotExported: true,
|
|
|
|
anchor: "routes-not-exported",
|
|
page: this.props.routes.notExported.page,
|
|
|
|
pageReceived: this.props.routes.received.page,
|
|
pageFiltered: this.props.routes.filtered.page,
|
|
pageNotExported: this.props.routes.notExported.page,
|
|
|
|
routing: this.props.routing
|
|
});
|
|
|
|
return (
|
|
<div className={`card routes-view ${name}`}>
|
|
<div className="row">
|
|
<div className="col-md-6">
|
|
<a name={name} id={name} ref="scrollAnchor">
|
|
<RoutesHeader type={type} />
|
|
</a>
|
|
</div>
|
|
</div>
|
|
<p className="help">
|
|
Due to the high amount of routes not exported,
|
|
they are only fetched on demand.
|
|
</p>
|
|
|
|
<Link to={linkProps} className="btn btn-block btn-danger">
|
|
Load Routes Not Exported
|
|
</Link>
|
|
</div>
|
|
);
|
|
}
|
|
}
|
|
|
|
export default connect(
|
|
(state) => {
|
|
const received = {
|
|
routes: state.routes.received,
|
|
requested: state.routes.receivedRequested,
|
|
loading: state.routes.receivedLoading,
|
|
page: state.routes.receivedPage,
|
|
pageSize: state.routes.receivedPageSize,
|
|
totalPages: state.routes.receivedTotalPages,
|
|
totalResults: state.routes.receivedTotalResults,
|
|
loadRoutes: true,
|
|
};
|
|
const filtered = {
|
|
routes: state.routes.filtered,
|
|
loading: state.routes.filteredLoading,
|
|
requested: state.routes.filteredRequested,
|
|
page: state.routes.filteredPage,
|
|
pageSize: state.routes.filteredPageSize,
|
|
totalPages: state.routes.filteredTotalPages,
|
|
totalResults: state.routes.filteredTotalResults,
|
|
loadRoutes: true,
|
|
};
|
|
const notExported = {
|
|
routes: state.routes.notExported,
|
|
requested: state.routes.notExportedRequested,
|
|
loading: state.routes.notExportedLoading,
|
|
page: state.routes.notExportedPage,
|
|
pageSize: state.routes.notExportedPageSize,
|
|
totalPages: state.routes.notExportedTotalPages,
|
|
totalResults: state.routes.notExportedTotalResults,
|
|
|
|
loadRoutes: state.routes.loadNotExported ||
|
|
!state.config.noexport_load_on_demand,
|
|
|
|
otherLoaded: state.routes.receivedRequested &&
|
|
!state.routes.receivedLoading &&
|
|
state.routes.filteredRequested &&
|
|
!state.routes.filteredLoading
|
|
};
|
|
return({
|
|
filterQuery: state.routes.filterQuery,
|
|
routes: {
|
|
[ROUTES_RECEIVED]: received,
|
|
[ROUTES_FILTERED]: filtered,
|
|
[ROUTES_NOT_EXPORTED]: notExported
|
|
},
|
|
routing: state.routing.locationBeforeTransitions
|
|
});
|
|
}
|
|
)(RoutesView);
|
|
|