From 230aaeef8cad0ea6e7f8754606a09de3c2762972 Mon Sep 17 00:00:00 2001 From: Darin Kelkhoff Date: Thu, 21 Mar 2024 16:41:09 -0500 Subject: [PATCH] Strip away null field names in criteria (e.g., from incomplete advanced filters) when storing in local storage, in saved views, and any time we load a view. --- src/qqq/components/misc/SavedViews.tsx | 12 ++++++++--- src/qqq/models/query/RecordQueryView.ts | 2 ++ src/qqq/pages/records/query/RecordQuery.tsx | 23 +++++++++++++++++++-- src/qqq/utils/qqq/FilterUtils.tsx | 23 +++++++++++++++++++++ 4 files changed, 55 insertions(+), 5 deletions(-) diff --git a/src/qqq/components/misc/SavedViews.tsx b/src/qqq/components/misc/SavedViews.tsx index 59dcc07..9407d3c 100644 --- a/src/qqq/components/misc/SavedViews.tsx +++ b/src/qqq/components/misc/SavedViews.tsx @@ -25,7 +25,7 @@ import {QTableMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QT import {QJobComplete} from "@kingsrook/qqq-frontend-core/lib/model/processes/QJobComplete"; import {QJobError} from "@kingsrook/qqq-frontend-core/lib/model/processes/QJobError"; import {QRecord} from "@kingsrook/qqq-frontend-core/lib/model/QRecord"; -import {Alert, Button, Link} from "@mui/material"; +import {Alert, Button} from "@mui/material"; import Box from "@mui/material/Box"; import Dialog from "@mui/material/Dialog"; import DialogActions from "@mui/material/DialogActions"; @@ -40,14 +40,14 @@ import TextField from "@mui/material/TextField"; import Tooltip from "@mui/material/Tooltip"; import {TooltipProps} from "@mui/material/Tooltip/Tooltip"; import FormData from "form-data"; -import React, {useContext, useEffect, useRef, useState} from "react"; -import {useLocation, useNavigate} from "react-router-dom"; import QContext from "QContext"; import colors from "qqq/assets/theme/base/colors"; import {QCancelButton, QDeleteButton, QSaveButton} from "qqq/components/buttons/DefaultButtons"; import RecordQueryView from "qqq/models/query/RecordQueryView"; import FilterUtils from "qqq/utils/qqq/FilterUtils"; import {SavedViewUtils} from "qqq/utils/qqq/SavedViewUtils"; +import React, {useContext, useEffect, useRef, useState} from "react"; +import {useLocation, useNavigate} from "react-router-dom"; interface Props { @@ -227,6 +227,12 @@ function SavedViews({qController, metaData, tableMetaData, currentSavedView, tab ///////////////////////////////////////////////////////////////////////////////////////////////// const viewObject = JSON.parse(JSON.stringify(view)); viewObject.queryFilter = JSON.parse(JSON.stringify(FilterUtils.convertFilterPossibleValuesToIds(viewObject.queryFilter))); + + //////////////////////////////////////////////////////////////////////////// + // strip away incomplete filters too, just for cleaner saved view filters // + //////////////////////////////////////////////////////////////////////////// + FilterUtils.stripAwayIncompleteCriteria(viewObject.queryFilter) + formData.append("viewJson", JSON.stringify(viewObject)); if (isSaveFilterAs || isRenameFilter || currentSavedView == null) diff --git a/src/qqq/models/query/RecordQueryView.ts b/src/qqq/models/query/RecordQueryView.ts index a705603..3b6faa2 100644 --- a/src/qqq/models/query/RecordQueryView.ts +++ b/src/qqq/models/query/RecordQueryView.ts @@ -63,6 +63,8 @@ export default class RecordQueryView view.queryFilter = json.queryFilter as QQueryFilter; + FilterUtils.stripAwayIncompleteCriteria(view.queryFilter) + ////////////////////////////////////////////////////////////////////////////////////////// // it's important that some criteria values exist as expression objects - so - do that. // ////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/qqq/pages/records/query/RecordQuery.tsx b/src/qqq/pages/records/query/RecordQuery.tsx index 24c7c63..80bf1e1 100644 --- a/src/qqq/pages/records/query/RecordQuery.tsx +++ b/src/qqq/pages/records/query/RecordQuery.tsx @@ -711,8 +711,27 @@ function RecordQuery({table, launchProcess}: Props): JSX.Element const doSetView = (view: RecordQueryView): void => { setView(view); - setViewAsJson(JSON.stringify(view)); - localStorage.setItem(viewLocalStorageKey, JSON.stringify(view)); + const viewAsJSON = JSON.stringify(view); + setViewAsJson(viewAsJSON); + + try + { + //////////////////////////////////////////////////////////////////////////////////// + // in case there's an incomplete criteria in the view (e.g., w/o a fieldName), // + // don't store that in local storage - we don't want that, it's messy, and it // + // has caused fails in the past. So, clone the view, and strip away such things. // + //////////////////////////////////////////////////////////////////////////////////// + const viewForLocalStorage: RecordQueryView = JSON.parse(viewAsJSON); + if (viewForLocalStorage?.queryFilter?.criteria?.length > 0) + { + FilterUtils.stripAwayIncompleteCriteria(viewForLocalStorage.queryFilter) + } + localStorage.setItem(viewLocalStorageKey, JSON.stringify(viewForLocalStorage)); + } + catch(e) + { + console.log("Error storing view in local storage: " + e) + } }; diff --git a/src/qqq/utils/qqq/FilterUtils.tsx b/src/qqq/utils/qqq/FilterUtils.tsx index f7d5575..153fbcb 100644 --- a/src/qqq/utils/qqq/FilterUtils.tsx +++ b/src/qqq/utils/qqq/FilterUtils.tsx @@ -589,6 +589,29 @@ class FilterUtils } } + + /******************************************************************************* + ** after go-live of redesigin in march 2024, we had bugs where we could get a + ** filter with a criteria w/ a null field name (e.g., by having an incomplete + ** criteria in the Advanced filter builder - and that would sometimes break + ** the screen! So, strip those away when storing or loading filters, via + ** this function. + *******************************************************************************/ + public static stripAwayIncompleteCriteria(filter: QQueryFilter) + { + if (filter?.criteria?.length > 0) + { + for (let i = 0; i < filter.criteria.length; i++) + { + if (!filter.criteria[i].fieldName) + { + filter.criteria.splice(i, 1); + i--; + } + } + } + } + } export default FilterUtils;