@@ -70,80 +70,116 @@ module.controller('ProjectListCtrl', [
7070 search : vm . formSearch . search ,
7171 status : vm . formSearch . status === ALL ? '' : vm . formSearch . status
7272 } ) . then (
73+
74+ // For the loaded project objects this function does:
75+ // 1. Queries user email and handles for ids of all projects' copilots
76+ // and owners. The queries are send in batches of size equal to
77+ // MAX_BATCH_SIZE ids per query.
78+ // 2. If 'vm.formSearch.filterByHandleOrEmail' is true, it filters
79+ // loaded project object by handle and emails;
80+ // 3. Redraws the table.
81+
7382 function ( projects ) {
7483
75- // Generates the query to search for members with 'usedId' specified
76- // in 'ownerId' and 'copilotId' field of each project we have found.
77- // The 'isNaN' check is necessary as 'copilotId' may be equal to
78- // "unassigned", or some other string values.
79- var query = projects . reduce ( function ( query , project ) {
80- if ( ! isNaN ( project . ownerId ) )
81- query += 'userId:' + project . ownerId + ' OR ' ;
82- if ( ! isNaN ( project . copilotId ) )
83- query += 'userId:' + project . copilotId + ' OR ' ;
84- return query ;
85- } , '' ) . slice ( 0 , - 4 ) ;
86-
87- vm . allProjects = projects ;
88- $scope . projects = vm . allProjects ;
89-
90- // Resolution of User IDs in the found project objects.
91- membersService . search ( {
92- search : query
93- } ) . then (
94- function ( users ) {
95-
96- // Uses the found 'users' array to add 'copilotHandle' and
97- // 'ownerHandle' field to each project object.
98- var map = users . reduce ( function ( map , user ) {
99- map [ user . userId ] = user ;
100- return map ;
101- } , { } ) ;
102- projects . forEach ( function ( project ) {
103- project . copilot = map [ project . copilotId ] ;
104- project . owner = map [ project . ownerId ] ;
105- } ) ;
84+ var MAX_BATCH_SIZE = 100 ;
10685
107- // If asked, filters the projects by owner's handle and
108- // and email (remaining projects will contain
109- // 'vm.formSearch.handleOrEmail' as a substring
110- // of their owner's handle or email).
111- if ( vm . filterByHandleOrEmail ) {
112- vm . filterByHandleOrEmail = false ;
113- var key = vm . formSearch . handleOrEmail ;
114- projects = projects . filter ( function ( project ) {
115- var res = false ;
116- res |= project . owner && project . owner . handle &&
117- project . owner . handle . includes ( key ) ;
118- res |= project . owner && project . owner . email &&
119- project . owner . email . includes ( key ) ;
120- res |= project . copilot && project . copilot . handle &&
121- project . copilot . handle . includes ( key ) ;
122- res |= project . copilot && project . copilot . email &&
123- project . copilot . email . includes ( key ) ;
124- return res ;
125- } ) ;
126- vm . allProjects = projects ;
127- $scope . projects = projects ;
128- }
129- $timeout ( function ( ) {
130- vm . formSearch . isLoading = false ;
131- $ ( '.table' ) . trigger ( 'footable_redraw' ) ;
132- } , 500 ) ;
86+ // Collects copilot and owner's ids from the loaded project objects.
87+ // The resulting 'queue' array will hold unique user ids to be
88+ // be queried from the MembersService in several batches, and
89+ // the 'users' dictionary will be prepared to collect queiried data.
90+ var queue = [ ] , collect = function ( users , userId ) {
91+ if ( ! isNaN ( userId ) && ! users [ userId ] ) {
92+ users [ userId ] = { email : '' , handle : '' } ;
93+ queue . push ( userId ) ;
94+ }
95+ } ;
96+ var users = projects . reduce ( function ( users , project ) {
97+
98+ // Ids should be trimmed, as in the production data some of them
99+ // may include spaces before and after, which breaks matching of
100+ // ids width handles.
101+ if ( project . copilotId ) {
102+ project . copilotId = project . copilotId . trim ( ) ;
103+ }
104+ if ( project . ownerId ) {
105+ project . ownerId = project . ownerId . trim ( ) ;
106+ }
133107
134- } ,
135- function ( error ) {
108+ collect ( users , project . copilotId ) ;
109+ collect ( users , project . ownerId ) ;
110+ return users ;
111+ } , { } ) ;
136112
137- // Even in case of failure with the request to the Member
138- // Service we still should update the page as the project's
139- // data have been loaded (but not the user handles).
140-
141- $timeout ( function ( ) {
142- vm . formSearch . isLoading = false ;
143- $ ( '.table' ) . trigger ( 'footable_redraw' ) ;
144- } , 500 ) ;
113+ // Now we send queries to MembersService in batches.
114+ // The MAX_BATCH_SIZE constant sets the maximal batch size
115+ // (i.e. the number of ids in a single query).
116+ var pos = 0 , queryNextBatch = function ( ) {
117+ var query = '' ;
118+ var end = Math . min ( pos + MAX_BATCH_SIZE , queue . length ) ;
119+ for ( var i = pos ; i < end ; ++ i ) {
120+ query += 'userId:' + queue [ i ] + ' OR ' ;
121+ }
122+ membersService . search ( {
123+ search : query . slice ( 0 , - 4 )
124+ } ) . then (
125+ function ( userObjects ) {
126+ pos += MAX_BATCH_SIZE ;
127+ userObjects . forEach ( function ( user ) {
128+ users [ user . userId ] = {
129+ email : user . email ,
130+ handle : user . handle
131+ } ;
132+ } ) ;
133+ if ( pos < queue . length ) {
134+ queryNextBatch ( ) ;
135+ } else {
136+ finalize ( ) ;
137+ }
138+ } ,
139+ function ( error ) {
140+ finalize ( ) ;
141+ }
142+ ) ;
143+ } ;
144+
145+ // Once all necessary data have been queried, this function
146+ // will be used to attach the queried user data to the loaded
147+ // project object, and to redraw the table.
148+ var finalize = function ( ) {
149+
150+ projects . forEach ( function ( project ) {
151+ project . copilot = users [ project . copilotId ] ;
152+ project . owner = users [ project . ownerId ] ;
153+ } ) ;
154+
155+ // If asked, filters the projects by owner's handle and
156+ // and email (remaining projects will contain
157+ // 'vm.formSearch.handleOrEmail' as a substring
158+ // of their owner's handle or email).
159+ if ( vm . formSearch . filterByHandleOrEmail ) {
160+ vm . formSearch . filterByHandleOrEmail = false ;
161+ var key = vm . formSearch . handleOrEmail ;
162+ projects = projects . filter ( function ( project ) {
163+ var res = false ;
164+ res |= project . owner && project . owner . handle &&
165+ project . owner . handle . includes ( key ) ;
166+ res |= project . owner && project . owner . email &&
167+ project . owner . email . includes ( key ) ;
168+ res |= project . copilot && project . copilot . handle &&
169+ project . copilot . handle . includes ( key ) ;
170+ res |= project . copilot && project . copilot . email &&
171+ project . copilot . email . includes ( key ) ;
172+ return res ;
173+ } ) ;
145174 }
146- ) ;
175+
176+ vm . allProjects = projects ;
177+ $scope . projects = projects ;
178+ vm . formSearch . isLoading = false ;
179+ $ ( '.table' ) . trigger ( 'footable_redraw' ) ;
180+ } ;
181+
182+ queryNextBatch ( ) ;
147183 } ,
148184 function ( error ) {
149185 // error handling
@@ -166,9 +202,9 @@ module.controller('ProjectListCtrl', [
166202 * with an additionally activated 'handle or e-mail' filter.
167203 */
168204 vm . findByHandleOrEmail = function ( ) {
169- vm . filterByHandleOrEmail = true ;
170- vm . search = '' ;
171- vm . status = ALL ;
205+ vm . formSearch . filterByHandleOrEmail = true ;
206+ vm . formSearch . search = '' ;
207+ vm . formSearch . status = ALL ;
172208 vm . findProjects ( ) ;
173209 } ;
174210
0 commit comments