Index: gm/rebaseline_server/static/loader.js |
diff --git a/gm/rebaseline_server/static/loader.js b/gm/rebaseline_server/static/loader.js |
index 9384196fb12fa7a42785b4bc0b34b3303d625164..19bc2378a0cbfd16b30d98bdf6a46151568aa8b4 100644 |
--- a/gm/rebaseline_server/static/loader.js |
+++ b/gm/rebaseline_server/static/loader.js |
@@ -30,24 +30,29 @@ Loader.directive( |
Loader.filter( |
'removeHiddenImagePairs', |
function(constants) { |
- return function(unfilteredImagePairs, showingColumnValues, |
- builderSubstring, testSubstring, viewingTab) { |
+ return function(unfilteredImagePairs, filterableColumnNames, showingColumnValues, |
+ viewingTab) { |
var filteredImagePairs = []; |
for (var i = 0; i < unfilteredImagePairs.length; i++) { |
var imagePair = unfilteredImagePairs[i]; |
var extraColumnValues = imagePair[constants.KEY__IMAGEPAIRS__EXTRACOLUMNS]; |
- // For performance, we examine the "set" objects directly rather |
- // than calling $scope.isValueInSet(). |
- // Besides, I don't think we have access to $scope in here... |
- if (showingColumnValues[constants.KEY__EXTRACOLUMNS__RESULT_TYPE] |
- [extraColumnValues[constants.KEY__EXTRACOLUMNS__RESULT_TYPE]] && |
- showingColumnValues[constants.KEY__EXTRACOLUMNS__CONFIG] |
- [extraColumnValues[constants.KEY__EXTRACOLUMNS__CONFIG]] && |
- !(-1 == extraColumnValues[constants.KEY__EXTRACOLUMNS__BUILDER] |
- .indexOf(builderSubstring)) && |
- !(-1 == extraColumnValues[constants.KEY__EXTRACOLUMNS__TEST] |
- .indexOf(testSubstring)) && |
- (viewingTab == imagePair.tab)) { |
+ var allColumnValuesAreVisible = true; |
+ // Loop over all columns, and if any of them contain values not found in |
+ // showingColumnValues[columnName], don't include this imagePair. |
+ // |
+ // We use this same filtering mechanism regardless of whether each column |
+ // has USE_FREEFORM_FILTER set or not; if that flag is set, then we will |
+ // have already used the freeform text entry block to populate |
+ // showingColumnValues[columnName]. |
+ for (var j = 0; j < filterableColumnNames.length; j++) { |
+ var columnName = filterableColumnNames[j]; |
+ var columnValue = extraColumnValues[columnName]; |
+ if (!showingColumnValues[columnName][columnValue]) { |
+ allColumnValuesAreVisible = false; |
+ break; |
+ } |
+ } |
+ if (allColumnValuesAreVisible && (viewingTab == imagePair.tab)) { |
filteredImagePairs.push(imagePair); |
} |
} |
@@ -159,6 +164,7 @@ Loader.controller( |
$scope.header = dataHeader; |
$scope.extraColumnHeaders = data[constants.KEY__ROOT__EXTRACOLUMNHEADERS]; |
+ $scope.orderedColumnNames = data[constants.KEY__ROOT__EXTRACOLUMNORDER]; |
$scope.imagePairs = data[constants.KEY__ROOT__IMAGEPAIRS]; |
$scope.imageSets = data[constants.KEY__ROOT__IMAGESETS]; |
$scope.sortColumnSubdict = constants.KEY__IMAGEPAIRS__DIFFERENCES; |
@@ -200,41 +206,69 @@ Loader.controller( |
// Arrays within which the user can toggle individual elements. |
$scope.selectedImagePairs = []; |
+ // Set up filters. |
+ // |
+ // filterableColumnNames is a list of all column names we can filter on. |
// allColumnValues[columnName] is a list of all known values |
- // for this column. |
+ // for a given column. |
// showingColumnValues[columnName] is a set indicating which values |
- // in this column would cause us to show a row, rather than hiding it. |
+ // in a given column would cause us to show a row, rather than hiding it. |
+ // |
+ // columnStringMatch[columnName] is a string used as a pattern to generate |
+ // showingColumnValues[columnName] for columns we filter using free-form text. |
+ // It is ignored for any columns with USE_FREEFORM_FILTER == false. |
+ $scope.filterableColumnNames = []; |
$scope.allColumnValues = {}; |
$scope.showingColumnValues = {}; |
+ $scope.columnStringMatch = {}; |
- // set allColumnValues/showingColumnValues for RESULT_TYPE; |
+ angular.forEach( |
+ Object.keys($scope.extraColumnHeaders), |
+ function(columnName) { |
+ var columnHeader = $scope.extraColumnHeaders[columnName]; |
+ if (columnHeader[constants.KEY__EXTRACOLUMNHEADERS__IS_FILTERABLE]) { |
+ $scope.filterableColumnNames.push(columnName); |
+ $scope.allColumnValues[columnName] = $scope.columnSliceOf2DArray( |
+ columnHeader[constants.KEY__EXTRACOLUMNHEADERS__VALUES_AND_COUNTS], 0); |
+ $scope.showingColumnValues[columnName] = {}; |
+ $scope.toggleValuesInSet($scope.allColumnValues[columnName], |
+ $scope.showingColumnValues[columnName]); |
+ $scope.columnStringMatch[columnName] = ""; |
+ } |
+ } |
+ ); |
+ |
+ // TODO(epoger): Special handling for RESULT_TYPE column: |
// by default, show only KEY__RESULT_TYPE__FAILED results |
- $scope.allColumnValues[constants.KEY__EXTRACOLUMNS__RESULT_TYPE] = |
- $scope.columnSliceOf2DArray( |
- $scope.extraColumnHeaders[constants.KEY__EXTRACOLUMNS__RESULT_TYPE] |
- [constants.KEY__EXTRACOLUMNHEADERS__VALUES_AND_COUNTS], |
- 0); |
$scope.showingColumnValues[constants.KEY__EXTRACOLUMNS__RESULT_TYPE] = {}; |
$scope.showingColumnValues[constants.KEY__EXTRACOLUMNS__RESULT_TYPE][ |
constants.KEY__RESULT_TYPE__FAILED] = true; |
- // set allColumnValues/showingColumnValues for CONFIG; |
- // by default, show results for all configs |
- $scope.allColumnValues[constants.KEY__EXTRACOLUMNS__CONFIG] = |
- $scope.columnSliceOf2DArray( |
- $scope.extraColumnHeaders[constants.KEY__EXTRACOLUMNS__CONFIG] |
- [constants.KEY__EXTRACOLUMNHEADERS__VALUES_AND_COUNTS], |
- 0); |
- $scope.showingColumnValues[constants.KEY__EXTRACOLUMNS__CONFIG] = {}; |
- $scope.toggleValuesInSet($scope.allColumnValues[constants.KEY__EXTRACOLUMNS__CONFIG], |
- $scope.showingColumnValues[constants.KEY__EXTRACOLUMNS__CONFIG]); |
- |
- // Associative array of partial string matches per category. |
- // TODO(epoger): Rename as columnValueMatch to be more consistent |
- // with allColumnValues/showingColumnValues ? |
- $scope.categoryValueMatch = {}; |
- $scope.categoryValueMatch[constants.KEY__EXTRACOLUMNS__BUILDER] = ""; |
- $scope.categoryValueMatch[constants.KEY__EXTRACOLUMNS__TEST] = ""; |
+ // Set up mapping for URL parameters. |
+ // parameter name -> copier object to load/save parameter value |
+ $scope.queryParameters.map = { |
+ 'resultsToLoad': $scope.queryParameters.copiers.simple, |
+ 'displayLimitPending': $scope.queryParameters.copiers.simple, |
+ 'showThumbnailsPending': $scope.queryParameters.copiers.simple, |
+ 'mergeIdenticalRowsPending': $scope.queryParameters.copiers.simple, |
+ 'imageSizePending': $scope.queryParameters.copiers.simple, |
+ 'sortColumnSubdict': $scope.queryParameters.copiers.simple, |
+ 'sortColumnKey': $scope.queryParameters.copiers.simple, |
+ }; |
+ // Some parameters are handled differently based on whether they USE_FREEFORM_FILTER. |
+ angular.forEach( |
+ $scope.filterableColumnNames, |
+ function(columnName) { |
+ if ($scope.extraColumnHeaders[columnName] |
+ [constants.KEY__EXTRACOLUMNHEADERS__USE_FREEFORM_FILTER]) { |
+ $scope.queryParameters.map[columnName] = |
+ $scope.queryParameters.copiers.columnStringMatch; |
+ } else { |
+ $scope.queryParameters.map[columnName] = |
+ $scope.queryParameters.copiers.showingColumnValuesSet; |
+ } |
+ } |
+ ); |
// If any defaults were overridden in the URL, get them now. |
$scope.queryParameters.load(); |
@@ -391,15 +425,15 @@ Loader.controller( |
} |
}, |
- 'categoryValueMatch': { |
+ 'columnStringMatch': { |
'load': function(nameValuePairs, name) { |
var value = nameValuePairs[name]; |
if (value) { |
- $scope.categoryValueMatch[name] = value; |
+ $scope.columnStringMatch[name] = value; |
} |
}, |
'save': function(nameValuePairs, name) { |
- nameValuePairs[name] = $scope.categoryValueMatch[name]; |
+ nameValuePairs[name] = $scope.columnStringMatch[name]; |
} |
}, |
@@ -419,25 +453,6 @@ Loader.controller( |
}; |
- // parameter name -> copier objects to load/save parameter value |
- $scope.queryParameters.map = { |
- 'resultsToLoad': $scope.queryParameters.copiers.simple, |
- 'displayLimitPending': $scope.queryParameters.copiers.simple, |
- 'showThumbnailsPending': $scope.queryParameters.copiers.simple, |
- 'mergeIdenticalRowsPending': $scope.queryParameters.copiers.simple, |
- 'imageSizePending': $scope.queryParameters.copiers.simple, |
- 'sortColumnSubdict': $scope.queryParameters.copiers.simple, |
- 'sortColumnKey': $scope.queryParameters.copiers.simple, |
- }; |
- $scope.queryParameters.map[constants.KEY__EXTRACOLUMNS__RESULT_TYPE] = |
- $scope.queryParameters.copiers.showingColumnValuesSet; |
- $scope.queryParameters.map[constants.KEY__EXTRACOLUMNS__BUILDER] = |
- $scope.queryParameters.copiers.categoryValueMatch; |
- $scope.queryParameters.map[constants.KEY__EXTRACOLUMNS__TEST] = |
- $scope.queryParameters.copiers.categoryValueMatch; |
- $scope.queryParameters.map[constants.KEY__EXTRACOLUMNS__CONFIG] = |
- $scope.queryParameters.copiers.showingColumnValuesSet; |
- |
// Loads all parameters into $scope from the URL query string; |
// any which are not found within the URL will keep their current value. |
$scope.queryParameters.load = function() { |
@@ -550,6 +565,30 @@ Loader.controller( |
$log.debug("renderStartTime: " + $scope.renderStartTime); |
$scope.displayLimit = $scope.displayLimitPending; |
$scope.mergeIdenticalRows = $scope.mergeIdenticalRowsPending; |
+ |
+ // For each USE_FREEFORM_FILTER column, populate showingColumnValues. |
+ // This is more efficient than applying the freeform filter within the |
+ // tight loop in removeHiddenImagePairs. |
+ angular.forEach( |
+ $scope.filterableColumnNames, |
+ function(columnName) { |
+ var columnHeader = $scope.extraColumnHeaders[columnName]; |
+ if (columnHeader[constants.KEY__EXTRACOLUMNHEADERS__USE_FREEFORM_FILTER]) { |
+ var columnStringMatch = $scope.columnStringMatch[columnName]; |
+ var showingColumnValues = {}; |
+ angular.forEach( |
+ $scope.allColumnValues[columnName], |
+ function(columnValue) { |
+ if (-1 != columnValue.indexOf(columnStringMatch)) { |
+ showingColumnValues[columnValue] = true; |
+ } |
+ } |
+ ); |
+ $scope.showingColumnValues[columnName] = showingColumnValues; |
+ } |
+ } |
+ ); |
+ |
// TODO(epoger): Every time we apply a filter, AngularJS creates |
// another copy of the array. Is there a way we can filter out |
// the imagePairs as they are displayed, rather than storing multiple |
@@ -569,9 +608,8 @@ Loader.controller( |
$filter("orderBy")( |
$filter("removeHiddenImagePairs")( |
$scope.imagePairs, |
+ $scope.filterableColumnNames, |
$scope.showingColumnValues, |
- $scope.categoryValueMatch[constants.KEY__EXTRACOLUMNS__BUILDER], |
- $scope.categoryValueMatch[constants.KEY__EXTRACOLUMNS__TEST], |
$scope.viewingTab |
), |
[$scope.getSortColumnValue, $scope.getSecondOrderSortValue], |
@@ -652,36 +690,40 @@ Loader.controller( |
} |
/** |
- * Set $scope.categoryValueMatch[name] = value, and update results. |
+ * Set $scope.columnStringMatch[name] = value, and update results. |
* |
* @param name |
* @param value |
*/ |
- $scope.setCategoryValueMatch = function(name, value) { |
- $scope.categoryValueMatch[name] = value; |
+ $scope.setColumnStringMatch = function(name, value) { |
+ $scope.columnStringMatch[name] = value; |
$scope.updateResults(); |
} |
/** |
- * Update $scope.showingColumnValues[columnName] so that ONLY entries with |
- * this columnValue are showing, and update the visible results. |
+ * Update $scope.showingColumnValues[columnName] and $scope.columnStringMatch[columnName] |
+ * so that ONLY entries with this columnValue are showing, and update the visible results. |
+ * (We update both of those, so we cover both freeform and checkbox filtered columns.) |
* |
* @param columnName |
* @param columnValue |
*/ |
$scope.showOnlyColumnValue = function(columnName, columnValue) { |
+ $scope.columnStringMatch[columnName] = columnValue; |
$scope.showingColumnValues[columnName] = {}; |
$scope.toggleValueInSet(columnValue, $scope.showingColumnValues[columnName]); |
$scope.updateResults(); |
} |
/** |
- * Update $scope.showingColumnValues[columnName] so that ALL entries are |
- * showing, and update the visible results. |
+ * Update $scope.showingColumnValues[columnName] and $scope.columnStringMatch[columnName] |
+ * so that ALL entries are showing, and update the visible results. |
+ * (We update both of those, so we cover both freeform and checkbox filtered columns.) |
* |
* @param columnName |
*/ |
$scope.showAllColumnValues = function(columnName) { |
+ $scope.columnStringMatch[columnName] = ""; |
$scope.showingColumnValues[columnName] = {}; |
$scope.toggleValuesInSet($scope.allColumnValues[columnName], |
$scope.showingColumnValues[columnName]); |