diff --git a/src/reducers/provider-state-updaters.ts b/src/reducers/provider-state-updaters.ts index 01dc77944e..e40b5a12c4 100644 --- a/src/reducers/provider-state-updaters.ts +++ b/src/reducers/provider-state-updaters.ts @@ -19,7 +19,7 @@ // THE SOFTWARE. import {withTask} from 'react-palm/tasks'; -import {default as Console} from 'global/console'; +import Console from 'global/console'; import {generateHashId, getError, isPlainObject, toArray} from '../utils/utils'; import { EXPORT_FILE_TO_CLOUD_TASK, diff --git a/src/schemas/vis-state-schema.ts b/src/schemas/vis-state-schema.ts index 7d8683acfd..227233a754 100644 --- a/src/schemas/vis-state-schema.ts +++ b/src/schemas/vis-state-schema.ts @@ -20,7 +20,7 @@ import pick from 'lodash.pick'; import {VERSIONS} from './versions'; -import {isValidFilterValue} from 'utils/filter-utils'; +import {isFilterValidToSave} from 'utils/filter-utils'; import {LAYER_VIS_CONFIGS} from '@kepler.gl/constants'; import Schema from './schema'; import cloneDeep from 'lodash.clonedeep'; @@ -610,8 +610,7 @@ export class FilterSchemaV0 extends Schema { save(filters: Filter[]): {filters: SavedFilter[]} { return { filters: filters - // @ts-expect-error should pass type of the layer instead? - .filter(isValidFilterValue) + .filter(isFilterValidToSave) .map(filter => this.savePropertiesOrApplySchema(filter).filters) }; } diff --git a/src/utils/dom-to-image.ts b/src/utils/dom-to-image.ts index 027b40f5f4..9aae60a7c9 100644 --- a/src/utils/dom-to-image.ts +++ b/src/utils/dom-to-image.ts @@ -25,7 +25,7 @@ import window from 'global/window'; import document from 'global/document'; -import console from 'global/console'; +import Console from 'global/console'; import svgToMiniDataURI from 'mini-svg-data-uri'; import {IMAGE_EXPORT_ERRORS} from '@kepler.gl/constants'; import { @@ -361,8 +361,8 @@ function newFontFaces() { // Handle any error that occurred in any of the previous // promises in the chain. stylesheet failed to load should not stop // the process, hence result in only a warning, instead of reject - console.warn(IMAGE_EXPORT_ERRORS.styleSheet, sheet.href); - console.log(err); + Console.warn(IMAGE_EXPORT_ERRORS.styleSheet, sheet.href); + Console.log(err); return; }); } @@ -431,7 +431,7 @@ function newFontFaces() { try { rules = sheet.rules || sheet.cssRules; } catch (e) { - console.log(`'Can't read the css rules of: ${sheet.href}`, e); + Console.log(`'Can't read the css rules of: ${sheet.href}`, e); return; } @@ -439,11 +439,11 @@ function newFontFaces() { try { asArray(rules || []).forEach(cssRules.push.bind(cssRules)); } catch (e) { - console.log(`Error while reading CSS rules from ${sheet.href}`, e); + Console.log(`Error while reading CSS rules from ${sheet.href}`, e); return; } } else { - console.log('getCssRules can not find cssRules'); + Console.log('getCssRules can not find cssRules'); return; } }); diff --git a/src/utils/dom-utils.ts b/src/utils/dom-utils.ts index 5e2b0c8e1a..3f0df9d7c3 100644 --- a/src/utils/dom-utils.ts +++ b/src/utils/dom-utils.ts @@ -18,7 +18,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -import console from 'global/console'; +import Console from 'global/console'; import window from 'global/window'; import document from 'global/document'; import {IMAGE_EXPORT_ERRORS} from '@kepler.gl/constants'; @@ -166,7 +166,7 @@ export function makeImage(uri) { }; image.onerror = err => { const message = IMAGE_EXPORT_ERRORS.dataUri; - console.log(uri); + Console.log(uri); // error is an Event Object // https://www.w3schools.com/jsref/obj_event.asp reject({event: err, message}); @@ -347,7 +347,7 @@ export function getAndEncode(url, options) { } function fail(message) { - console.error(message); + Console.error(message); resolve(''); } }); diff --git a/src/utils/filter-utils.ts b/src/utils/filter-utils.ts index af8f9c8521..8f296fc3f1 100644 --- a/src/utils/filter-utils.ts +++ b/src/utils/filter-utils.ts @@ -20,7 +20,7 @@ import {ascending, extent, histogram as d3Histogram, ticks} from 'd3-array'; import keyMirror from 'keymirror'; -import {console as Console} from 'global/console'; +import Console from 'global/console'; import get from 'lodash.get'; import isEqual from 'lodash.isequal'; @@ -240,7 +240,7 @@ export function validateFilter( const filterDataId = toArray(filter.dataId); const filterDatasetIndex = filterDataId.indexOf(dataset.id); - if (filterDatasetIndex < 0) { + if (filterDatasetIndex < 0 || !toArray(filter.name)[filterDatasetIndex]) { // the current filter is not mapped against the current dataset return failed; } @@ -829,6 +829,20 @@ export function getTimeWidgetHintFormatter(domain: [number, number]): string | u /** * Sanity check on filters to prepare for save + * @type {typeof import('./filter-utils').isFilterValidToSave} + */ +export function isFilterValidToSave(filter: any): boolean { + return ( + filter?.type && + Array.isArray(filter?.name) && + filter?.name.length && + isValidFilterValue(filter?.type, filter?.value) + ); +} + +/** + * Sanity check on filters to prepare for save + * @type {typeof import('./filter-utils').isValidFilterValue} */ /* eslint-disable complexity */ export function isValidFilterValue(type: string | null, value: any): boolean { diff --git a/src/utils/locale-utils.ts b/src/utils/locale-utils.ts index 1d4677d8c7..8c6730b885 100644 --- a/src/utils/locale-utils.ts +++ b/src/utils/locale-utils.ts @@ -19,7 +19,7 @@ // THE SOFTWARE. import {isObject} from './utils'; -import {console as Console} from 'global/console'; +import Console from 'global/console'; // Flat messages since react-intl does not seem to support nested structures // Adapted from https://medium.com/siren-apparel-press/internationalization-and-localization-of-sirenapparel-eu-sirenapparel-us-and-sirenapparel-asia-ddee266066a2 diff --git a/src/utils/table-utils/kepler-table.ts b/src/utils/table-utils/kepler-table.ts index 10b2f14091..973a20f7e3 100644 --- a/src/utils/table-utils/kepler-table.ts +++ b/src/utils/table-utils/kepler-table.ts @@ -18,7 +18,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -import {console as Console} from 'global/console'; +import Console from 'global/console'; import {TRIP_POINT_FIELDS, SORT_ORDER, ALL_FIELD_TYPES, SCALE_TYPES} from '@kepler.gl/constants'; import {ascending, descending} from 'd3-array'; diff --git a/test/node/reducers/vis-state-merger-test.js b/test/node/reducers/vis-state-merger-test.js index 0819987b31..e52eb8c09d 100644 --- a/test/node/reducers/vis-state-merger-test.js +++ b/test/node/reducers/vis-state-merger-test.js @@ -249,6 +249,45 @@ test('VisStateMerger.v1 -> mergeFilters -> toWorkingState', t => { t.end(); }); +test('VisStateMerger.v1 -> mergeFilters -> empty filter', t => { + const savedConfig = cloneDeep(savedStateV1); + // set an empty filter + savedConfig.config.config.visState.filters[0].name = []; + const oldState = cloneDeep(InitialState); + + const oldVisState = oldState.visState; + const oldFilters = [...oldState.visState.filters]; + + const parsedConfig = SchemaManager.parseSavedConfig(savedConfig.config, oldState); + const parsedFilters = parsedConfig.visState.filters; + + const mergedState = mergeFilters(oldState.visState, parsedFilters); + + Object.keys(oldVisState).forEach(key => { + if (key === 'filterToBeMerged') { + t.deepEqual( + mergedState.filterToBeMerged, + parsedFilters, + 'Should save filters to filterToBeMerged before data loaded' + ); + } else { + t.deepEqual(mergedState[key], oldVisState[key], 'Should keep the rest of state same'); + } + }); + + const parsedData = SchemaManager.parseSavedData(savedConfig.datasets); + + // load data into reducer + const stateWData = visStateReducer(mergedState, updateVisData(parsedData)); + + // test parsed filters + cmpFilters(t, oldFilters, stateWData.filters); + t.deepEqual(stateWData.filterToBeMerged, [], 'should not pass fiter validate if tiler is empty'); + + // should filter data + t.end(); +}); + test('VisStateMerger -> mergeLayers -> invalid layer config', t => { const oldState = cloneDeep(InitialState); const oldVisState = oldState.visState; diff --git a/test/node/schemas/vis-state-schema-test.js b/test/node/schemas/vis-state-schema-test.js index 876637ed48..39c6850c83 100644 --- a/test/node/schemas/vis-state-schema-test.js +++ b/test/node/schemas/vis-state-schema-test.js @@ -37,6 +37,8 @@ import { testCsvDataId, testGeoJsonDataId } from 'test/helpers/mock-state'; +import keplerGlReducer from 'reducers/core'; +import * as VisStateActions from 'actions/vis-state-actions'; test('#visStateSchema -> v1 -> save layers', t => { const initialState = cloneDeep(StateWFilesFiltersLayerColor); @@ -124,6 +126,19 @@ test('#visStateSchema -> v1 -> save load filters', t => { t.end(); }); +test('#visStateSchema -> v1 -> save and validate filters', t => { + const initialState = cloneDeep(StateWFilesFiltersLayerColor); + + // add empty filter + const nextStte = keplerGlReducer(initialState, VisStateActions.addFilter(testCsvDataId)); + const savedState = SchemaManager.getConfigToSave(nextStte); + + t.equal(nextStte.visState.filters.length, 3, 'should have 3 filters'); + t.equal(savedState.config.visState.filters.length, 2, 'should only save 2 filters'); + + t.end(); +}); + test('#visStateSchema -> v1 -> save load interaction', t => { const initialState = cloneDeep(StateWFilesFiltersLayerColor); const savedState = SchemaManager.getConfigToSave(initialState);