Skip to content
This repository has been archived by the owner on May 27, 2021. It is now read-only.

ability to sort and filter on actions #497

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/tests/workflows/recipes/pages/RecipeListingPage.test.js
@@ -1,4 +1,4 @@
import { List } from 'immutable';
import { List, Map } from 'immutable';
import TestComponent from 'console/workflows/recipes/pages/RecipeListingPage';

const { WrappedComponent: RecipeListingPage } = TestComponent;
Expand All @@ -7,6 +7,7 @@ describe('<RecipeListingPage>', () => {
const props = {
columns: new List(),
count: null,
actions: new Map(),
fetchFilteredRecipesPage: () => {},
getCurrentUrlAsObject: () => {},
history: {},
Expand Down
184 changes: 100 additions & 84 deletions src/workflows/recipes/pages/RecipeListingPage.js
Expand Up @@ -2,7 +2,7 @@ import { Pagination, Table } from 'antd';
import autobind from 'autobind-decorator';
import { push } from 'connected-react-router';
import dateFns from 'date-fns';
import { List } from 'immutable';
import { Map, List } from 'immutable';
import PropTypes from 'prop-types';
import React from 'react';
import { connect } from 'react-redux';
Expand All @@ -28,9 +28,11 @@ import {
getQueryParam,
getQueryParamAsInt,
} from 'console/state/router/selectors';
import { getAllActions } from 'console/state/actions/selectors';

@connect(
(state, props) => ({
actions: getAllActions(state, new Map()),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can/should this be actions: getAllActions(state) || new Map() instead?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it could be that too.

columns: getRecipeListingColumns(state),
count: getRecipeListingCount(state),
getCurrentUrlAsObject: queryParams => getCurrentUrlAsObjectSelector(state, queryParams),
Expand All @@ -39,6 +41,7 @@ import {
recipes: getRecipeListingFlattenedAction(state),
searchText: getQueryParam(state, 'searchText'),
status: getQueryParam(state, 'status'),
action: getQueryParam(state, 'action'),
}),
{
push,
Expand All @@ -47,6 +50,7 @@ import {
@autobind
class RecipeListingPage extends React.PureComponent {
static propTypes = {
actions: PropTypes.instanceOf(Map).isRequired,
columns: PropTypes.instanceOf(List).isRequired,
count: PropTypes.number,
getCurrentUrlAsObject: PropTypes.func.isRequired,
Expand All @@ -56,6 +60,7 @@ class RecipeListingPage extends React.PureComponent {
recipes: PropTypes.instanceOf(List).isRequired,
searchText: PropTypes.string,
status: PropTypes.string,
action: PropTypes.string,
};

static defaultProps = {
Expand All @@ -64,99 +69,21 @@ class RecipeListingPage extends React.PureComponent {
pageNumber: null,
searchText: null,
status: null,
};

static columnRenderers = {
name({ ordering }) {
return (
<Table.Column
title="Name"
dataIndex="name"
key="name"
render={(text, record) => (
<div className="recipe-listing-name">
<ShieldIdenticon className="shieldicon" seed={record.identicon_seed} size={24} />
{RecipeListingPage.renderLinkedText(text, record)}
</div>
)}
sortOrder={DataList.getSortOrder('name', ordering)}
sorter
/>
);
},

action() {
return (
<Table.Column
title="Action"
dataIndex="action"
key="action"
render={RecipeListingPage.renderLinkedText}
/>
);
},

enabled({ status }) {
return (
<Table.Column
title="Enabled"
key="status"
render={(text, record) => <BooleanIcon value={record.enabled} />}
filters={[
{ text: 'Enabled', value: 'enabled' },
{ text: 'Disabled', value: 'disabled' },
]}
filteredValue={status}
filterMultiple={false}
/>
);
},

paused() {
return (
<Table.Column
title="Enrollment Active"
key="paused"
render={(text, record) => <EnrollmentStatus recipe={record} />}
/>
);
},

lastUpdated({ ordering }) {
return (
<Table.Column
title="Last Updated"
key="last_updated"
dataIndex="last_updated"
render={(text, record) => {
const lastUpdated = dateFns.parse(record.last_updated);
return (
<Link
to={reverse('recipes.details', { recipeId: record.id })}
title={dateFns.format(lastUpdated, 'dddd, MMMM M, YYYY h:mm A')}
>
{dateFns.distanceInWordsToNow(lastUpdated)}
</Link>
);
}}
sortOrder={DataList.getSortOrder('last_updated', ordering)}
sorter
/>
);
},
action: null,
};

static renderLinkedText(text, { id: recipeId }) {
return <Link to={reverse('recipes.details', { recipeId })}>{text}</Link>;
}

getFilters() {
const { ordering, searchText, status } = this.props;
const { ordering, searchText, status, action } = this.props;

const filters = {
text: searchText,
ordering,
status,
action,
};

Object.keys(filters).forEach(key => {
Expand All @@ -178,12 +105,100 @@ class RecipeListingPage extends React.PureComponent {
}

render() {
const { columns, count, ordering, pageNumber, recipes, status } = this.props;
const { columns, count, ordering, pageNumber, recipes, status, action, actions } = this.props;
const actionNames = Object.values(actions.toJS()).map(action => action.name);
actionNames.sort();

const filters = this.getFilters();

const filterIds = Object.keys(filters).map(key => `${key}-${filters[key]}`);
const requestId = `fetch-filtered-recipes-page-${pageNumber}-${filterIds.join('-')}`;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The change here is that I moved it from being a static object of functions to instead being defined inside the render method. I did that so I can dynamically (using closures) get the list of all possible action names. And I also, changed the function for action. The rest is just code moves.

const columnRenderers = {
name: ({ ordering }) => {
return (
<Table.Column
title="Name"
dataIndex="name"
key="name"
render={(text, record) => (
<div className="recipe-listing-name">
<ShieldIdenticon className="shieldicon" seed={record.identicon_seed} size={24} />
{RecipeListingPage.renderLinkedText(text, record)}
</div>
)}
sortOrder={DataList.getSortOrder('name', ordering)}
sorter
/>
);
},

action: ({ action, ordering }) => {
return (
<Table.Column
title="Action"
dataIndex="action"
key="action"
render={RecipeListingPage.renderLinkedText}
filters={actionNames.map(name => ({ text: name, value: name }))}
filteredValue={[action]}
filterMultiple={false}
sortOrder={DataList.getSortOrder('action', ordering)}
sorter
/>
);
},

enabled: ({ status }) => {
return (
<Table.Column
title="Enabled"
key="status"
render={(text, record) => <BooleanIcon value={record.enabled} />}
filters={[
{ text: 'Enabled', value: 'enabled' },
{ text: 'Disabled', value: 'disabled' },
]}
filteredValue={status}
filterMultiple={false}
/>
);
},

paused: () => {
return (
<Table.Column
title="Enrollment Active"
key="paused"
render={(text, record) => <EnrollmentStatus recipe={record} />}
/>
);
},

lastUpdated: ({ ordering }) => {
return (
<Table.Column
title="Last Updated"
key="last_updated"
dataIndex="last_updated"
render={(text, record) => {
const lastUpdated = dateFns.parse(record.last_updated);
return (
<Link
to={reverse('recipes.details', { recipeId: record.id })}
title={dateFns.format(lastUpdated, 'dddd, MMMM M, YYYY h:mm A')}
>
{dateFns.distanceInWordsToNow(lastUpdated)}
</Link>
);
}}
sortOrder={DataList.getSortOrder('last_updated', ordering)}
sorter
/>
);
},
};

return (
<div className="content-wrapper">
<QueryRecipeListingColumns />
Expand All @@ -194,11 +209,12 @@ class RecipeListingPage extends React.PureComponent {
<LoadingOverlay requestIds={requestId}>
<DataList
columns={columns}
columnRenderers={RecipeListingPage.columnRenderers}
columnRenderers={columnRenderers}
dataSource={recipes.toJS()}
ordering={ordering}
getUrlFromRecord={this.getUrlFromRecord}
status={status}
action={action}
/>
</LoadingOverlay>

Expand Down