UNPKG

@gpa-gemstone/react-interactive

Version:
297 lines (296 loc) 18.3 kB
"use strict"; // ****************************************************************************************************** // SearchBar.tsx - Gbtc // // Copyright © 2020, Grid Protection Alliance. All Rights Reserved. // // Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See // the NOTICE file distributed with this work for additional information regarding copyright ownership. // The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this // file except in compliance with the License. You may obtain a copy of the License at: // // http://opensource.org/licenses/MIT // // Unless agreed to in writing, the subject software distributed under the License is distributed on an // "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the // License for the specific language governing permissions and limitations. // // Code Modification History: // ---------------------------------------------------------------------------------------------------- // 01/06/2020 - Christoph Lackner // Generated original version of source code. // ****************************************************************************************************** var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.GetStoredFilters = void 0; exports.default = SearchBar; var React = __importStar(require("react")); var Modal_1 = __importDefault(require("../Modal")); var LoadingIcon_1 = __importDefault(require("../LoadingIcon")); var react_forms_1 = require("@gpa-gemstone/react-forms"); var lodash_1 = __importDefault(require("lodash")); var FilterCreator_1 = __importDefault(require("./FilterCreator")); var FilterRow_1 = __importDefault(require("./FilterRow")); var gpa_symbols_1 = require("@gpa-gemstone/gpa-symbols"); var helper_functions_1 = require("@gpa-gemstone/helper-functions"); function SearchBar(props) { var _a, _b; var hasExternalFilters = props.Filters !== undefined; var useQuickSearch = props.defaultCollumn !== undefined; var _c = React.useState(false), hover = _c[0], setHover = _c[1]; var _d = React.useState(false), show = _d[0], setShow = _d[1]; var _e = React.useState(false), isNew = _e[0], setIsNew = _e[1]; var _f = React.useState([]), internalFilters = _f[0], setInternalFilters = _f[1]; var _g = React.useState(""), search = _g[0], setSearch = _g[1]; var _h = React.useState(null), searchFilter = _h[0], setSearchFilter = _h[1]; var _j = React.useState(setDefaultDraftFilter(props.CollumnList[0])), draftFilter = _j[0], setDraftFilter = _j[1]; var _k = React.useState(false), showHelpTooltip = _k[0], setShowHelpTooltip = _k[1]; var helpTooltipRef = React.useRef((0, helper_functions_1.CreateGuid)()); var activeFilters = React.useMemo(function () { var _a; return hasExternalFilters ? ((_a = props.Filters) !== null && _a !== void 0 ? _a : []) : internalFilters; }, [hasExternalFilters, props.Filters, internalFilters]); // Memoized default column to prevent unneccessary re-renders var stringifiedDefaultColumn = React.useMemo(function () { return props.defaultCollumn != null ? JSON.stringify(props.defaultCollumn) : null; }, [props.defaultCollumn]); var memoizedDefaultColumn = React.useMemo(function () { return stringifiedDefaultColumn != null ? JSON.parse(stringifiedDefaultColumn) : undefined; }, [stringifiedDefaultColumn]); // Memoized function to apply quick search with debounce and push filters up var applyQuickSearch = React.useMemo(function () { return lodash_1.default.debounce(function (text, baseFilters) { if (!useQuickSearch || memoizedDefaultColumn == null) { props.SetFilter(baseFilters); return; } if (text.length === 0) { setSearchFilter(null); props.SetFilter(baseFilters); return; } var quick = { FieldName: memoizedDefaultColumn.key, Operator: 'LIKE', Type: memoizedDefaultColumn.type, SearchText: "*".concat(text, "*"), IsPivotColumn: memoizedDefaultColumn.isPivotField }; setSearchFilter(quick); props.SetFilter(__spreadArray(__spreadArray([], baseFilters, true), [quick], false)); }, 500); }, [props.SetFilter, memoizedDefaultColumn, useQuickSearch]); // Cleanup debounce on unmount React.useEffect(function () { return function () { return applyQuickSearch.cancel(); }; }, [applyQuickSearch]); // Handling filter initialization from props or localStorage React.useEffect(function () { var _a, _b; if (props.StorageID == null || hasExternalFilters) return; // Get Button Filters var storedFilters = (_a = JSON.parse(localStorage.getItem("".concat(props.StorageID, ".Filters")))) !== null && _a !== void 0 ? _a : []; setInternalFilters(storedFilters); // Get Bar Search var storedSearch = (_b = localStorage.getItem("".concat(props.StorageID, ".Search"))) !== null && _b !== void 0 ? _b : ""; setSearch(storedSearch); applyQuickSearch.cancel(); applyQuickSearch(storedSearch, storedFilters); applyQuickSearch.flush(); //Ensure immediate execution on load }, [props.StorageID, hasExternalFilters, applyQuickSearch]); //Effect tp store active filters if StorageID is provided React.useEffect(function () { if (props.StorageID == null || hasExternalFilters) return; localStorage.setItem("".concat(props.StorageID, ".Filters"), JSON.stringify(activeFilters)); }, [activeFilters, hasExternalFilters]); //Effect to store search string if StorageID is provided React.useEffect(function () { if (props.StorageID == null || hasExternalFilters) return; localStorage.setItem("".concat(props.StorageID, ".Search"), search); }, [search, hasExternalFilters]); //Callback to push up filters // if newSearchFilter is provided and not undefined, it will be used instead of the internal searchFilter var pushFilters = React.useCallback(function (newFilters, newSearchFilter) { var filtersToPush = __spreadArray([], newFilters, true); //Only add newSearchFilter if quick search is being used and searchFilter is defined if (newSearchFilter !== undefined) { if (useQuickSearch && newSearchFilter != null) props.SetFilter(__spreadArray(__spreadArray([], filtersToPush, true), [newSearchFilter], false)); else props.SetFilter(filtersToPush); return; } if (useQuickSearch && searchFilter != null) filtersToPush.push(searchFilter); props.SetFilter(filtersToPush); }, [searchFilter, props.SetFilter, useQuickSearch]); function deleteFilter(filterToDelete) { var updatedFilters = activeFilters.filter(function (f) { return f !== filterToDelete; }); setHover(false); if (!hasExternalFilters) setInternalFilters(updatedFilters); if (useQuickSearch) applyQuickSearch(search, updatedFilters); else pushFilters(updatedFilters, undefined); } function addFilter() { var oldFilters = __spreadArray([], activeFilters, true); var adjustedFilter = __assign({}, draftFilter); if (adjustedFilter.Type === 'string' && (adjustedFilter.Operator === 'LIKE' || adjustedFilter.Operator === 'NOT LIKE')) adjustedFilter.SearchText = '*' + adjustedFilter.SearchText + '*'; oldFilters.push(adjustedFilter); setDraftFilter(setDefaultDraftFilter(props.CollumnList[0])); if (!hasExternalFilters) setInternalFilters(oldFilters); if (useQuickSearch) applyQuickSearch(search, oldFilters); else pushFilters(oldFilters, undefined); } function editFilter(index) { setIsNew(false); var oldFilters = __spreadArray([], activeFilters, true); var filt = __assign({}, oldFilters[index]); oldFilters.splice(index, 1); if (filt.Type === 'string' && (filt.Operator === 'LIKE' || filt.Operator === 'NOT LIKE')) filt.SearchText = filt.SearchText.substr(1, filt.SearchText.length - 2); setShow(true); setDraftFilter(filt); if (!hasExternalFilters) setInternalFilters(oldFilters); if (useQuickSearch) applyQuickSearch(search, oldFilters); else pushFilters(oldFilters, undefined); } function createFilter() { setShow(!show); setIsNew(true); setDraftFilter(setDefaultDraftFilter(props.CollumnList[0])); } var editSearch = function (text) { setSearch(text); applyQuickSearch(text, activeFilters); }; var content = (React.createElement("form", null, React.createElement("div", { className: "row" }, useQuickSearch ? React.createElement("div", { className: "col" }, React.createElement("div", { className: "input-group" }, React.createElement("input", { className: "form-control mr-sm-2", type: "search", placeholder: "Search " + ((_a = memoizedDefaultColumn === null || memoizedDefaultColumn === void 0 ? void 0 : memoizedDefaultColumn.label) !== null && _a !== void 0 ? _a : ''), onChange: function (event) { return editSearch(event.target.value); }, value: search, disabled: props.Disabled }), props.ShowLoading !== undefined && props.ShowLoading ? React.createElement("div", { className: "input-group-append" }, React.createElement(LoadingIcon_1.default, { Show: true })) : null), React.createElement("p", { style: { marginTop: 2, marginBottom: 2 } }, props.ResultNote)) : null, React.createElement("div", { style: { position: 'relative', display: 'inline-block' }, className: 'col align-items-start' }, React.createElement("button", { disabled: props.Disabled, className: "btn btn-" + (activeFilters.length > 0 ? "warning" : "primary"), onClick: function (evt) { evt.preventDefault(); createFilter(); }, onMouseEnter: function () { return setHover(true); }, onMouseLeave: function () { return setHover(false); } }, "Add Filter", activeFilters.length > 0 ? ("(" + activeFilters.length + ")") : ""), props.Help != null ? React.createElement("button", { className: 'btn', onMouseEnter: function () { return setShowHelpTooltip(true); }, onMouseLeave: function () { return setShowHelpTooltip(false); }, "data-tooltip": helpTooltipRef.current }, React.createElement(gpa_symbols_1.ReactIcons.QuestionMark, { Color: "var(--info)", Size: 20 }), React.createElement(react_forms_1.ToolTip, { Show: showHelpTooltip, Target: helpTooltipRef.current, Class: "info" }, props.Help)) : null, React.createElement("div", { className: "popover", style: { display: hover ? 'block' : 'none', maxWidth: 'unset', right: (props.Direction === 'right' ? 0 : 'unset'), left: (props.Direction === 'left' ? 0 : 'unset'), top: 'unset' }, onMouseEnter: function () { return setHover(true); }, onMouseLeave: function () { return setHover(false); } }, React.createElement("table", { className: 'table table-hover' }, React.createElement("thead", null, React.createElement("tr", null, React.createElement("th", null, "Column"), React.createElement("th", null, "Operator"), React.createElement("th", null, "Search Text"), React.createElement("th", null, "Edit"), React.createElement("th", null, "Remove"))), React.createElement("tbody", null, activeFilters.map(function (f, i) { return React.createElement(FilterRow_1.default, { Filter: f, Edit: function () { return editFilter(i); }, Delete: function () { return deleteFilter(f); }, key: i, Collumns: props.CollumnList }); })))))))); return (React.createElement("div", { className: (_b = props.Class) !== null && _b !== void 0 ? _b : 'w-100' }, React.createElement("nav", { className: "navbar navbar-expand" }, React.createElement("div", { className: 'w-100' }, React.createElement("ul", { className: "navbar-nav mr-auto d-flex align-items-center w-100" }, props.Direction === 'right' ? props.children : null, props.Label !== undefined ? React.createElement("li", { className: "nav-item", style: { minWidth: (props.Width === undefined ? '150px' : undefined), width: props.Width, paddingRight: 10 } }, React.createElement("fieldset", { className: "border", style: { padding: '10px', height: '100%' } }, React.createElement("legend", { className: "w-auto", style: { fontSize: 'large' } }, props.Label, ":"), content)) : React.createElement("li", { className: "nav-item", style: { minWidth: (props.Width === undefined ? '150px' : undefined), width: props.Width, paddingRight: 10 } }, content), props.Direction === 'left' ? props.children : null))), React.createElement(Modal_1.default, { Title: 'Add Filter', Show: show, CallBack: function (conf) { if (conf) addFilter(); setShow(false); }, ConfirmText: isNew ? 'Add' : 'Save', CancelText: isNew ? 'Close' : 'Delete' }, React.createElement(react_forms_1.Select, { Record: draftFilter, Field: 'FieldName', Options: props.CollumnList.map(function (fl) { return ({ Value: fl.key, Label: fl.label }); }), Setter: function (record) { var operator = "IN"; var column = props.CollumnList.find(function (fl) { return fl.key === record.FieldName; }); if (column !== undefined && column.type === 'string') operator = "LIKE"; if (column !== undefined && (column.type === 'number' || column.type === 'integer' || column.type === 'boolean')) operator = '='; if (column !== undefined && column.type === 'datetime') operator = '>'; setDraftFilter(function (prevFilter) { return (__assign(__assign({}, prevFilter), { FieldName: record.FieldName, SearchText: '', Operator: operator, Type: (column !== undefined ? column.type : 'string'), IsPivotColumn: (column !== undefined ? column.isPivotField : true) })); }); }, Label: 'Column' }), React.createElement(FilterCreator_1.default, { Filter: draftFilter, Field: props.CollumnList.find(function (fl) { return fl.key === draftFilter.FieldName; }), Setter: function (record) { return setDraftFilter(record); }, Enum: (props.GetEnum === undefined ? undefined : props.GetEnum) })))); } var GetStoredFilters = function (storageID) { var _a, _b; var storedFilters = (_a = JSON.parse(localStorage.getItem("".concat(storageID, ".Filters")))) !== null && _a !== void 0 ? _a : []; var storedSearch = (_b = localStorage.getItem("".concat(storageID, ".Search"))) !== null && _b !== void 0 ? _b : ""; return __spreadArray(__spreadArray([], storedFilters, true), [storedSearch], false); }; exports.GetStoredFilters = GetStoredFilters; var setDefaultDraftFilter = function (filter) { var draftFilter = { FieldName: filter.key, SearchText: '', Operator: filter.type === 'string' ? 'LIKE' : '=', Type: filter.type, IsPivotColumn: filter.isPivotField }; return draftFilter; };