From b38545f1d7f14fd55ad43e620f8f3a9012fa5ffb Mon Sep 17 00:00:00 2001 From: Terence Tuhinanshu Date: Fri, 25 Aug 2017 12:10:03 -0400 Subject: [PATCH 1/6] =?UTF-8?q?Fix=20field=20names:=20created=20=E2=86=92?= =?UTF-8?q?=20created=5Fat,=20updated=5Fat?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update these fields to match the API. --- src/mmw/js/src/data_catalog/models.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mmw/js/src/data_catalog/models.js b/src/mmw/js/src/data_catalog/models.js index b3a281ef6..9e5c6caa4 100644 --- a/src/mmw/js/src/data_catalog/models.js +++ b/src/mmw/js/src/data_catalog/models.js @@ -160,8 +160,8 @@ var Result = Backbone.Model.extend({ description: '', geom: null, // GeoJSON links: null, // Array - created: '', - updated: '', + created_at: '', + updated_at: '', show_detail: false // Show this result as the detail view? }, From 3299dc480f84446b794628d9a9d790490216e7fb Mon Sep 17 00:00:00 2001 From: Terence Tuhinanshu Date: Fri, 25 Aug 2017 16:18:58 -0400 Subject: [PATCH 2/6] Add support for search options In order to support a diverse set of behaviors for each catalog, we add an `options` query parameter which will take string values, and apply them if they match any supported options. --- src/mmw/apps/bigcz/views.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mmw/apps/bigcz/views.py b/src/mmw/apps/bigcz/views.py index 41f5a26d5..52512dd9b 100644 --- a/src/mmw/apps/bigcz/views.py +++ b/src/mmw/apps/bigcz/views.py @@ -32,6 +32,7 @@ def _do_search(request): 'to_date': parse_date(request.query_params.get('to_date')), 'from_date': parse_date(request.query_params.get('from_date')), 'bbox': request.query_params.get('bbox'), + 'options': request.query_params.get('options', ''), 'page': page, } From 6319ccfdef8e846291dc2c02ddbbaf4f48a8fd37 Mon Sep 17 00:00:00 2001 From: Terence Tuhinanshu Date: Fri, 25 Aug 2017 16:59:24 -0400 Subject: [PATCH 3/6] Exclude gridded services from CUAHSI by default These services will be rarely useful, so we exclude them by default. To include them, the user can specify `options=gridded` as a query parameter. --- src/mmw/apps/bigcz/clients/cuahsi/search.py | 35 ++++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/src/mmw/apps/bigcz/clients/cuahsi/search.py b/src/mmw/apps/bigcz/clients/cuahsi/search.py index ba2a6f79a..c0f1dc229 100644 --- a/src/mmw/apps/bigcz/clients/cuahsi/search.py +++ b/src/mmw/apps/bigcz/clients/cuahsi/search.py @@ -29,10 +29,35 @@ DATE_MAX = date(2100, 1, 1) DATE_FORMAT = '%m/%d/%Y' +GRIDDED = [ + 'NWS-WGRFC_Hourly_MPE', + 'NWS_WGRFC_Daily_MPE_Recent_Values', + 'LMRFC_Data', + 'GLDAS_NOAH', + 'NLDAS_FORA', + 'NLDAS_NOAH', + 'TRMM_3B42_7', +] client = Client(CATALOG_URL, timeout=settings.BIGCZ_CLIENT_TIMEOUT) +def filter_networkIDs(services, gridded=False): + """ + Transforms list of services to list of ServiceIDs, with respect to + given options. + + If gridded=False, then GRIDDED services will not be included. + + If no filters apply, we return an empty list to disable filtering. + """ + if not gridded: + return [str(s.ServiceID) for s in services + if s.NetworkName not in GRIDDED] + + return [] + + def parse_geom(record): lat = record['latitude'] lng = record['longitude'] @@ -173,7 +198,7 @@ def get_services_in_box(box): return [] -def get_series_catalog_in_box(box, from_date, to_date): +def get_series_catalog_in_box(box, from_date, to_date, networkIDs): from_date = from_date or DATE_MIN to_date = to_date or DATE_MAX @@ -183,7 +208,7 @@ def get_series_catalog_in_box(box, from_date, to_date): ymin=box.ymin, ymax=box.ymax, conceptKeyword='', - networkIDs='', + networkIDs=','.join(networkIDs), beginDate=from_date.strftime(DATE_FORMAT), endDate=to_date.strftime(DATE_FORMAT)) @@ -201,6 +226,7 @@ def search(**kwargs): bbox = kwargs.get('bbox') to_date = kwargs.get('to_date') from_date = kwargs.get('from_date') + gridded = 'gridded' in kwargs.get('options') if not bbox: raise ValidationError({ @@ -209,9 +235,10 @@ def search(**kwargs): box = BBox(bbox) world = BBox('-180,-90,180,90') - series = get_series_catalog_in_box(box, from_date, to_date) - series = group_series_by_location(series) services = get_services_in_box(world) + networkIDs = filter_networkIDs(services, gridded) + series = get_series_catalog_in_box(box, from_date, to_date, networkIDs) + series = group_series_by_location(series) results = sorted(parse_records(series, services), key=attrgetter('end_date'), reverse=True) From 5a76550fe8a18432346b1b570d1629e1adde1d6b Mon Sep 17 00:00:00 2001 From: Terence Tuhinanshu Date: Mon, 28 Aug 2017 13:21:34 -0400 Subject: [PATCH 4/6] Add support for search options in front-end Add `has_filters` and `options` attributes to Catalog model. If `has_filters` is true, then we show the UI section for filters, and wire up some handlers. When a new Catalog is created, we can optionally give it a collection of SearchOptions, each with an `id` and an `active` state. When making search requests, all Options that are `active` will be joined together into a comma-separated list and sent as `options=a,b,c` to the sever. --- src/mmw/js/src/data_catalog/models.js | 34 ++++++++++++++++++- .../data_catalog/templates/tabContent.html | 5 +++ src/mmw/js/src/data_catalog/views.js | 6 ++++ src/mmw/sass/pages/_data-catalog.scss | 4 +++ 4 files changed, 48 insertions(+), 1 deletion(-) diff --git a/src/mmw/js/src/data_catalog/models.js b/src/mmw/js/src/data_catalog/models.js index 9e5c6caa4..8633e5836 100644 --- a/src/mmw/js/src/data_catalog/models.js +++ b/src/mmw/js/src/data_catalog/models.js @@ -1,7 +1,7 @@ "use strict"; var $ = require('jquery'), - _ = require('underscore'), + _ = require('lodash'), Backbone = require('../../shim/backbone'), turfIntersect = require('turf-intersect'), App = require('../app'), @@ -11,6 +11,17 @@ var REQUEST_TIMED_OUT_CODE = 408; var DESCRIPTION_MAX_LENGTH = 100; var PAGE_SIZE = settings.get('data_catalog_page_size'); +var SearchOption = Backbone.Model.extend({ + defaults: { + id: '', + active: false, + }, +}); + +var SearchOptions = Backbone.Collection.extend({ + model: SearchOption, +}); + var Catalog = Backbone.Model.extend({ defaults: { id: '', @@ -24,6 +35,8 @@ var Catalog = Backbone.Model.extend({ active: false, results: null, // Results collection resultCount: 0, + has_filters: false, // If local filters apply + options: null, // SearchOptions collection is_pageable: true, page: 1, error: '', @@ -35,6 +48,14 @@ var Catalog = Backbone.Model.extend({ this.get('results').on('change:show_detail', function() { self.set('detail_result', self.get('results').getDetail()); }); + + // Initialize and listen to options for changes + if (this.get('options') === null) { + this.set({ options: new SearchOptions() }); + } + this.get('options').on('change:active', function() { + self.startSearch(1); + }); }, searchIfNeeded: function(query, fromDate, toDate, bbox) { @@ -76,6 +97,9 @@ var Catalog = Backbone.Model.extend({ startSearch: function(page) { var lastPage = Math.ceil(this.get('resultCount') / PAGE_SIZE), thisPage = parseInt(page) || 1, + has_filters = this.get('has_filters'), + options = this.get('options'), + id = function(option) { return option.id; }, data = { catalog: this.id, query: this.get('query'), @@ -88,6 +112,12 @@ var Catalog = Backbone.Model.extend({ _.assign(data, { page: thisPage }); } + if (has_filters && options) { + _.assign(data, { + options: options.where({ active: true }).map(id).join(',') + }); + } + this.set('loading', true); this.set('error', false); @@ -260,6 +290,8 @@ var SearchForm = Backbone.Model.extend({ }); module.exports = { + SearchOption: SearchOption, + SearchOptions: SearchOptions, Catalog: Catalog, Catalogs: Catalogs, Result: Result, diff --git a/src/mmw/js/src/data_catalog/templates/tabContent.html b/src/mmw/js/src/data_catalog/templates/tabContent.html index d372b4c47..8cd74f974 100644 --- a/src/mmw/js/src/data_catalog/templates/tabContent.html +++ b/src/mmw/js/src/data_catalog/templates/tabContent.html @@ -1,3 +1,8 @@ +{% if has_filters %} +
+
+{% endif %} + {% if description %}
{{ description }} diff --git a/src/mmw/js/src/data_catalog/views.js b/src/mmw/js/src/data_catalog/views.js index fa0d7c968..df6fed250 100644 --- a/src/mmw/js/src/data_catalog/views.js +++ b/src/mmw/js/src/data_catalog/views.js @@ -331,6 +331,8 @@ var TabContentView = Marionette.LayoutView.extend({ }, onShow: function() { + var model = this.model; + this.toggleActiveClass(); this.resultRegion.show(new ResultsView({ @@ -347,6 +349,10 @@ var TabContentView = Marionette.LayoutView.extend({ model: this.model, })); } + + if (model.get('has_filters')) { + // TODO Generalize for different types of filters + } }, toggleActiveClass: function() { diff --git a/src/mmw/sass/pages/_data-catalog.scss b/src/mmw/sass/pages/_data-catalog.scss index 75f8c568b..6e11a0eb6 100644 --- a/src/mmw/sass/pages/_data-catalog.scss +++ b/src/mmw/sass/pages/_data-catalog.scss @@ -40,6 +40,10 @@ } } + .filters-region { + padding: 6px 10px 0 10px; + } + .result-region { height: auto !important; width: auto !important; From 2daa2155b2e9dbab8b95f09f3c924e806d251e89 Mon Sep 17 00:00:00 2001 From: Terence Tuhinanshu Date: Mon, 28 Aug 2017 13:22:57 -0400 Subject: [PATCH 5/6] Add gridded checkbox option to CUAHSI When checked, we send the 'gridded' option, fetching results that include the gridded services. This checkbox will be unchecked by default. --- src/mmw/js/src/data_catalog/controllers.js | 3 ++- src/mmw/js/src/data_catalog/templates/tabContent.html | 8 ++++++++ src/mmw/js/src/data_catalog/views.js | 7 +++++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/mmw/js/src/data_catalog/controllers.js b/src/mmw/js/src/data_catalog/controllers.js index 6d404734e..d29cb9146 100644 --- a/src/mmw/js/src/data_catalog/controllers.js +++ b/src/mmw/js/src/data_catalog/controllers.js @@ -38,7 +38,8 @@ var DataCatalogController = { new models.Catalog({ id: 'cuahsi', name: 'WDC', - description: 'Optional catalog description here...', + has_filters: true, + options: new models.SearchOptions([{ id: 'gridded' }]), is_pageable: false, results: new models.Results(null, { catalog: 'cuahsi' }), }) diff --git a/src/mmw/js/src/data_catalog/templates/tabContent.html b/src/mmw/js/src/data_catalog/templates/tabContent.html index 8cd74f974..d03183299 100644 --- a/src/mmw/js/src/data_catalog/templates/tabContent.html +++ b/src/mmw/js/src/data_catalog/templates/tabContent.html @@ -1,5 +1,13 @@ {% if has_filters %}
+ {% if id == 'cuahsi' %} +
+ +
+ {% endif %}
{% endif %} diff --git a/src/mmw/js/src/data_catalog/views.js b/src/mmw/js/src/data_catalog/views.js index df6fed250..2f232e45a 100644 --- a/src/mmw/js/src/data_catalog/views.js +++ b/src/mmw/js/src/data_catalog/views.js @@ -352,6 +352,13 @@ var TabContentView = Marionette.LayoutView.extend({ if (model.get('has_filters')) { // TODO Generalize for different types of filters + if (model.id === 'cuahsi') { + $('input#gridded').change(function() { + model.get('options') + .findWhere({ id: 'gridded' }) + .set({ active: this.checked }); + }); + } } }, From a7222e3417c8bdf3940903b3ed268dbddd58811a Mon Sep 17 00:00:00 2001 From: Terence Tuhinanshu Date: Mon, 28 Aug 2017 13:24:01 -0400 Subject: [PATCH 6/6] Lint --- src/mmw/js/src/data_catalog/views.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/mmw/js/src/data_catalog/views.js b/src/mmw/js/src/data_catalog/views.js index 2f232e45a..52ed15f46 100644 --- a/src/mmw/js/src/data_catalog/views.js +++ b/src/mmw/js/src/data_catalog/views.js @@ -336,17 +336,17 @@ var TabContentView = Marionette.LayoutView.extend({ this.toggleActiveClass(); this.resultRegion.show(new ResultsView({ - collection: this.model.get('results'), - catalog: this.model.id, + collection: model.get('results'), + catalog: model.id, })); this.errorRegion.show(new ErrorView({ - model: this.model, + model: model, })); - if (this.model.get('is_pageable')) { + if (model.get('is_pageable')) { this.pagerRegion.show(new PagerView({ - model: this.model, + model: model, })); }