From ae4b383b2b5e49e35caa372720311dad21c5342a Mon Sep 17 00:00:00 2001 From: Nikolaus Piccolotto Date: Tue, 27 Oct 2015 13:51:58 +0100 Subject: [PATCH 1/5] #314 add all accounts --- .../asset/less/common/account-selector.less | 7 ++ client/lib/violation/src/account-selector.jsx | 71 +++++++++++++++---- 2 files changed, 64 insertions(+), 14 deletions(-) diff --git a/client/lib/common/asset/less/common/account-selector.less b/client/lib/common/asset/less/common/account-selector.less index dbaba35c..fbc18443 100644 --- a/client/lib/common/asset/less/common/account-selector.less +++ b/client/lib/common/asset/less/common/account-selector.less @@ -3,6 +3,11 @@ .account-selector { padding: @padding-small 0; + .account-selector-list { + max-height: 300px; + overflow: auto; + } + label { .transition(background, color); cursor: pointer; @@ -52,6 +57,7 @@ .input-group { display: flex; + width: 30em; padding-bottom: @padding-small; .fa { user-select: none; @@ -69,6 +75,7 @@ input { border-top-left-radius: 0px; border-bottom-left-radius: 0px; + width: 100%; } } } \ No newline at end of file diff --git a/client/lib/violation/src/account-selector.jsx b/client/lib/violation/src/account-selector.jsx index 2bf3215e..c24d8838 100644 --- a/client/lib/violation/src/account-selector.jsx +++ b/client/lib/violation/src/account-selector.jsx @@ -1,23 +1,36 @@ import React from 'react'; import Icon from 'react-fa'; +import _ from 'lodash'; import {Typeahead} from 'react-typeahead'; +import fuzzysearch from 'fuzzysearch'; import 'common/asset/less/common/account-selector.less'; function filterOptionFn(input, option) { return input .trim() .split(' ') - .some(term => (option.name + option.id).indexOf(term) >= 0); + .some(term => fuzzysearch(term, option.name + option.id)); } class AccountSelector extends React.Component { constructor(props) { super(); this.state = { + allAdded: props.selectedAccounts ? props.selectedAccounts.length === props.selectableAccounts.length : false, + filter: '', selectedAccounts: props.selectedAccounts || [] }; } + _addAll() { + let selectedAccountIds = this.state.selectedAccounts.map(a => a.id), + toSelect = this.props.selectableAccounts.filter(a => selectedAccountIds.indexOf(a.id) < 0); + toSelect.forEach(this._selectAccount.bind(this)); + this.setState({ + allAdded: true + }); + } + _selectAccount(account) { let {id} = account; if (this.state.selectedAccounts.map(a => a.id).indexOf(id) >= 0) { @@ -56,23 +69,52 @@ class AccountSelector extends React.Component { } } + _filter(evt) { + this.setState({ + filter: evt.target.value + }); + } + render() { let {selectableAccounts, activeAccountIds} = this.props, - {selectedAccounts} = this.state; + {selectedAccounts} = this.state, + displayedAccounts = this.state.filter ? + selectedAccounts.filter(a => fuzzysearch(this.state.filter, a.name)) : + selectedAccounts; return
Show violations in accounts:
- You can search by name or account number. -
- - `${option.name} (${option.id})`} - filterOption={filterOptionFn} - onOptionSelected={this._selectAccount.bind(this)} - maxVisible={10} /> -
- {selectedAccounts.map(a => + {!this.state.allAdded ? +
+
+ You can search by name or account number or + Add all accounts + + +
+
+ + `${option.name} (${option.id})`} + filterOption={filterOptionFn} + onOptionSelected={this._selectAccount.bind(this)} + maxVisible={10} /> +
+
+ : +
+ + +
} +
+ {_.sortBy(displayedAccounts, 'name') + .map(a => )} +
; } } From 5836ef1cf5cb9324fbf633d7cea66cf6f54f4582 Mon Sep 17 00:00:00 2001 From: Nikolaus Piccolotto Date: Tue, 27 Oct 2015 13:58:48 +0100 Subject: [PATCH 2/5] #314 lint --- .../lib/violation/src/violation-analysis/violation-analysis.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/lib/violation/src/violation-analysis/violation-analysis.jsx b/client/lib/violation/src/violation-analysis/violation-analysis.jsx index 6fb814ca..e5bbc218 100644 --- a/client/lib/violation/src/violation-analysis/violation-analysis.jsx +++ b/client/lib/violation/src/violation-analysis/violation-analysis.jsx @@ -120,7 +120,7 @@ class ViolationAnalysis extends React.Component { return
No violations! -
+ ; } } ViolationAnalysis.displayName = 'ViolationAnalysis'; From 80ea951164f3359f823c18d69ac660f612e6a12a Mon Sep 17 00:00:00 2001 From: Nikolaus Piccolotto Date: Tue, 27 Oct 2015 14:43:08 +0100 Subject: [PATCH 3/5] #314 efficiency, sort active first toggle callback for all at once, not one by one --- client/Gulpfile.js | 1 + client/lib/common/src/lodash.custom.js | 66 ++++++++++++++++++- client/lib/violation/src/account-selector.jsx | 47 +++++++------ 3 files changed, 92 insertions(+), 22 deletions(-) diff --git a/client/Gulpfile.js b/client/Gulpfile.js index 59587985..a46a6a99 100644 --- a/client/Gulpfile.js +++ b/client/Gulpfile.js @@ -26,6 +26,7 @@ var LODASH_FUNCS = [ 'groupBy', 'intersection', 'isEmpty', + 'partition', 'pluck', 'reverse', 'sortBy', diff --git a/client/lib/common/src/lodash.custom.js b/client/lib/common/src/lodash.custom.js index bf9156bd..163efaf8 100644 --- a/client/lib/common/src/lodash.custom.js +++ b/client/lib/common/src/lodash.custom.js @@ -1,7 +1,7 @@ /** * @license * lodash 3.9.3 (Custom Build) - * Build: `lodash modern include="chain,debounce,difference,extend,filter,findLastIndex,flatten,forOwn,groupBy,intersection,isEmpty,pluck,reverse,sortBy,slice,take,times,value,values" -d -o lib/common/src/lodash.custom.js` + * Build: `lodash modern include="chain,debounce,difference,extend,filter,findLastIndex,flatten,forOwn,groupBy,intersection,isEmpty,partition,pluck,reverse,sortBy,slice,take,times,value,values" -d -o lib/common/src/lodash.custom.js` * Copyright 2012-2015 The Dojo Foundation * Based on Underscore.js 1.8.3 * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors @@ -3354,6 +3354,69 @@ return func(collection, iteratee); } + /** + * Creates an array of elements split into two groups, the first of which + * contains elements `predicate` returns truthy for, while the second of which + * contains elements `predicate` returns falsey for. The predicate is bound + * to `thisArg` and invoked with three arguments: (value, index|key, collection). + * + * If a property name is provided for `predicate` the created `_.property` + * style callback returns the property value of the given element. + * + * If a value is also provided for `thisArg` the created `_.matchesProperty` + * style callback returns `true` for elements that have a matching property + * value, else `false`. + * + * If an object is provided for `predicate` the created `_.matches` style + * callback returns `true` for elements that have the properties of the given + * object, else `false`. + * + * @static + * @memberOf _ + * @category Collection + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function|Object|string} [predicate=_.identity] The function invoked + * per iteration. + * @param {*} [thisArg] The `this` binding of `predicate`. + * @returns {Array} Returns the array of grouped elements. + * @example + * + * _.partition([1, 2, 3], function(n) { + * return n % 2; + * }); + * // => [[1, 3], [2]] + * + * _.partition([1.2, 2.3, 3.4], function(n) { + * return this.floor(n) % 2; + * }, Math); + * // => [[1.2, 3.4], [2.3]] + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': false }, + * { 'user': 'fred', 'age': 40, 'active': true }, + * { 'user': 'pebbles', 'age': 1, 'active': false } + * ]; + * + * var mapper = function(array) { + * return _.pluck(array, 'user'); + * }; + * + * // using the `_.matches` callback shorthand + * _.map(_.partition(users, { 'age': 1, 'active': false }), mapper); + * // => [['pebbles'], ['barney', 'fred']] + * + * // using the `_.matchesProperty` callback shorthand + * _.map(_.partition(users, 'active', false), mapper); + * // => [['barney', 'pebbles'], ['fred']] + * + * // using the `_.property` callback shorthand + * _.map(_.partition(users, 'active'), mapper); + * // => [['fred'], ['barney', 'pebbles']] + */ + var partition = createAggregator(function(result, value, key) { + result[key ? 0 : 1].push(value); + }, function() { return [[], []]; }); + /** * Gets the property value of `path` from all elements in `collection`. * @@ -4461,6 +4524,7 @@ lodash.matches = matches; lodash.mixin = mixin; lodash.pairs = pairs; + lodash.partition = partition; lodash.pluck = pluck; lodash.property = property; lodash.restParam = restParam; diff --git a/client/lib/violation/src/account-selector.jsx b/client/lib/violation/src/account-selector.jsx index c24d8838..508d90f8 100644 --- a/client/lib/violation/src/account-selector.jsx +++ b/client/lib/violation/src/account-selector.jsx @@ -16,18 +16,18 @@ class AccountSelector extends React.Component { constructor(props) { super(); this.state = { - allAdded: props.selectedAccounts ? props.selectedAccounts.length === props.selectableAccounts.length : false, + allSelected: props.selectedAccounts ? props.selectedAccounts.length === props.selectableAccounts.length : false, filter: '', selectedAccounts: props.selectedAccounts || [] }; } - _addAll() { - let selectedAccountIds = this.state.selectedAccounts.map(a => a.id), - toSelect = this.props.selectableAccounts.filter(a => selectedAccountIds.indexOf(a.id) < 0); - toSelect.forEach(this._selectAccount.bind(this)); + _selectAll() { + this.props.onToggleAccount(this.props.selectableAccounts.map(a => a.id)); + this.setState({ - allAdded: true + allSelected: true, + selectedAccounts: _.sortBy(this.props.selectableAccounts, 'name') }); } @@ -37,17 +37,8 @@ class AccountSelector extends React.Component { return; } this.state.selectedAccounts.push(account); - this.state.selectedAccounts - .sort((a, b) => { - let aName = a.name.toLowerCase(), - bName = b.name.toLowerCase(); - return aName < bName ? - -1 : - bName < aName ? - 1 : 0; - }); this.setState({ - selectedAccounts: this.state.selectedAccounts + selectedAccounts: _.sortBy(this.state.selectedAccounts, 'name') }); let {activeAccountIds} = this.props; if (activeAccountIds.indexOf(account.id) < 0) { @@ -80,16 +71,19 @@ class AccountSelector extends React.Component { {selectedAccounts} = this.state, displayedAccounts = this.state.filter ? selectedAccounts.filter(a => fuzzysearch(this.state.filter, a.name)) : - selectedAccounts; + selectedAccounts, + partitionedAccounts = _.partition(displayedAccounts, a => activeAccountIds.indexOf(a.id) >= 0), + activeAccounts = partitionedAccounts[0], + inactiveAccounts = partitionedAccounts[1]; return
Show violations in accounts:
- {!this.state.allAdded ? + {!this.state.allSelected ?
You can search by name or account number or - Add all accounts + Select all accounts
@@ -113,7 +107,18 @@ class AccountSelector extends React.Component { type='text'/>
}
- {_.sortBy(displayedAccounts, 'name') + {_.sortBy(activeAccounts, 'name') + .map(a => + )} + {_.sortBy(inactiveAccounts, 'name') .map(a =>
} +
+
+ Toggle all +
+
+ Untoggle all +
+
{_.sortBy(activeAccounts, 'name') .map(a => From d2128011b08e7eaa080249e573b4519d92b7c45b Mon Sep 17 00:00:00 2001 From: Nikolaus Piccolotto Date: Tue, 27 Oct 2015 15:02:53 +0100 Subject: [PATCH 5/5] #314 actually the build script was fine before --- build.sh | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/build.sh b/build.sh index 653c7eb6..ee59cac7 100755 --- a/build.sh +++ b/build.sh @@ -11,13 +11,10 @@ then exit 1 fi -# create new version -npm version "$1" # build npm install cd client gulp build cd .. # push -docker build -t "$DEFAULT_DOCKER_REGISTRY/stups/yourturn:$1" . && docker push "$DEFAULT_DOCKER_REGISTRY/stups/yourturn:$1" -git push --tags \ No newline at end of file +docker build -t "$DEFAULT_DOCKER_REGISTRY/stups/yourturn:$1" . && docker push "$DEFAULT_DOCKER_REGISTRY/stups/yourturn:$1" \ No newline at end of file