Skip to content

Commit

Permalink
Add pagination to abilities logs
Browse files Browse the repository at this point in the history
  • Loading branch information
javierbrea committed Feb 25, 2019
1 parent ef7ed43 commit 302bcd6
Show file tree
Hide file tree
Showing 13 changed files with 119 additions and 102 deletions.
2 changes: 1 addition & 1 deletion mocks/features/fixtures/logs/get.js
Expand Up @@ -77,7 +77,7 @@ const getLogsSuccess = {
};

const countLogsSuccess = {
url: "/api/logs/count",
url: "/api/logs/stats",
method: "GET",
response: {
status: 200,
Expand Down
2 changes: 1 addition & 1 deletion src/components/logs-list/LogsList.js
Expand Up @@ -40,7 +40,7 @@ export const LogsList = ({ logs = [], logsLoading, showPlaceHolders }) => {
}
return (
<React.Fragment>
{logs.length < 1 && !logsLoading ? <NoResults /> : null}
{!showPlaceHolders && logs.length < 1 && !logsLoading ? <NoResults /> : null}
{logs.map(log => (
<Log
key={log._id}
Expand Down
3 changes: 0 additions & 3 deletions src/components/paginated-list/index.js

This file was deleted.

Expand Up @@ -4,7 +4,7 @@ import InfiniteScroll from "react-infinite-scroller";

import { ScrollContext } from "src/contexts/ScrollContext";

export class PaginatedList extends Component {
export class ScrollPaginatedList extends Component {
constructor(props) {
super(props);
this.state = {
Expand All @@ -20,21 +20,33 @@ export class PaginatedList extends Component {
}

hasMore() {
return this.state.currentPage * this.props.pageSize < this.props.itemsCount.total;
return this.state.currentPage * this.props.pageSize < this.props.itemsCount.total + 1;
}

render() {
const List = this.props.List;
const ListWrapper = this.props.ListWrapper;
const pages = [];
for (let i = 0; i < this.state.currentPage + 1; i++) {
for (let i = 1; i < this.state.currentPage; i++) {
pages.push(
<List page={i} key={`paginated-list-${i}`} showPlaceHolders={this.props.pageSize} />
<List
page={i}
key={`paginated-list-${i}`}
showPlaceHolders={this.props.pageSize}
extraFilter={this.props.extraFilter}
/>
);
}
if (!this.props.itemsCountLoading && this.props.itemsCount.total === 0) {
return (
<ListWrapper>
<List page={1} showPlaceHolders={0} extraFilter={this.props.extraFilter} />
</ListWrapper>
);
}
return (
<InfiniteScroll
pageStart={0}
pageStart={1}
loadMore={this.loadMore}
hasMore={this.hasMore()}
initialLoad={true}
Expand All @@ -48,12 +60,13 @@ export class PaginatedList extends Component {
}
}

PaginatedList.contextType = ScrollContext;
ScrollPaginatedList.contextType = ScrollContext;

PaginatedList.propTypes = {
ScrollPaginatedList.propTypes = {
List: PropTypes.func,
ListWrapper: PropTypes.func,
extraFilter: PropTypes.any,
itemsCount: PropTypes.any,
// itemsCountLoading: PropTypes.bool,
itemsCountLoading: PropTypes.bool,
pageSize: PropTypes.number
};
3 changes: 3 additions & 0 deletions src/components/scroll-paginated-list/index.js
@@ -0,0 +1,3 @@
import { ScrollPaginatedList } from "./ScrollPaginatedList";

export const Component = ScrollPaginatedList;
15 changes: 0 additions & 15 deletions src/data-layer/services/logs/filters.js

This file was deleted.

10 changes: 9 additions & 1 deletion src/data-layer/services/logs/origins.js
Expand Up @@ -12,7 +12,7 @@ export const logs = new origins.Api(
);

export const countLogs = new origins.Api(
"/logs/count",
"/logs/stats",
{},
{
...authConfig,
Expand All @@ -21,3 +21,11 @@ export const countLogs = new origins.Api(
}
}
);

countLogs.addCustomFilter({
ofAbility: abilityId => ({
query: {
ability: abilityId
}
})
});
50 changes: 23 additions & 27 deletions src/data-layer/services/logs/selectors.js
@@ -1,27 +1,25 @@
import { Selector } from "reactive-data-source";

import { displayValue, formatDate } from "../../helpers";

import { abilitiesCollection } from "../abilities/origins";
import { servicesCollection } from "../services/origins";
import { logs } from "./origins";
import { addLogsDetails } from "./filters";

const NUMBER_OF_LOGS = 10;

export const lastLogs = new Selector(
logs,
logsResults => [...logsResults].reverse().slice(0, NUMBER_OF_LOGS),
[]
);

export const logsPage = new Selector(
{
source: logs,
filter: filter => {
const query = {};
if (filter) {
if (filter.page) {
query.page = filter.page;
}
if (filter.ability) {
query.ability = filter.ability;
}
return {
query: {
page: filter.page
}
query
};
}
return null;
Expand All @@ -38,20 +36,18 @@ export const logsPageWithDetails = new Selector(
source: logsPage,
filter: filter => filter
},
addLogsDetails,
[]
);

export const lastLogsDetails = new Selector(
abilitiesCollection,
servicesCollection,
lastLogs,
addLogsDetails,
[]
);

export const logsOfAbility = new Selector(
lastLogsDetails,
(lastLogsResults, abilityId) => lastLogsResults.filter(log => log._ability === abilityId),
(abilitiesResults, servicesResults, logsResults) => {
return logsResults.map(log => {
const ability = abilitiesResults.find(ability => ability._id === log._ability);
const service = servicesResults.find(service => service._id === ability._service);
return {
...log,
dateTime: formatDate(log.createdAt),
module: (service && service.name) || "-",
ability: (ability && ability.name) || "-",
data: displayValue(log.data)
};
});
},
[]
);
35 changes: 22 additions & 13 deletions src/modules/abilities/components/ability/Ability.js
Expand Up @@ -3,8 +3,8 @@ import PropTypes from "prop-types";
import { Link } from "react-router-dom";

import { Component as Container } from "src/components/container-content";
import { Component as ScrollPaginatedList } from "src/components/scroll-paginated-list";
import { Component as LogsListTable } from "src/components/logs-list-table";
import { Component as LogsList } from "src/components/logs-list";
import { Component as Breadcrumbs } from "src/components/breadcrumbs";
import { Component as AbilityInfo } from "../ability-info";
import { Menu, Icon } from "semantic-ui-react";
Expand All @@ -13,27 +13,34 @@ const ACTIVITY = "activity";
const INFO = "info";

export const Ability = ({
logs = [],
logsError,
logsLoading,
LogsList,
abilityId,
ability = {},
abilityLoading,
abilityError,
display = INFO,
activityUrl,
infoUrl,
baseUrl
baseUrl,
logsPageSize,
logsCount,
logsCountLoading
}) => {
const subsection =
display === ACTIVITY ? (
<LogsListTable>
<LogsList logs={logs} logsLoading={logsLoading} />
</LogsListTable>
<ScrollPaginatedList
List={LogsList}
ListWrapper={LogsListTable}
pageSize={logsPageSize}
itemsCount={logsCount}
itemsCountLoading={logsCountLoading}
extraFilter={{ abilityId }}
/>
) : (
<AbilityInfo ability={ability} loading={abilityLoading} />
);
const loading = display === ACTIVITY ? logsLoading : abilityLoading;
const error = display === ACTIVITY ? logsError : abilityError;
const loading = display === ACTIVITY ? null : abilityLoading;
const error = display === ACTIVITY ? null : abilityError;
return (
<Container loading={loading} error={error} background={true}>
<Container.Header loading={abilityLoading}>
Expand Down Expand Up @@ -67,14 +74,16 @@ export const Ability = ({
};

Ability.propTypes = {
LogsList: PropTypes.func,
ability: PropTypes.any.isRequired,
abilityError: PropTypes.instanceOf(Error),
abilityId: PropTypes.string,
abilityLoading: PropTypes.bool.isRequired,
activityUrl: PropTypes.string,
baseUrl: PropTypes.string,
display: PropTypes.oneOf([ACTIVITY, INFO]),
infoUrl: PropTypes.string,
logs: PropTypes.any.isRequired,
logsError: PropTypes.instanceOf(Error),
logsLoading: PropTypes.bool.isRequired
logsCount: PropTypes.any,
logsCountLoading: PropTypes.bool,
logsPageSize: PropTypes.number
};
14 changes: 9 additions & 5 deletions src/modules/abilities/views/Ability.js
Expand Up @@ -3,15 +3,19 @@ import { plugins } from "reactive-data-source";
import { Component as AbilityComponent } from "../components/ability";

import { abilityModelsWithExtraData } from "src/data-layer/services";
import { logsOfAbility } from "src/data-layer/services";
import { countLogs } from "src/data-layer/services";

import { Logs } from "./Logs";

export const mapDataSourceToProps = ({ id }) => {
const ability = abilityModelsWithExtraData.byId(id).read;
const logs = logsOfAbility.filter(id).read;
const getLogsCount = countLogs.ofAbility(id).read.getters;
return {
logs: logs.getters.value,
logsError: logs.getters.error,
logsLoading: logs.getters.loading,
LogsList: Logs,
logsPageSize: 10,
logsCount: getLogsCount.value,
logsCountLoading: getLogsCount.loading,
abilityId: id,
ability: ability.getters.value,
abilityError: ability.getters.error,
abilityLoading: ability.getters.loading
Expand Down
19 changes: 19 additions & 0 deletions src/modules/abilities/views/Logs.js
@@ -0,0 +1,19 @@
import { plugins } from "reactive-data-source";

import { Component as LogsList } from "src/components/logs-list";

import { logsPageWithDetails } from "src/data-layer/services";

export const mapDataSourceToProps = ({ page, extraFilter }) => {
const readLogs = logsPageWithDetails.filter({
page: page,
ability: extraFilter.abilityId
}).read.getters;
return {
logs: readLogs.value,
error: readLogs.error,
logsLoading: readLogs.loading
};
};

export const Logs = plugins.connect(mapDataSourceToProps)(LogsList);
28 changes: 4 additions & 24 deletions src/modules/activity/components/activity/Activity.js
@@ -1,30 +1,10 @@
import React from "react";
import PropTypes from "prop-types";

import { Component as PaginatedList } from "src/components/paginated-list";
import { Component as ScrollPaginatedList } from "src/components/scroll-paginated-list";
import { Component as Container } from "src/components/container-content";
import { Component as Breadcrumbs } from "src/components/breadcrumbs";

import { Table } from "semantic-ui-react";

const ListWrapper = ({ children }) => (
<Table unstackable compact basic size="small">
<Table.Header>
<Table.Row>
<Table.HeaderCell>At</Table.HeaderCell>
<Table.HeaderCell>Type</Table.HeaderCell>
<Table.HeaderCell>Module</Table.HeaderCell>
<Table.HeaderCell>Ability</Table.HeaderCell>
<Table.HeaderCell>Data</Table.HeaderCell>
</Table.Row>
</Table.Header>
<Table.Body>{children}</Table.Body>
</Table>
);

ListWrapper.propTypes = {
children: PropTypes.node
};
import { Component as LogsListTable } from "src/components/logs-list-table";

export const Activity = ({ LogsList, pageSize, logsCount, logsCountLoading }) => {
return (
Expand All @@ -33,9 +13,9 @@ export const Activity = ({ LogsList, pageSize, logsCount, logsCountLoading }) =>
<Breadcrumbs sections={[{ text: "Activity", icon: "history" }]} />
</Container.Header>
<Container.Content>
<PaginatedList
<ScrollPaginatedList
List={LogsList}
ListWrapper={ListWrapper}
ListWrapper={LogsListTable}
pageSize={pageSize}
itemsCount={logsCount}
itemsCountLoading={logsCountLoading}
Expand Down
11 changes: 7 additions & 4 deletions src/modules/dashboard/views/Main.js
@@ -1,7 +1,7 @@
import { plugins } from "reactive-data-source";

import { Module as AbilityCard } from "src/modules/ability-card";
import { lastLogsDetails } from "src/data-layer/services";
import { logsPageWithDetails } from "src/data-layer/services";

import { Component as DashboardLayout } from "../components/dashboard-layout";

Expand All @@ -15,13 +15,16 @@ export const init = configuration => {

export const mapDataSourceToProps = () => {
const abilities = dashboardAbilities.read;
const readlogsPage = logsPageWithDetails.filter({
page: 1
}).read.getters;
return {
abilities: abilities.getters.value,
abilitiesError: abilities.getters.error,
abilitiesLoading: abilities.getters.loading,
logs: lastLogsDetails.read.getters.value,
logsError: lastLogsDetails.read.getters.error,
logsLoading: lastLogsDetails.read.getters.loading,
logs: readlogsPage.value,
logsError: readlogsPage.error,
logsLoading: readlogsPage.loading,
AbilityCard,
abilitiesBaseUrl: config.abilitiesBaseUrl
};
Expand Down

0 comments on commit 302bcd6

Please sign in to comment.