From 4ca7a344a02dbfef040b3f1433ba564ed1b5cd35 Mon Sep 17 00:00:00 2001 From: Stephen Kilbourn Date: Tue, 24 Oct 2023 19:34:14 -0600 Subject: [PATCH 01/11] WIP: add param on submit and clear on reset --- src/components/SearchFilter.vue | 60 +++++++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 3 deletions(-) diff --git a/src/components/SearchFilter.vue b/src/components/SearchFilter.vue index c359eb8bc..34bc5c178 100644 --- a/src/components/SearchFilter.vue +++ b/src/components/SearchFilter.vue @@ -111,6 +111,7 @@ {{ $t('submit') }} + print query {{ $t('reset') }} @@ -138,6 +139,17 @@ import CqlLogicalOperator from '../models/cql2/operators/logical'; import { CqlEqual } from '../models/cql2/operators/comparison'; import { stacRequest } from '../store/utils'; +const allowedQueryParams = [ + 'q', + 'datetime', + 'bbox', + 'limit', + 'ids', + 'collections', + 'sortby', + 'filters', + 'itemsPerPage']; + function getQueryDefaults() { return { q: [], @@ -151,6 +163,10 @@ function getQueryDefaults() { }; } +function getQueryValues() { + return {...getQueryDefaults()}; +} + function getDefaults() { return { sortOrder: 1, @@ -202,6 +218,10 @@ export default { value: { type: Object, default: () => ({}) + }, + searchLink: { + type: Object, + default: () => ({}) } }, data() { @@ -297,7 +317,7 @@ export default { immediate: true, deep: true, handler(value) { - let query = Object.assign(getQueryDefaults(), value); + let query = Object.assign(getQueryValues(), value); if (Array.isArray(query.datetime)) { query.datetime = query.datetime.map(Utils.dateFromUTC); } @@ -312,7 +332,8 @@ export default { }); } } - } + }, + $route() {}, }, beforeCreate() { formId++; @@ -494,10 +515,12 @@ export default { let filters = this.buildFilter(); this.$set(this.query, 'filters', filters); this.$emit('input', this.query, false); + this.updateQueryParams(); }, async onReset() { Object.assign(this, getDefaults()); this.$emit('input', {}, true); + this.removeQueryParams(); }, setLimit(limit) { limit = Number.parseInt(limit, 10); @@ -575,8 +598,39 @@ export default { else { return null; } + }, + async updateQueryParams() { + const currentParams = this.$route.query; + console.log('current parameters in url: ', JSON.stringify(currentParams)); + const currentQuery = this.query; + const newQuery = {}; + for (const [key, value] of Object.entries(currentQuery)) { + if ( allowedQueryParams.includes(key) && value && value.length) { + newQuery[key] = value; + } + } + const params = {...currentParams, ...newQuery}; + console.log('my new query: ', JSON.stringify(newQuery)) + if (JSON.stringify(currentParams) !== JSON.stringify(params)) { + this.$router.replace({query: {...params}}); + } + }, + removeQueryParams() { + this.$router.replace({name: "search"}); + }, + getQueryParams() { + const currentParams = this.$route.query; + // remove invalid query params + const cleanParams = {}; + for (const [key, value] of Object.entries(currentParams)) { + if ( allowedQueryParams.includes(key) && value && value.length) { + cleanParams[key]=value; + } + } + console.log(cleanParams); + return cleanParams; } - } + }, }; From 03efc9a06f120f8e66dddc86c2a71d44c5eb04a4 Mon Sep 17 00:00:00 2001 From: Stephen Kilbourn Date: Thu, 2 Nov 2023 16:48:44 -0600 Subject: [PATCH 02/11] implement loading filter values from params --- src/components/SearchFilter.vue | 78 +++++++++++++++++++-------------- 1 file changed, 46 insertions(+), 32 deletions(-) diff --git a/src/components/SearchFilter.vue b/src/components/SearchFilter.vue index 34bc5c178..8a8e6468b 100644 --- a/src/components/SearchFilter.vue +++ b/src/components/SearchFilter.vue @@ -111,7 +111,6 @@ {{ $t('submit') }} - print query {{ $t('reset') }} @@ -164,14 +163,29 @@ function getQueryDefaults() { } function getQueryValues() { - return {...getQueryDefaults()}; + const searchURL = new URL(window.location); + const params = searchURL.searchParams; + const urlParams = {}; + const arrayParams = ['bbox', 'collections', 'ids'] + allowedQueryParams.forEach((allowedParam) => { + if (params.has(allowedParam)) { + if( arrayParams.includes(allowedParam)) { + urlParams[allowedParam] = params.get(allowedParam).split(','); + } else { + urlParams[allowedParam] = params.get(allowedParam); + } + } + }); + + const combinedQuery = { ...getQueryDefaults(), ...urlParams}; + return combinedQuery; } function getDefaults() { return { sortOrder: 1, sortTerm: null, - provideBBox: false, + provideBBox: true, query: getQueryDefaults(), filtersAndOr: 'and', filters: [], @@ -179,6 +193,24 @@ function getDefaults() { }; } +function updateQueryString(key, value) { + console.log(`update called for ${key}: ${value}`); + // remove parameters if new value is null + const searchURL = new URL(window.location); + if (value === null || value.length === 0 || value.value === null) { + searchURL.searchParams.delete(key); + window.history.pushState({}, '', searchURL); + return; + } + if(key === 'sortTerm') { + searchURL.searchParams.set(key, value.value); + } else { + searchURL.searchParams.set(key, value); + } + + window.history.pushState({}, '', searchURL); +} + let formId = 0; export default { @@ -486,9 +518,11 @@ export default { }, sortFieldSet(value) { this.sortTerm = value; + updateQueryString('sortTerm', value); }, sortDirectionSet(value) { this.sortOrder = value; + updateQueryString('sortOrder', value); }, buildFilter() { if (this.filters.length === 0) { @@ -515,7 +549,6 @@ export default { let filters = this.buildFilter(); this.$set(this.query, 'filters', filters); this.$emit('input', this.query, false); - this.updateQueryParams(); }, async onReset() { Object.assign(this, getDefaults()); @@ -531,15 +564,18 @@ export default { limit = null; } this.$set(this.query, 'limit', limit); + updateQueryString('limit', limit); }, addSearchTerm(term) { if (!Utils.hasText(term)) { return; } this.query.q.push(term); + updateQueryString('q', term); }, setSearchTerms(terms) { this.$set(this.query, 'q', terms); + updateQueryString('q', terms); }, setBBox(bounds) { let bbox = null; @@ -560,6 +596,7 @@ export default { } } this.$set(this.query, 'bbox', bbox); + updateQueryString('bbox', bbox); }, setDateTime(datetime) { if (datetime.find(dt => dt instanceof Date)) { @@ -569,6 +606,7 @@ export default { datetime = null; } this.$set(this.query, 'datetime', datetime); + updateQueryString('datetime', datetime); }, addCollection(collection) { if (!this.collectionSelectOptions.taggable) { @@ -579,16 +617,20 @@ export default { this.selectedCollections.push(opt); this.collections.push(opt); this.query.collections.push(collection); + updateQueryString('collections', collection); }, setCollections(collections) { this.selectedCollections = collections; this.$set(this.query, 'collections', collections.map(c => c.value)); + updateQueryString('collections', collections.map(c => c.value)); }, addId(id) { this.query.ids.push(id); + updateQueryString('ids', id); }, setIds(ids) { this.$set(this.query, 'ids', ids); + updateQueryString('ids', ids); }, formatSort() { if (this.sortTerm && this.sortTerm.value && this.sortOrder) { @@ -599,37 +641,9 @@ export default { return null; } }, - async updateQueryParams() { - const currentParams = this.$route.query; - console.log('current parameters in url: ', JSON.stringify(currentParams)); - const currentQuery = this.query; - const newQuery = {}; - for (const [key, value] of Object.entries(currentQuery)) { - if ( allowedQueryParams.includes(key) && value && value.length) { - newQuery[key] = value; - } - } - const params = {...currentParams, ...newQuery}; - console.log('my new query: ', JSON.stringify(newQuery)) - if (JSON.stringify(currentParams) !== JSON.stringify(params)) { - this.$router.replace({query: {...params}}); - } - }, removeQueryParams() { this.$router.replace({name: "search"}); }, - getQueryParams() { - const currentParams = this.$route.query; - // remove invalid query params - const cleanParams = {}; - for (const [key, value] of Object.entries(currentParams)) { - if ( allowedQueryParams.includes(key) && value && value.length) { - cleanParams[key]=value; - } - } - console.log(cleanParams); - return cleanParams; - } }, }; From 94318fba2c64aec1ea7d153c02c4291227a1708e Mon Sep 17 00:00:00 2001 From: Stephen Kilbourn Date: Fri, 3 Nov 2023 10:20:08 -0600 Subject: [PATCH 03/11] check & show geospatial map based on url param --- src/components/SearchFilter.vue | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/components/SearchFilter.vue b/src/components/SearchFilter.vue index 8a8e6468b..5634bec2a 100644 --- a/src/components/SearchFilter.vue +++ b/src/components/SearchFilter.vue @@ -27,7 +27,7 @@ - {{ $t('search.filterBySpatialExtent') }} + {{ $t('search.filterBySpatialExtent') }} @@ -181,11 +181,17 @@ function getQueryValues() { return combinedQuery; } +function bboxProvided() { + const searchURL = new URL(window.location); + const hasBbox = searchURL.searchParams.has('bbox'); + return hasBbox; + } + function getDefaults() { return { sortOrder: 1, sortTerm: null, - provideBBox: true, + provideBBox: bboxProvided(), query: getQueryDefaults(), filtersAndOr: 'and', filters: [], From dcec953954e2fe690d9890e6329bb01517e04994 Mon Sep 17 00:00:00 2001 From: Stephen Kilbourn Date: Fri, 3 Nov 2023 13:12:49 -0600 Subject: [PATCH 04/11] overwrite defaults with url params --- src/components/SearchFilter.vue | 38 ++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/src/components/SearchFilter.vue b/src/components/SearchFilter.vue index 5634bec2a..25824d72b 100644 --- a/src/components/SearchFilter.vue +++ b/src/components/SearchFilter.vue @@ -166,7 +166,7 @@ function getQueryValues() { const searchURL = new URL(window.location); const params = searchURL.searchParams; const urlParams = {}; - const arrayParams = ['bbox', 'collections', 'ids'] + const arrayParams = ['bbox', 'collections', 'ids']; allowedQueryParams.forEach((allowedParam) => { if (params.has(allowedParam)) { if( arrayParams.includes(allowedParam)) { @@ -191,7 +191,7 @@ function getDefaults() { return { sortOrder: 1, sortTerm: null, - provideBBox: bboxProvided(), + provideBBox: false, query: getQueryDefaults(), filtersAndOr: 'and', filters: [], @@ -199,8 +199,35 @@ function getDefaults() { }; } +function overwriteDefaults() { + const searchURL = new URL(window.location); + const params = searchURL.searchParams; + const permittedOverwrites = ['sortOrder', 'sortTerm', 'provideBBox']; + const numericParams=['sortOrder', 'limit']; + const defaultOverwrites = { + provideBBox: bboxProvided() + }; + + + permittedOverwrites.forEach((allowedValue) => { + if(params.has(allowedValue)) { + // sortTerm is a json object, not a string + if (allowedValue === 'sortTerm') { + defaultOverwrites[allowedValue] = JSON.parse(params.get(allowedValue)); + } + else if(numericParams.includes(allowedValue)) { + defaultOverwrites[allowedValue] = parseInt(params.get(allowedValue)); + } else { + defaultOverwrites[allowedValue] = params.get(allowedValue); + } + } + }); + + return {...getDefaults(), ...defaultOverwrites}; + +} + function updateQueryString(key, value) { - console.log(`update called for ${key}: ${value}`); // remove parameters if new value is null const searchURL = new URL(window.location); if (value === null || value.length === 0 || value.value === null) { @@ -208,8 +235,9 @@ function updateQueryString(key, value) { window.history.pushState({}, '', searchURL); return; } + // sortTerm is an object if(key === 'sortTerm') { - searchURL.searchParams.set(key, value.value); + searchURL.searchParams.set(key, JSON.stringify(value)); } else { searchURL.searchParams.set(key, value); } @@ -272,7 +300,7 @@ export default { collections: [], collectionsLoadingTimer: null, additionalCollectionCount: 0 - }, getDefaults()); + }, overwriteDefaults()); }, computed: { ...mapState(['itemsPerPage', 'uiLanguage']), From 8d6af73e05be4c33241d209f2d31ad52940c1712 Mon Sep 17 00:00:00 2001 From: Stephen Kilbourn Date: Fri, 3 Nov 2023 15:28:33 -0600 Subject: [PATCH 05/11] submit form on load if query params present --- src/components/SearchFilter.vue | 36 ++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/src/components/SearchFilter.vue b/src/components/SearchFilter.vue index 25824d72b..35909ee3c 100644 --- a/src/components/SearchFilter.vue +++ b/src/components/SearchFilter.vue @@ -110,7 +110,7 @@ - {{ $t('submit') }} + {{ $t('submit') }} {{ $t('reset') }} @@ -138,17 +138,6 @@ import CqlLogicalOperator from '../models/cql2/operators/logical'; import { CqlEqual } from '../models/cql2/operators/comparison'; import { stacRequest } from '../store/utils'; -const allowedQueryParams = [ - 'q', - 'datetime', - 'bbox', - 'limit', - 'ids', - 'collections', - 'sortby', - 'filters', - 'itemsPerPage']; - function getQueryDefaults() { return { q: [], @@ -167,10 +156,25 @@ function getQueryValues() { const params = searchURL.searchParams; const urlParams = {}; const arrayParams = ['bbox', 'collections', 'ids']; + const allowedQueryParams = [ + 'q', + 'datetime', + 'bbox', + 'limit', + 'ids', + 'collections', + 'sortby', + 'filters', + 'itemsPerPage']; + allowedQueryParams.forEach((allowedParam) => { if (params.has(allowedParam)) { if( arrayParams.includes(allowedParam)) { urlParams[allowedParam] = params.get(allowedParam).split(','); + // bbox bust be array of numbers + if(allowedParam === 'bbox') { + urlParams[allowedParam] = urlParams[allowedParam].map(Number); + } } else { urlParams[allowedParam] = params.get(allowedParam); } @@ -428,6 +432,14 @@ export default { } Promise.all(promises).finally(() => this.loaded = true); }, + mounted() { + // submit form if loaded with url params + const searchURL = new URL(window.location); + const params = searchURL.searchParams; + if(params.size > 1) { + document.getElementById("submitBtn").click(); + } + }, methods: { resetSearchCollection() { clearTimeout(this.collectionsLoadingTimer); From 01bd9da6ad39f8b708cf47d5b34acab9e47343cf Mon Sep 17 00:00:00 2001 From: Stephen Kilbourn Date: Wed, 8 Nov 2023 17:03:50 -0700 Subject: [PATCH 06/11] allow bbox input via text or map --- src/components/SearchFilter.vue | 90 +++++++++++++++++++++++++++++++-- src/locales/en/texts.json | 4 ++ 2 files changed, 90 insertions(+), 4 deletions(-) diff --git a/src/components/SearchFilter.vue b/src/components/SearchFilter.vue index 35909ee3c..36b73ad70 100644 --- a/src/components/SearchFilter.vue +++ b/src/components/SearchFilter.vue @@ -28,7 +28,80 @@ {{ $t('search.filterBySpatialExtent') }} - + @@ -118,7 +191,7 @@ diff --git a/src/components/SearchFilter.vue b/src/components/SearchFilter.vue index 1ee849bde..c6b7562b1 100644 --- a/src/components/SearchFilter.vue +++ b/src/components/SearchFilter.vue @@ -40,66 +40,7 @@ {{ $t('search.defineBbox.text') }} - - - - - - - - - - - - - - - - - - - - - - - - + @@ -196,6 +137,7 @@ import Multiselect from 'vue-multiselect'; import { mapGetters, mapState } from "vuex"; import refParser from '@apidevtools/json-schema-ref-parser'; +import BBoxEntry from './BBoxEntry.vue'; import Utils, { schemaMediaType } from '../utils'; import { ogcQueryables } from "../rels"; @@ -339,6 +281,7 @@ export default { name: 'SearchFilter', components: { BBadge, + BBoxEntry, BDropdown, BDropdownItem, BForm, From 71df2ed6ecc644c5988a0ddfa7940243d1dc8ae9 Mon Sep 17 00:00:00 2001 From: Stephen Kilbourn Date: Thu, 9 Nov 2023 16:11:11 -0700 Subject: [PATCH 09/11] fix linting error --- src/components/SearchFilter.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/SearchFilter.vue b/src/components/SearchFilter.vue index c6b7562b1..619d88991 100644 --- a/src/components/SearchFilter.vue +++ b/src/components/SearchFilter.vue @@ -266,7 +266,7 @@ function updateUrlParamString(key, value) { if(key === 'sortTerm') { searchURL.searchParams.set(key, JSON.stringify(value)); } else if(key ==='datetime') { - const dateFormattedForPicker = `${JSON.stringify(value['0'])}/${JSON.stringify(value['1'])}` + const dateFormattedForPicker = `${JSON.stringify(value['0'])}/${JSON.stringify(value['1'])}`; searchURL.searchParams.set(key, dateFormattedForPicker.replaceAll('"','')); } else { searchURL.searchParams.set(key, value); From 37f9d6b90311172f75fb888cc0ff4508f098cbd8 Mon Sep 17 00:00:00 2001 From: Stephen Kilbourn Date: Fri, 10 Nov 2023 10:27:32 -0700 Subject: [PATCH 10/11] remove BBEntry component for this pr --- src/components/BBoxEntry.vue | 85 --------------------------------- src/components/SearchFilter.vue | 23 ++------- src/locales/en/texts.json | 4 -- 3 files changed, 3 insertions(+), 109 deletions(-) delete mode 100644 src/components/BBoxEntry.vue diff --git a/src/components/BBoxEntry.vue b/src/components/BBoxEntry.vue deleted file mode 100644 index fe82cd867..000000000 --- a/src/components/BBoxEntry.vue +++ /dev/null @@ -1,85 +0,0 @@ - - - diff --git a/src/components/SearchFilter.vue b/src/components/SearchFilter.vue index 619d88991..05bb98d12 100644 --- a/src/components/SearchFilter.vue +++ b/src/components/SearchFilter.vue @@ -27,22 +27,8 @@ - {{ $t('search.filterBySpatialExtent') }} - + {{ $t('search.filterBySpatialExtent') }} + @@ -132,12 +118,11 @@