Skip to content

Commit

Permalink
Jkmarx/file browser refactor services (#1787)
Browse files Browse the repository at this point in the history
* Refactor main factory file according to style guide.

* Update main factory test and remove unneccessary variables.

* Update smaller services according to style guide. (#1788)

* Update smaller services according to style guide.

* Jkmarx/generalize attribute filter (#1790)

* Move uiSelectedFields to service.

* Add assay filter service.

* Move methods to assay-filters-ctrl

* Update initialize events.

* Add and update unit test for ctrl.

* Fix bug related to url query.

* Remove broadcast and use watcher.

* Remove console.

* Update unit test.

* Add ctrl comments.

* Fix scope and remove unneccessary variable.

* fix bug due to url query generation.

* Add comments and unit test.

* Add unit test and comments.
  • Loading branch information
jkmarx committed Jun 13, 2017
1 parent 40a2b94 commit acaf0c3
Show file tree
Hide file tree
Showing 21 changed files with 1,602 additions and 1,205 deletions.
212 changes: 212 additions & 0 deletions refinery/ui/source/js/file-browser/ctrls/assay-filters-ctrl.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
/**
* Assay Filters Ctrl
* @namespace AssayFiltersCtrl
* @desc Main ctrl for the assay filters, which can be used for a ui-grid
* displaying data from solr. Updates a files param to display data
* when user select filters or when in url query.
* @memberOf refineryFileBrowser
*/
(function () {
'use strict';

angular
.module('refineryFileBrowser')
.controller('AssayFiltersCtrl', AssayFiltersCtrl);

AssayFiltersCtrl.$inject = [
'$location',
'$scope',
'$timeout',
'_',
'assayFiltersService',
'filesLoadingService',
'fileParamService',
'resetGridService',
'selectedFilterService'
];

function AssayFiltersCtrl (
$location,
$scope,
$timeout,
_,
assayFiltersService,
filesLoadingService,
fileParamService,
resetGridService,
selectedFilterService
) {
var vm = this;
vm.attributeFilter = assayFiltersService.attributeFilter;
vm.analysisFilter = assayFiltersService.analysisFilter;
vm.attributeSelectionUpdate = attributeSelectionUpdate;
vm.queryKeys = Object.keys($location.search()); // used for pre-set filters in url query
vm.refreshSelectedFieldFromQuery = refreshSelectedFieldFromQuery;
/** Used by ui to select/deselect, attributes have an object of filter fields
* attributeInternalName: {fieldName: boolean, fieldName: boolean} */
vm.uiSelectedFields = {};
vm.updateFiltersFromUrlQuery = updateFiltersFromUrlQuery;
vm.updateFilterDOM = false;

activate();
/*
* ---------------------------------------------------------
* Methods
* ---------------------------------------------------------
*/
function activate () {
// Only on a new page load/new data set do we expect the attribute filters
// to be empty
if (_.isEmpty(assayFiltersService.attributeFilter)) {
// Requires waiting for the api response which should update the
// service's attribute filter and unbind.
var watchOnce = $scope.$watchCollection(
function () {
return assayFiltersService.attributeFilter;
},
function () {
// no need to update filters if there are no url queries
if (Object.keys($location.search()).length === 0) {
watchOnce(); // unbind watcher
}
if (!_.isEmpty(assayFiltersService.attributeFilter)) {
updateFiltersFromUrlQuery();
// drop panels in ui from query
vm.updateFilterDOM = true;
// update data in grid
resetGridService.setRefreshGridFlag(true);
watchOnce(); // unbind watcher
}
}
);
} else {
// Else is for soft loads (example tabbing)
// updates view model's selected attribute filters
angular.forEach(
selectedFilterService.attributeSelectedFields,
function (fieldArr, attributeInternalName) {
for (var i = 0; i < fieldArr.length; i++) {
if (_.isEmpty(vm.uiSelectedFields) ||
!vm.uiSelectedFields.hasOwnProperty(attributeInternalName)) {
vm.uiSelectedFields[attributeInternalName] = {};
}
vm.uiSelectedFields[attributeInternalName][fieldArr[i]] = true;
// update url with selected fields(filters)
var encodedAttribute = selectedFilterService
.stringifyAndEncodeAttributeObj(attributeInternalName, fieldArr[i]);
selectedFilterService.updateUrlQuery(encodedAttribute, true);
}
});
// for attribute filter directive, drop panels in query
vm.updateFilterDOM = true;
// updates url with the selected filters (ex: tabbing)
if (Object.keys($location.search()).length > 0) {
updateFiltersFromUrlQuery();
}
}
}

/**
* @name attributeSelectionUpdate
* @desc Used by ui, updates which attribute filters are selected and ui-grid data
* @memberOf refineryFileBrowser.AssayFiltersCtrl
* @param {string} internalName - solr name for attribute
* @param {string} field - value for the attributes
**/
function attributeSelectionUpdate (internalName, field) {
selectedFilterService.updateSelectedFilters(
vm.uiSelectedFields[internalName], internalName, field
);
fileParamService.setParamFilterAttribute(selectedFilterService.attributeSelectedFields);
// refresh grid
resetGridService.setRefreshGridFlag(true);
}

/**
* @name refreshSelectedFieldFromQuery
* @desc helper method, upon refresh/load add fields to select data objs from query
* @memberOf refineryFileBrowser.AssayFiltersCtrl
* @param {object} attributeObj - combination of attribute and analysis
* object from solr
**/
function refreshSelectedFieldFromQuery (attributeObj) {
// stringify/encode attributeInternalName:fieldName for url query comparison
angular.forEach(attributeObj.facetObj, function (fieldObj) {
var encodedField = selectedFilterService.stringifyAndEncodeAttributeObj(
attributeObj.internal_name,
fieldObj.name
);

if (vm.queryKeys.indexOf(encodedField) > -1) {
if (!vm.uiSelectedFields.hasOwnProperty(attributeObj.internal_name)) {
vm.uiSelectedFields[attributeObj.internal_name] = {};
}
vm.uiSelectedFields[attributeObj.internal_name][fieldObj.name] = true;
selectedFilterService.updateSelectedFilters(
vm.uiSelectedFields[attributeObj.internal_name],
attributeObj.internal_name,
fieldObj.name
);
}
});
}

/**
* @name updateFiltersFromUrlQuery
* @desc checks url for params to update the filter
* @memberOf refineryFileBrowser.AssayFiltersCtrl
**/
function updateFiltersFromUrlQuery () {
var allFilters = {};
// Merge attribute and analysis filter data obj
angular.copy(vm.attributeFilter, allFilters);
if (typeof vm.analysisFilter.Analysis !== 'undefined') {
angular.copy(vm.analysisFilter, allFilters.Analysis);
}

angular.forEach(allFilters, function (attributeObj) {
vm.refreshSelectedFieldFromQuery(attributeObj);
});
fileParamService.setParamFilterAttribute(
selectedFilterService.attributeSelectedFields
);
}

/*
* ---------------------------------------------------------
* Watchers
* ---------------------------------------------------------
*/
// When the filters are updated (ex when a new analysis runs)
$scope.$watchCollection(
function () {
return assayFiltersService.analysisFilter;
},
function () {
vm.analysisFilter = assayFiltersService.analysisFilter;
vm.attributeFilter = assayFiltersService.attributeFilter;
}
);

// Reset grid flag if set to true, grid, params, filters, and nodes resets
$scope.$watch(
function () {
return resetGridService.resetGridFlag;
},
function () {
if (resetGridService.resetGridFlag) {
// Have to set selected Fields in control due to service scope
angular.forEach(vm.uiSelectedFields, function (fieldsObj, attributeInternalName) {
angular.forEach(fieldsObj, function (value, fieldName) {
// initialize the uiSelectObj for easier indexing
vm.uiSelectedFields[attributeInternalName][fieldName] = false;
});
selectedFilterService.resetAttributeFilter(fieldsObj);
});
fileParamService.resetParamFilterAttribute = {};
resetGridService.setResetGridFlag(false);
}
}
);
}
})();
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
(function () {
'use strict';

describe('Controller: AssayFiltersCtrl', function () {
var ctrl;
var scope;
var service;

beforeEach(module('refineryApp'));
beforeEach(module('refineryFileBrowser'));
beforeEach(inject(function (
$controller,
$rootScope,
$window,
mockParamsFactory,
selectedFilterService
) {
scope = $rootScope.$new();
ctrl = $controller('AssayFiltersCtrl', {
$scope: scope
});
service = selectedFilterService;
$window.externalAssayUuid = mockParamsFactory.generateUuid();
}));

it('AssayFiltersCtrl ctrl should exist', function () {
expect(ctrl).toBeDefined();
});

it('Data & UI displays variables should exist for views', function () {
expect(ctrl.attributeFilter).toEqual({});
expect(ctrl.analysisFilter).toEqual({});
expect(ctrl.updateFilterDOM).toEqual(false);
expect(ctrl.uiSelectedFields).toEqual({});
});

it('QueryKeys to be set should exist for views', function () {
expect(ctrl.queryKeys).toEqual([]);
});

it('Test updateFiltersFromUrlQuery', function () {
ctrl.analysisFilter.Analysis = undefined;
ctrl.attributeFilter = {
Title: {
facet_obj: [
{
count: 129,
name: 'Device independent graphical display description'
}, {
count: 18,
name: 'Graphics Facilities at Ames Research Center'
}],
internal_name: 'Title_Characteristics_92_46_s'
}
};
service.attributeSelectedFields = {
REFINERY_ANALYSIS_UUID_92_46_s: ['N/A', 'Test Workflow', '3']
};
spyOn(scope, '$broadcast');
spyOn(ctrl, 'refreshSelectedFieldFromQuery');
expect(ctrl.refreshSelectedFieldFromQuery).not.toHaveBeenCalled();
ctrl.updateFiltersFromUrlQuery();
expect(ctrl.refreshSelectedFieldFromQuery).toHaveBeenCalled();
});

it('Test RefreshSelectedFieldFromQuery', function () {
var attributeObj = {
facetObj: [
{
count: 133,
name: 'March'
},
{
count: 24,
name: 'April'
}
],
internal_name: 'Month_Characteristics_92_46_s'
};
ctrl.queryKeys = ['{"Month_Characteristics_92_46_s":"March"}',
'{"Month_Characteristics_92_46_s":"April"}', +
'{"Author_Characteristics_82_36_s":"Conner"}'];

expect(service.attributeSelectedFields.Month_Characteristics_92_46_s)
.not.toBeDefined();
expect(ctrl.uiSelectedFields.Month_Characteristics_92_46_s).not.toBeDefined();
ctrl.refreshSelectedFieldFromQuery(attributeObj);
expect(ctrl.uiSelectedFields.Month_Characteristics_92_46_s.March).toEqual(true);
expect(ctrl.uiSelectedFields.Month_Characteristics_92_46_s.June).not.toBeDefined();
expect(service.attributeSelectedFields.Month_Characteristics_92_46_s)
.toEqual(['March', 'April']);
});
});
})();

0 comments on commit acaf0c3

Please sign in to comment.