diff --git a/js/components/forms/members_list.js b/js/components/forms/members_list.js index a092ab28..bc5a872f 100644 --- a/js/components/forms/members_list.js +++ b/js/components/forms/members_list.js @@ -1,3 +1,50 @@ +import { compose, sortBy, reverse, indexBy, partial, prop, pipe, toLower } from 'ramda' + +const search = (query, members) => { + if (query === '' || query === 'all') { + return members + } else { + const normalizedQuery = query.toLowerCase() + return members.filter( + (member) => member.name.toLowerCase().includes(normalizedQuery) + ) + } +} + +const filterByStatus = (status, members) => { + if (status === '' || status === 'all') { + return members + } else { + return members.filter( + (member) => member.status === status + ) + } +} + +const filterByRole = (role, rolesByDisplayname, members) => { + const getRoleNameFromDisplayName = (_role) => rolesByDisplayname[_role].name + + if (role === '' || role === 'all') { + return members + } else { + return members.filter( + (member) => getRoleNameFromDisplayName(member.role) === role + ) + } +} + +const sort = (sortInfo, members) => { + if (sortInfo.columnName === '') { + return members + } else { + const sortColumn = sortInfo.columns[sortInfo.columnName] + const sortedMembers = sortColumn.sortFunc(sortColumn.attr, members) + + return sortInfo.isAscending ? + sortedMembers : + reverse(sortedMembers) + } +} export default { name: 'members-list', @@ -8,33 +55,73 @@ export default { }, data: function () { + const alphabeticalSort = (attr, members) => { + const lowercaseProp = compose(toLower, prop(attr)) + return sortBy(lowercaseProp, members) + } + + const numericSort = (attr, members) => sortBy(prop(attr), members) + + const columns = [ + { + displayName: 'Name', + attr: 'name', + sortFunc: alphabeticalSort, + width: "50%" + }, + { + displayName: 'Environments', + attr: 'num_env', + sortFunc: numericSort, + class: "table-cell--align-right" + }, + { + displayName: 'Status', + attr: 'status', + sortFunc: alphabeticalSort + }, + { + displayName: 'Workspace Role', + attr: 'role', + sortFunc: alphabeticalSort + }, + ] + return { searchValue: '', status: '', role: '', + rolesByDisplayName: indexBy(prop('display_name'), this.choices), + sortInfo: { + columnName: '', + isAscending: true, + columns: indexBy(prop('displayName'), columns) + }, } }, computed: { searchedList: function () { - return this.members.filter( - member => this.status ? - member.status === this.status | this.status === 'all' - : true - ).filter( - member => this.role ? ( - this.getRoleFromDisplayName(member.role) === this.role | this.role === 'all') - : true - ).filter( - member => this.searchValue ? member.name.toLowerCase() - .includes(this.searchValue.toLowerCase()) : true - ) + return pipe( + partial(search, [this.searchValue]), + partial(filterByStatus, [this.status]), + partial(filterByRole, [this.role, this.rolesByDisplayName]), + partial(sort, [this.sortInfo]) + )(this.members) } }, methods: { - getRoleFromDisplayName: function (role) { - return this.choices.find(choice => choice.display_name === role).name + updateSort: function(columnName) { + // clicking a column twice toggles ascending / descending + if (columnName === this.sortInfo.columnName) { + this.sortInfo.isAscending = !this.sortInfo.isAscending + } + + this.sortInfo.columnName = columnName }, - }, + getColumns: function() { + return Object.values(this.sortInfo.columns) + } + } } diff --git a/templates/workspaces/members/index.html b/templates/workspaces/members/index.html index 82086696..ef932607 100644 --- a/templates/workspaces/members/index.html +++ b/templates/workspaces/members/index.html @@ -2,6 +2,7 @@ {% from "components/empty_state.html" import EmptyState %} {% from "components/alert.html" import Alert %} +{% from "components/icon.html" import Icon %} {% block workspace_content %} @@ -82,10 +83,15 @@ - - - - +
NameEnvironmentsStatusWorkspace Role + !{ col.displayName } + + {{ Icon("caret_down") }} + + + {{ Icon("caret_up") }} + +