@bento-core/query-bar 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/DESIGN.md ADDED
@@ -0,0 +1,32 @@
1
+ # Overview
2
+
3
+ This document describes the technical design behind this component. For actual usage, please see the [README.md](./README.md) in this folder.
4
+
5
+ # Details
6
+
7
+ ## Bases
8
+
9
+ This component is based on the following:
10
+
11
+ - N/A – This is a custom component not based on a specific Material-UI component
12
+
13
+ ## States
14
+
15
+ This component uses **local** states for:
16
+
17
+ - N/A – The component does not use local states
18
+
19
+ This component watches the **global** state for:
20
+
21
+ - The Dashboard Facet Sidebar State (`state->statusReducer->filterState`)
22
+ - The Local Find State (`state->localFind`) (`->upload` and `->autocomplete`)
23
+
24
+ > **Note**: This component does not modify the global state or the property mentioned above.
25
+
26
+ ## Retrieval
27
+
28
+ The main component, `<QueryBar>` is generated through the `QueryBarGenerator()` function. See the main [README.md](./README.md) for more information. The sub-components found in [components](./src/components/) are not designed to be used outside of this component, but are retrieved via importing them directly. No documentation on using them directly is provided.
29
+
30
+ ## Configuration
31
+
32
+ The default configuration object is defined in [config.js](./src/Generators/config.js). To override and customize the component, you must provide the new configuration object to the `QueryBarGenerator()` function. **You do not need to override every option** only overriden options will be used.
package/README.md ADDED
@@ -0,0 +1,139 @@
1
+ # Introduction
2
+
3
+ This package provides the Query Bar component that displays the current Facet Search and Local Find filters on the Dashboard/Explore page. It also provides the direct ability to reset all or some of the filters with the click of a button. It is designed to be implemented directly with the:
4
+
5
+ - `@bento-core/local-find`
6
+ - `@bento-core/facet-filter`
7
+
8
+ packages. For the component's technical details, please see [DESIGN.md](./DESIGN.md).
9
+
10
+ See below for usage instructions.
11
+
12
+ # Usage
13
+
14
+ ## Quick Start
15
+
16
+ <details>
17
+ <summary>Basic Usage</summary>
18
+
19
+ ```javascript
20
+ import { QueryBarGenerator } from '@bento-core/query-bar';
21
+
22
+ // Generate the component
23
+ const { QueryBar } = QueryBarGenerator({
24
+ /** See Generator Options **/
25
+ });
26
+
27
+ // Use the component (e.g. In dashTemplateView.js)
28
+ const Layout = (props) => {
29
+ return (
30
+ {/* other components */}
31
+ <div className={classes.rightContent}>
32
+ <div className={classes.widgetsContainer}>
33
+ {/* other components */}
34
+
35
+ <QueryBar />
36
+
37
+ {/* other components */}
38
+ </div>
39
+ </div>
40
+ {/* other components */}
41
+ );
42
+ };
43
+ ```
44
+
45
+ </details>
46
+
47
+ ## Generator Configuration
48
+
49
+ See the available `DEFAULT_CONFIG_QUERYBAR` object to understand the component generator options. You can choose to override `config`, and/or `functions`. You DO NOT need to override all of the options if you don't want to. The component generator will only use the options you provide.
50
+
51
+ ```javascript
52
+ const CONFIG = {
53
+ /* General Component Configuration */
54
+ config: {
55
+ /**
56
+ * The maximum number of items to display in a query bar facet section
57
+ * @var {number}
58
+ */
59
+ maxItems: 2,
60
+ },
61
+
62
+ /* Component Helper Functions */
63
+ functions: {
64
+ /**
65
+ * Clear all active facet/local find filters
66
+ *
67
+ * @returns {void}
68
+ */
69
+ clearAll: () => {},
70
+
71
+ /**
72
+ * Clear all active Local Find file upload filters
73
+ *
74
+ * @returns {void}
75
+ */
76
+ clearUpload: () => {},
77
+
78
+ /**
79
+ * Clear all active Local Find searchbox filters
80
+ *
81
+ * @returns {void}
82
+ */
83
+ clearAutocomplete: () => {},
84
+
85
+ /**
86
+ * Delete a specific Local Find searchbox filter (case)
87
+ *
88
+ * @param {string} title
89
+ * @returns {void}
90
+ */
91
+ deleteAutocompleteItem: (title) => {},
92
+
93
+ /**
94
+ * Reset a specific facet section (e.g. Program)
95
+ *
96
+ * @param {object} section the configuration object for the section
97
+ * @returns {void}
98
+ */
99
+ resetFacetSection: (section) => {},
100
+
101
+ /**
102
+ * Reset a specific facet checkbox (e.g. Program > TAILORx)
103
+ *
104
+ * @param {object} section the configuration object for the section
105
+ * @param {string} checkbox the name of the checkbox
106
+ * @returns {void}
107
+ */
108
+ resetFacetCheckbox: (section, checkbox) => {},
109
+
110
+ /**
111
+ * Reset a specific slider section (e.g. Age)
112
+ *
113
+ * @param {object} section the configuration object for the section
114
+ * @returns {void}
115
+ */
116
+ resetFacetSlider: (section) => {},
117
+ },
118
+ };
119
+ ```
120
+
121
+ # Exports
122
+
123
+ This component exports the following components and objects by default. You may use them as necessary.
124
+
125
+ - `QueryBarGenerator` - The component generator function
126
+ - `DEFAULT_CONFIG_QUERYBAR` - The default configuration object
127
+ - `DEFAULT_STYLES_QUERYBAR` – The default Material UI styles
128
+
129
+ # Props
130
+
131
+ This component, which is generated by the provided generator, accepts the following props directly. The default value is specified, along with the possible values. The `classes` prop will override the default styling for any provided classes.
132
+
133
+ ```javascript
134
+ <QueryBar
135
+ statusReducer={undefined} // {object} - The status reducer object with the section `facetsConfig` combined
136
+ localFind={undefined} // {object} - The local find reducer object (Not modified)
137
+ classes={undefined} // {object} - The Material UI classes object. Overrides default styling for provided classes.
138
+ />
139
+ ```
@@ -0,0 +1,21 @@
1
+ {
2
+ "presets": [
3
+ [
4
+ "@babel/env",
5
+ {
6
+ "targets": {
7
+ "edge": "17",
8
+ "firefox": "60",
9
+ "chrome": "67",
10
+ "safari": "11.1"
11
+ }
12
+ }
13
+ ],
14
+ "@babel/preset-react"
15
+ ],
16
+ "plugins": [
17
+ "@babel/plugin-transform-react-jsx",
18
+ "@babel/plugin-syntax-jsx",
19
+ "@babel/plugin-proposal-class-properties"
20
+ ]
21
+ }
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _react = _interopRequireDefault(require("react"));
8
+ var _clsx = _interopRequireDefault(require("clsx"));
9
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
10
+ var _default = _ref => {
11
+ let {
12
+ index,
13
+ data,
14
+ classes,
15
+ maxItems,
16
+ onSectionClick,
17
+ onItemClick
18
+ } = _ref;
19
+ const {
20
+ items,
21
+ section
22
+ } = data;
23
+ return /*#__PURE__*/_react.default.createElement("span", null, /*#__PURE__*/_react.default.createElement("span", null, ' ', index !== 0 ? /*#__PURE__*/_react.default.createElement("span", {
24
+ className: classes.operators
25
+ }, " AND ") : '', /*#__PURE__*/_react.default.createElement("span", {
26
+ className: (0, _clsx.default)(classes.filterName, classes["facetSection".concat(section, "Background")]),
27
+ onClick: () => onSectionClick(data)
28
+ }, data.label), ' '), /*#__PURE__*/_react.default.createElement("span", null, ' ', /*#__PURE__*/_react.default.createElement("span", {
29
+ className: classes.operators
30
+ }, items.length === 1 ? 'IS ' : 'IN '), items.length > 1 && /*#__PURE__*/_react.default.createElement("span", {
31
+ className: classes.bracketsOpen
32
+ }, "("), items.slice(0, maxItems).map((d, idx) => /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement("span", {
33
+ className: (0, _clsx.default)(classes.filterCheckboxes, classes["facetSection".concat(section)]),
34
+ key: idx,
35
+ onClick: () => onItemClick(data, d)
36
+ }, d), idx === maxItems - 1 ? null : ' ')), items.length > maxItems && '...', items.length > 1 && /*#__PURE__*/_react.default.createElement("span", {
37
+ className: classes.bracketsClose
38
+ }, ")")));
39
+ };
40
+ exports.default = _default;
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = exports.Filter = void 0;
7
+ var _react = _interopRequireWildcard(require("react"));
8
+ var _CheckboxFilter = _interopRequireDefault(require("./CheckboxFilter"));
9
+ var _SliderFilter = _interopRequireDefault(require("./SliderFilter"));
10
+ const _excluded = ["type"];
11
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
12
+ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
13
+ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
14
+ function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
15
+ function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
16
+ const DEFAULT_FILTER_MAP = {
17
+ checkbox: _CheckboxFilter.default,
18
+ slider: _SliderFilter.default
19
+ };
20
+
21
+ /**
22
+ * This is a helper component to wrap the Filter component
23
+ *
24
+ * Note: If the filter component type is unknown,
25
+ * a placeholder component will be rendered instead
26
+ *
27
+ * @param {object} props
28
+ * @param {string} props.type - The type of component to render
29
+ * @returns {JSX.Element} - The component to render
30
+ */
31
+ const Filter = _ref => {
32
+ let {
33
+ type
34
+ } = _ref,
35
+ props = _objectWithoutProperties(_ref, _excluded);
36
+ // Default to the default card map
37
+ if (typeof DEFAULT_FILTER_MAP[type] !== 'undefined') {
38
+ return /*#__PURE__*/(0, _react.createElement)(DEFAULT_FILTER_MAP[type], props);
39
+ }
40
+
41
+ // Render a placeholder component
42
+ return /*#__PURE__*/(0, _react.createElement)(() => /*#__PURE__*/_react.default.createElement("div", null, "The component for ".concat(type, " was not found.")));
43
+ };
44
+ exports.Filter = Filter;
45
+ var _default = Filter;
46
+ exports.default = _default;
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _react = _interopRequireDefault(require("react"));
8
+ var _clsx = _interopRequireDefault(require("clsx"));
9
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
10
+ var _default = _ref => {
11
+ let {
12
+ index,
13
+ data,
14
+ classes,
15
+ onSectionClick,
16
+ onItemClick
17
+ } = _ref;
18
+ const {
19
+ items,
20
+ section
21
+ } = data;
22
+ return /*#__PURE__*/_react.default.createElement("span", null, /*#__PURE__*/_react.default.createElement("span", null, ' ', index !== 0 ? /*#__PURE__*/_react.default.createElement("span", {
23
+ className: classes.operators
24
+ }, " AND ") : '', /*#__PURE__*/_react.default.createElement("span", {
25
+ className: (0, _clsx.default)(classes.filterName, classes["facetSection".concat(section, "Background")]),
26
+ onClick: () => onSectionClick(data)
27
+ }, data.label), ' '), /*#__PURE__*/_react.default.createElement("span", null, ' ', /*#__PURE__*/_react.default.createElement("span", {
28
+ className: classes.operators
29
+ }, "IS BETWEEN", ' '), /*#__PURE__*/_react.default.createElement("span", {
30
+ className: (0, _clsx.default)(classes.filterCheckboxes, classes["facetSection".concat(section)]),
31
+ onClick: () => onItemClick(data, items[0])
32
+ }, "".concat(items[0], " \u2013 ").concat(items[1]))));
33
+ };
34
+ exports.default = _default;
@@ -0,0 +1,117 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = exports.QueryBarGenerator = void 0;
7
+ var _react = _interopRequireDefault(require("react"));
8
+ var _core = require("@material-ui/core");
9
+ var _facetFilter = require("@bento-core/facet-filter");
10
+ var _clsx = _interopRequireDefault(require("clsx"));
11
+ var _FilterMap = require("../components/FilterMap");
12
+ var _styles = _interopRequireDefault(require("./styles"));
13
+ var _config = _interopRequireDefault(require("./config"));
14
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
15
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
16
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
17
+ function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
18
+ function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
19
+ function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
20
+ /**
21
+ * Generate a pre-configured Explore Query Bar component
22
+ *
23
+ * @param {object} uiConfig the component configuration object
24
+ * @returns {object} { QueryBar }
25
+ */
26
+ const QueryBarGenerator = function QueryBarGenerator() {
27
+ let uiConfig = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _config.default;
28
+ const {
29
+ config,
30
+ functions
31
+ } = uiConfig;
32
+ const {
33
+ CHECKBOX
34
+ } = _facetFilter.InputTypes;
35
+ const maxItems = config && typeof config.maxItems === 'number' ? config.maxItems : _config.default.config.maxItems;
36
+ const clearAll = functions && typeof functions.clearAll === 'function' ? functions.clearAll : _config.default.functions.clearAll;
37
+ const clearUpload = functions && typeof functions.clearUpload === 'function' ? functions.clearUpload : _config.default.functions.clearUpload;
38
+ const clearAutocomplete = functions && typeof functions.clearAutocomplete === 'function' ? functions.clearAutocomplete : _config.default.functions.clearAutocomplete;
39
+ const deleteAutocompleteItem = functions && typeof functions.deleteAutocompleteItem === 'function' ? functions.deleteAutocompleteItem : _config.default.functions.deleteAutocompleteItem;
40
+ const resetFacetSection = functions && typeof functions.resetFacetSection === 'function' ? functions.resetFacetSection : _config.default.functions.resetFacetSection;
41
+ const resetFacetCheckbox = functions && typeof functions.resetFacetCheckbox === 'function' ? functions.resetFacetCheckbox : _config.default.functions.resetFacetCheckbox;
42
+ const resetFacetSlider = functions && typeof functions.resetFacetSlider === 'function' ? functions.resetFacetSlider : _config.default.functions.resetFacetSlider;
43
+ return {
44
+ QueryBar: (0, _core.withStyles)(_styles.default, {
45
+ withTheme: true
46
+ })(props => {
47
+ const {
48
+ statusReducer,
49
+ localFind,
50
+ classes
51
+ } = props;
52
+ const {
53
+ autocomplete,
54
+ upload
55
+ } = localFind;
56
+
57
+ // Remove any sections without checkboxes selected
58
+ const mappedInputs = statusReducer.filter(facet => facet.section && facet.type).map(facet => {
59
+ if (facet.type !== CHECKBOX) {
60
+ return facet;
61
+ }
62
+ const items = Object.keys(facet.items);
63
+ items.sort((a, b) => a.localeCompare(b));
64
+ return _objectSpread(_objectSpread({}, facet), {}, {
65
+ items
66
+ });
67
+ }).filter(facet => facet.items.length > 0);
68
+ if ((mappedInputs.length || autocomplete.length || upload.length) <= 0) {
69
+ return null;
70
+ }
71
+ return /*#__PURE__*/_react.default.createElement("div", {
72
+ className: classes.queryWrapper
73
+ }, /*#__PURE__*/_react.default.createElement(_core.Button, {
74
+ className: classes.clearQueryButton,
75
+ color: "primary",
76
+ variant: "outlined",
77
+ onClick: clearAll
78
+ }, "Clear Query"), /*#__PURE__*/_react.default.createElement("span", {
79
+ className: classes.divider
80
+ }), /*#__PURE__*/_react.default.createElement("span", {
81
+ className: classes.queryContainer
82
+ }, autocomplete.length || upload.length ? /*#__PURE__*/_react.default.createElement("span", null, upload.length && !autocomplete.length ? /*#__PURE__*/_react.default.createElement("span", {
83
+ className: (0, _clsx.default)(classes.filterCheckboxes, classes.localFindBackground),
84
+ onClick: clearUpload
85
+ }, "INPUT CASE SET") : null, autocomplete.length ? /*#__PURE__*/_react.default.createElement("span", null, ' ', /*#__PURE__*/_react.default.createElement("span", {
86
+ className: (0, _clsx.default)(classes.filterName, classes.localFindBackground),
87
+ onClick: clearAutocomplete
88
+ }, "Case IDs"), ' ', ' ', /*#__PURE__*/_react.default.createElement("span", {
89
+ className: classes.operators
90
+ }, autocomplete.length === 1 && !upload.length ? 'IS ' : 'IN ')) : null, /*#__PURE__*/_react.default.createElement("span", null, (upload.length > 0 ? 1 : 0) + autocomplete.length > 1 ? /*#__PURE__*/_react.default.createElement("span", {
91
+ className: classes.bracketsOpen
92
+ }, "(") : null, upload.length && autocomplete.length ? /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, ' ', /*#__PURE__*/_react.default.createElement("span", {
93
+ className: (0, _clsx.default)(classes.filterCheckboxes, classes.localFind),
94
+ onClick: clearUpload
95
+ }, "INPUT CASE SET"), ' ') : null, autocomplete.slice(0, maxItems).map((d, idx) => /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement("span", {
96
+ className: (0, _clsx.default)(classes.filterCheckboxes, classes.facetSectionCases),
97
+ key: idx,
98
+ onClick: () => deleteAutocompleteItem(d.title)
99
+ }, d.title), idx === maxItems - 1 ? null : ' ')), autocomplete.length > maxItems && '...', (upload.length > 0 ? 1 : 0) + autocomplete.length > 1 ? /*#__PURE__*/_react.default.createElement("span", {
100
+ className: classes.bracketsClose
101
+ }, ")") : null)) : null, (autocomplete.length || upload.length) && mappedInputs.length ? /*#__PURE__*/_react.default.createElement("span", {
102
+ className: classes.operators
103
+ }, " AND ") : null, mappedInputs.map((filter, index) => /*#__PURE__*/_react.default.createElement(_FilterMap.Filter, {
104
+ index: index,
105
+ type: filter.type,
106
+ data: filter,
107
+ maxItems: maxItems,
108
+ classes: classes,
109
+ onSectionClick: filter.type === CHECKBOX ? resetFacetSection : resetFacetSlider,
110
+ onItemClick: filter.type === CHECKBOX ? resetFacetCheckbox : resetFacetSlider
111
+ }))));
112
+ })
113
+ };
114
+ };
115
+ exports.QueryBarGenerator = QueryBarGenerator;
116
+ var _default = QueryBarGenerator;
117
+ exports.default = _default;
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ /* eslint-disable no-unused-vars */
8
+ var _default = {
9
+ /* General Component Configuration */
10
+ config: {
11
+ /**
12
+ * The maximum number of items to display in a query bar facet section
13
+ * @var {number}
14
+ */
15
+ maxItems: 2
16
+ },
17
+ /* Component Helper Functions */
18
+ functions: {
19
+ /**
20
+ * Clear all active facet/local find filters
21
+ *
22
+ * @returns {void}
23
+ */
24
+ clearAll: () => {},
25
+ /**
26
+ * Clear all active Local Find file upload filters
27
+ *
28
+ * @returns {void}
29
+ */
30
+ clearUpload: () => {},
31
+ /**
32
+ * Clear all active Local Find searchbox filters
33
+ *
34
+ * @returns {void}
35
+ */
36
+ clearAutocomplete: () => {},
37
+ /**
38
+ * Delete a specific Local Find searchbox filter (case)
39
+ *
40
+ * @param {string} title
41
+ * @returns {void}
42
+ */
43
+ deleteAutocompleteItem: title => {},
44
+ /**
45
+ * Reset a specific facet section (e.g. Program)
46
+ *
47
+ * @param {object} section the configuration object for the section
48
+ * @returns {void}
49
+ */
50
+ resetFacetSection: section => {},
51
+ /**
52
+ * Reset a specific facet checkbox (e.g. Program > TAILORx)
53
+ *
54
+ * @param {object} section the configuration object for the section
55
+ * @param {string} checkbox the name of the checkbox
56
+ * @returns {void}
57
+ */
58
+ resetFacetCheckbox: (section, checkbox) => {},
59
+ /**
60
+ * Reset a specific slider section (e.g. Age)
61
+ *
62
+ * @param {object} section the configuration object for the section
63
+ * @returns {void}
64
+ */
65
+ resetFacetSlider: section => {}
66
+ }
67
+ };
68
+ exports.default = _default;
@@ -0,0 +1,114 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ /**
8
+ * Generate the default styling for the component
9
+ */
10
+ var _default = () => ({
11
+ queryWrapper: {
12
+ height: '120px',
13
+ backgroundColor: '#f1f1f1',
14
+ padding: '14px 14px 0px 35px',
15
+ overflowY: 'auto'
16
+ },
17
+ queryContainer: {
18
+ marginLeft: 7,
19
+ position: 'relative',
20
+ lineHeight: '2.4em',
21
+ letterSpacing: '0.5px',
22
+ fontFamily: 'Nunito',
23
+ fontSize: '14px',
24
+ color: '#0e3151'
25
+ },
26
+ filterName: {
27
+ textTransform: 'uppercase',
28
+ padding: '5px 6px 5px 7px',
29
+ borderRadius: 4,
30
+ fontSize: 12,
31
+ fontWeight: 600,
32
+ cursor: 'pointer'
33
+ },
34
+ filterCheckboxes: {
35
+ padding: '4px 7px 3px 6px',
36
+ borderRadius: 4,
37
+ fontSize: 12,
38
+ fontWeight: 600,
39
+ border: '0.75px solid #898989',
40
+ width: 'fit-content',
41
+ backgroundColor: '#fff',
42
+ cursor: 'pointer'
43
+ },
44
+ bracketsOpen: {
45
+ fontSize: 18,
46
+ fontFamily: 'Nunito Sans Semibold',
47
+ color: '#787878',
48
+ marginRight: 3,
49
+ fontWeight: 600
50
+ },
51
+ bracketsClose: {
52
+ fontSize: 18,
53
+ fontFamily: 'Nunito Sans Semibold',
54
+ color: '#787878',
55
+ marginLeft: 3,
56
+ fontWeight: 600
57
+ },
58
+ operators: {
59
+ color: '#646464',
60
+ marginLeft: '3px',
61
+ marginRight: '3px',
62
+ borderBottom: 'none',
63
+ textDecoration: 'none',
64
+ fontSize: 10,
65
+ fontWeight: 'bold'
66
+ },
67
+ clearQueryButton: {
68
+ margin: '1px',
69
+ marginLeft: -6,
70
+ fontWeight: 600,
71
+ fontSize: '13px',
72
+ color: '#fff',
73
+ borderRadius: '15px',
74
+ fontFamily: 'Nunito',
75
+ boxSizing: 'border-box',
76
+ backgroundColor: '#969696',
77
+ textTransform: 'capitalize',
78
+ border: '1px solid #B4B4B4',
79
+ padding: '1px 5px 0px 6px',
80
+ '&:hover': {
81
+ backgroundColor: '#969696'
82
+ }
83
+ },
84
+ divider: {
85
+ borderRight: '2px solid #969696',
86
+ marginLeft: 7
87
+ },
88
+ /* Custom Styling by Project */
89
+ localFind: {
90
+ color: '#10A075'
91
+ },
92
+ localFindBackground: {
93
+ backgroundColor: '#C0E9D7'
94
+ },
95
+ facetSectionCases: {
96
+ color: '#10A075'
97
+ },
98
+ facetSectionCasesBackground: {
99
+ backgroundColor: '#C0E9D7'
100
+ },
101
+ facetSectionFiles: {
102
+ color: '#E636E4'
103
+ },
104
+ facetSectionFilesBackground: {
105
+ backgroundColor: '#F5C3F1'
106
+ },
107
+ facetSectionSamples: {
108
+ color: '#10BEFF'
109
+ },
110
+ facetSectionSamplesBackground: {
111
+ backgroundColor: '#C3EAF5'
112
+ }
113
+ });
114
+ exports.default = _default;
package/dist/index.js ADDED
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "DEFAULT_CONFIG_QUERYBAR", {
7
+ enumerable: true,
8
+ get: function get() {
9
+ return _config.default;
10
+ }
11
+ });
12
+ Object.defineProperty(exports, "DEFAULT_STYLES_QUERYBAR", {
13
+ enumerable: true,
14
+ get: function get() {
15
+ return _styles.default;
16
+ }
17
+ });
18
+ Object.defineProperty(exports, "QueryBarGenerator", {
19
+ enumerable: true,
20
+ get: function get() {
21
+ return _QueryBarGenerator.QueryBarGenerator;
22
+ }
23
+ });
24
+ var _QueryBarGenerator = require("./generators/QueryBarGenerator");
25
+ var _styles = _interopRequireDefault(require("./generators/styles"));
26
+ var _config = _interopRequireDefault(require("./generators/config"));
27
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
package/package.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "@bento-core/query-bar",
3
+ "version": "0.2.0",
4
+ "description": "",
5
+ "main": "dist/index.js",
6
+ "scripts": {
7
+ "build": "cross-env-shell rm -rf dist && NODE_ENV=production BABEL_ENV=es babel src --out-dir dist --copy-files",
8
+ "test": "echo \"Error: no test specified\" && exit 1"
9
+ },
10
+ "repository": "https://github.com/CBIIT/bento-frontend",
11
+ "publishConfig": {
12
+ "access": "public"
13
+ },
14
+ "peerDependencies": {
15
+ "@bento-core/facet-filter": "*",
16
+ "@material-ui/core": "^4.10.0",
17
+ "clsx": "*",
18
+ "react": "^17.0.2",
19
+ "react-dom": "^17.0.0",
20
+ "react-redux": "^7.2.1"
21
+ },
22
+ "dependencies": {
23
+ "lodash": "^4.17.20"
24
+ },
25
+ "author": "CTOS Bento Team",
26
+ "license": "ISC",
27
+ "gitHead": "10ee9deeae6dd0f139ecb7a70afc4c96a4e33d74"
28
+ }
@@ -0,0 +1,46 @@
1
+ import React from 'react';
2
+ import clsx from 'clsx';
3
+
4
+ export default ({
5
+ index, data, classes, maxItems,
6
+ onSectionClick, onItemClick,
7
+ }) => {
8
+ const { items, section } = data;
9
+
10
+ return (
11
+ <span>
12
+ <span>
13
+ {' '}
14
+ {index !== 0 ? <span className={classes.operators}> AND </span> : ''}
15
+ <span
16
+ className={clsx(classes.filterName, classes[`facetSection${section}Background`])}
17
+ onClick={() => onSectionClick(data)}
18
+ >
19
+ {data.label}
20
+ </span>
21
+ {' '}
22
+ </span>
23
+ <span>
24
+ {' '}
25
+ <span className={classes.operators}>
26
+ {items.length === 1 ? 'IS ' : 'IN '}
27
+ </span>
28
+ {items.length > 1 && <span className={classes.bracketsOpen}>(</span>}
29
+ {items.slice(0, maxItems).map((d, idx) => (
30
+ <>
31
+ <span
32
+ className={clsx(classes.filterCheckboxes, classes[`facetSection${section}`])}
33
+ key={idx}
34
+ onClick={() => onItemClick(data, d)}
35
+ >
36
+ {d}
37
+ </span>
38
+ {idx === (maxItems - 1) ? null : ' '}
39
+ </>
40
+ ))}
41
+ {items.length > maxItems && '...'}
42
+ {items.length > 1 && <span className={classes.bracketsClose}>)</span>}
43
+ </span>
44
+ </span>
45
+ );
46
+ };
@@ -0,0 +1,34 @@
1
+ import React, { createElement } from 'react';
2
+ import Checkbox from './CheckboxFilter';
3
+ import Slider from './SliderFilter';
4
+
5
+ const DEFAULT_FILTER_MAP = {
6
+ checkbox: Checkbox,
7
+ slider: Slider,
8
+ };
9
+
10
+ /**
11
+ * This is a helper component to wrap the Filter component
12
+ *
13
+ * Note: If the filter component type is unknown,
14
+ * a placeholder component will be rendered instead
15
+ *
16
+ * @param {object} props
17
+ * @param {string} props.type - The type of component to render
18
+ * @returns {JSX.Element} - The component to render
19
+ */
20
+ export const Filter = ({ type, ...props }) => {
21
+ // Default to the default card map
22
+ if (typeof DEFAULT_FILTER_MAP[type] !== 'undefined') {
23
+ return createElement(DEFAULT_FILTER_MAP[type], props);
24
+ }
25
+
26
+ // Render a placeholder component
27
+ return createElement(() => (
28
+ <div>
29
+ {`The component for ${type} was not found.`}
30
+ </div>
31
+ ));
32
+ };
33
+
34
+ export default Filter;
@@ -0,0 +1,38 @@
1
+ import React from 'react';
2
+ import clsx from 'clsx';
3
+
4
+ export default ({
5
+ index, data, classes,
6
+ onSectionClick, onItemClick,
7
+ }) => {
8
+ const { items, section } = data;
9
+
10
+ return (
11
+ <span>
12
+ <span>
13
+ {' '}
14
+ {index !== 0 ? <span className={classes.operators}> AND </span> : ''}
15
+ <span
16
+ className={clsx(classes.filterName, classes[`facetSection${section}Background`])}
17
+ onClick={() => onSectionClick(data)}
18
+ >
19
+ {data.label}
20
+ </span>
21
+ {' '}
22
+ </span>
23
+ <span>
24
+ {' '}
25
+ <span className={classes.operators}>
26
+ IS BETWEEN
27
+ {' '}
28
+ </span>
29
+ <span
30
+ className={clsx(classes.filterCheckboxes, classes[`facetSection${section}`])}
31
+ onClick={() => onItemClick(data, items[0])}
32
+ >
33
+ {`${items[0]} – ${items[1]}`}
34
+ </span>
35
+ </span>
36
+ </span>
37
+ );
38
+ };
@@ -0,0 +1,178 @@
1
+ import React from 'react';
2
+ import { withStyles, Button } from '@material-ui/core';
3
+ import { InputTypes } from '@bento-core/facet-filter';
4
+ import clsx from 'clsx';
5
+ import { Filter } from '../components/FilterMap';
6
+ import DEFAULT_STYLES from './styles';
7
+ import DEFAULT_CONFIG from './config';
8
+
9
+ /**
10
+ * Generate a pre-configured Explore Query Bar component
11
+ *
12
+ * @param {object} uiConfig the component configuration object
13
+ * @returns {object} { QueryBar }
14
+ */
15
+ export const QueryBarGenerator = (uiConfig = DEFAULT_CONFIG) => {
16
+ const { config, functions } = uiConfig;
17
+ const { CHECKBOX } = InputTypes;
18
+
19
+ const maxItems = config && typeof config.maxItems === 'number'
20
+ ? config.maxItems
21
+ : DEFAULT_CONFIG.config.maxItems;
22
+
23
+ const clearAll = functions && typeof functions.clearAll === 'function'
24
+ ? functions.clearAll
25
+ : DEFAULT_CONFIG.functions.clearAll;
26
+
27
+ const clearUpload = functions && typeof functions.clearUpload === 'function'
28
+ ? functions.clearUpload
29
+ : DEFAULT_CONFIG.functions.clearUpload;
30
+
31
+ const clearAutocomplete = functions && typeof functions.clearAutocomplete === 'function'
32
+ ? functions.clearAutocomplete
33
+ : DEFAULT_CONFIG.functions.clearAutocomplete;
34
+
35
+ const deleteAutocompleteItem = functions && typeof functions.deleteAutocompleteItem === 'function'
36
+ ? functions.deleteAutocompleteItem
37
+ : DEFAULT_CONFIG.functions.deleteAutocompleteItem;
38
+
39
+ const resetFacetSection = functions && typeof functions.resetFacetSection === 'function'
40
+ ? functions.resetFacetSection
41
+ : DEFAULT_CONFIG.functions.resetFacetSection;
42
+
43
+ const resetFacetCheckbox = functions && typeof functions.resetFacetCheckbox === 'function'
44
+ ? functions.resetFacetCheckbox
45
+ : DEFAULT_CONFIG.functions.resetFacetCheckbox;
46
+
47
+ const resetFacetSlider = functions && typeof functions.resetFacetSlider === 'function'
48
+ ? functions.resetFacetSlider
49
+ : DEFAULT_CONFIG.functions.resetFacetSlider;
50
+
51
+ return {
52
+ QueryBar: withStyles(DEFAULT_STYLES, { withTheme: true })((props) => {
53
+ const { statusReducer, localFind, classes } = props;
54
+
55
+ const { autocomplete, upload } = localFind;
56
+
57
+ // Remove any sections without checkboxes selected
58
+ const mappedInputs = statusReducer.filter((facet) => facet.section && facet.type)
59
+ .map((facet) => {
60
+ if (facet.type !== CHECKBOX) { return facet; }
61
+
62
+ const items = Object.keys(facet.items);
63
+ items.sort((a, b) => a.localeCompare(b));
64
+
65
+ return { ...facet, items };
66
+ })
67
+ .filter((facet) => facet.items.length > 0);
68
+
69
+ if ((mappedInputs.length || autocomplete.length || upload.length) <= 0) {
70
+ return null;
71
+ }
72
+
73
+ return (
74
+ <div className={classes.queryWrapper}>
75
+ <Button
76
+ className={classes.clearQueryButton}
77
+ color="primary"
78
+ variant="outlined"
79
+ onClick={clearAll}
80
+ >
81
+ Clear Query
82
+ </Button>
83
+ <span className={classes.divider} />
84
+ <span className={classes.queryContainer}>
85
+ {/* Local Find Selections */}
86
+ {/* TODO: Refactor this into a separate component */}
87
+ {(autocomplete.length || upload.length) ? (
88
+ <span>
89
+ {/* Standalone case set button */}
90
+ {(upload.length && !autocomplete.length)
91
+ ? (
92
+ <span
93
+ className={clsx(classes.filterCheckboxes, classes.localFindBackground)}
94
+ onClick={clearUpload}
95
+ >
96
+ INPUT CASE SET
97
+ </span>
98
+ ) : null}
99
+ {autocomplete.length
100
+ ? (
101
+ <span>
102
+ {' '}
103
+ <span
104
+ className={clsx(classes.filterName, classes.localFindBackground)}
105
+ onClick={clearAutocomplete}
106
+ >
107
+ Case IDs
108
+ </span>
109
+ {' '}
110
+ {' '}
111
+ <span className={classes.operators}>
112
+ {(autocomplete.length === 1 && !upload.length) ? 'IS ' : 'IN '}
113
+ </span>
114
+ </span>
115
+ ) : null}
116
+ <span>
117
+ {(((upload.length > 0 ? 1 : 0) + autocomplete.length) > 1)
118
+ ? <span className={classes.bracketsOpen}>(</span>
119
+ : null}
120
+ {upload.length && autocomplete.length ? (
121
+ <>
122
+ {' '}
123
+ <span
124
+ className={clsx(classes.filterCheckboxes, classes.localFind)}
125
+ onClick={clearUpload}
126
+ >
127
+ INPUT CASE SET
128
+ </span>
129
+ {' '}
130
+ </>
131
+ ) : null}
132
+ {autocomplete.slice(0, maxItems).map((d, idx) => (
133
+ <>
134
+ <span
135
+ className={clsx(classes.filterCheckboxes, classes.facetSectionCases)}
136
+ key={idx}
137
+ onClick={() => deleteAutocompleteItem(d.title)}
138
+ >
139
+ {d.title}
140
+ </span>
141
+ {idx === (maxItems - 1) ? null : ' '}
142
+ </>
143
+ ))}
144
+ {autocomplete.length > maxItems && '...'}
145
+ {(((upload.length > 0 ? 1 : 0) + autocomplete.length) > 1)
146
+ ? <span className={classes.bracketsClose}>)</span>
147
+ : null}
148
+ </span>
149
+ </span>
150
+ ) : null}
151
+
152
+ {/* Facet Sidebar Selections */}
153
+ {((autocomplete.length || upload.length) && mappedInputs.length)
154
+ ? <span className={classes.operators}> AND </span>
155
+ : null}
156
+ {mappedInputs.map((filter, index) => (
157
+ <Filter
158
+ index={index}
159
+ type={filter.type}
160
+ data={filter}
161
+ maxItems={maxItems}
162
+ classes={classes}
163
+ onSectionClick={filter.type === CHECKBOX
164
+ ? resetFacetSection
165
+ : resetFacetSlider}
166
+ onItemClick={filter.type === CHECKBOX
167
+ ? resetFacetCheckbox
168
+ : resetFacetSlider}
169
+ />
170
+ ))}
171
+ </span>
172
+ </div>
173
+ );
174
+ }),
175
+ };
176
+ };
177
+
178
+ export default QueryBarGenerator;
@@ -0,0 +1,68 @@
1
+ /* eslint-disable no-unused-vars */
2
+ export default {
3
+ /* General Component Configuration */
4
+ config: {
5
+ /**
6
+ * The maximum number of items to display in a query bar facet section
7
+ * @var {number}
8
+ */
9
+ maxItems: 2,
10
+ },
11
+
12
+ /* Component Helper Functions */
13
+ functions: {
14
+ /**
15
+ * Clear all active facet/local find filters
16
+ *
17
+ * @returns {void}
18
+ */
19
+ clearAll: () => {},
20
+
21
+ /**
22
+ * Clear all active Local Find file upload filters
23
+ *
24
+ * @returns {void}
25
+ */
26
+ clearUpload: () => {},
27
+
28
+ /**
29
+ * Clear all active Local Find searchbox filters
30
+ *
31
+ * @returns {void}
32
+ */
33
+ clearAutocomplete: () => {},
34
+
35
+ /**
36
+ * Delete a specific Local Find searchbox filter (case)
37
+ *
38
+ * @param {string} title
39
+ * @returns {void}
40
+ */
41
+ deleteAutocompleteItem: (title) => {},
42
+
43
+ /**
44
+ * Reset a specific facet section (e.g. Program)
45
+ *
46
+ * @param {object} section the configuration object for the section
47
+ * @returns {void}
48
+ */
49
+ resetFacetSection: (section) => {},
50
+
51
+ /**
52
+ * Reset a specific facet checkbox (e.g. Program > TAILORx)
53
+ *
54
+ * @param {object} section the configuration object for the section
55
+ * @param {string} checkbox the name of the checkbox
56
+ * @returns {void}
57
+ */
58
+ resetFacetCheckbox: (section, checkbox) => {},
59
+
60
+ /**
61
+ * Reset a specific slider section (e.g. Age)
62
+ *
63
+ * @param {object} section the configuration object for the section
64
+ * @returns {void}
65
+ */
66
+ resetFacetSlider: (section) => {},
67
+ },
68
+ };
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Generate the default styling for the component
3
+ */
4
+ export default () => ({
5
+ queryWrapper: {
6
+ height: '120px',
7
+ backgroundColor: '#f1f1f1',
8
+ padding: '14px 14px 0px 35px',
9
+ overflowY: 'auto',
10
+ },
11
+ queryContainer: {
12
+ marginLeft: 7,
13
+ position: 'relative',
14
+ lineHeight: '2.4em',
15
+ letterSpacing: '0.5px',
16
+ fontFamily: 'Nunito',
17
+ fontSize: '14px',
18
+ color: '#0e3151',
19
+ },
20
+ filterName: {
21
+ textTransform: 'uppercase',
22
+ padding: '5px 6px 5px 7px',
23
+ borderRadius: 4,
24
+ fontSize: 12,
25
+ fontWeight: 600,
26
+ cursor: 'pointer',
27
+ },
28
+ filterCheckboxes: {
29
+ padding: '4px 7px 3px 6px',
30
+ borderRadius: 4,
31
+ fontSize: 12,
32
+ fontWeight: 600,
33
+ border: '0.75px solid #898989',
34
+ width: 'fit-content',
35
+ backgroundColor: '#fff',
36
+ cursor: 'pointer',
37
+ },
38
+ bracketsOpen: {
39
+ fontSize: 18,
40
+ fontFamily: 'Nunito Sans Semibold',
41
+ color: '#787878',
42
+ marginRight: 3,
43
+ fontWeight: 600,
44
+ },
45
+ bracketsClose: {
46
+ fontSize: 18,
47
+ fontFamily: 'Nunito Sans Semibold',
48
+ color: '#787878',
49
+ marginLeft: 3,
50
+ fontWeight: 600,
51
+ },
52
+ operators: {
53
+ color: '#646464',
54
+ marginLeft: '3px',
55
+ marginRight: '3px',
56
+ borderBottom: 'none',
57
+ textDecoration: 'none',
58
+ fontSize: 10,
59
+ fontWeight: 'bold',
60
+ },
61
+ clearQueryButton: {
62
+ margin: '1px',
63
+ marginLeft: -6,
64
+ fontWeight: 600,
65
+ fontSize: '13px',
66
+ color: '#fff',
67
+ borderRadius: '15px',
68
+ fontFamily: 'Nunito',
69
+ boxSizing: 'border-box',
70
+ backgroundColor: '#969696',
71
+ textTransform: 'capitalize',
72
+ border: '1px solid #B4B4B4',
73
+ padding: '1px 5px 0px 6px',
74
+ '&:hover': {
75
+ backgroundColor: '#969696',
76
+ },
77
+ },
78
+ divider: {
79
+ borderRight: '2px solid #969696',
80
+ marginLeft: 7,
81
+ },
82
+ /* Custom Styling by Project */
83
+ localFind: {
84
+ color: '#10A075',
85
+ },
86
+ localFindBackground: {
87
+ backgroundColor: '#C0E9D7',
88
+ },
89
+ facetSectionCases: {
90
+ color: '#10A075',
91
+ },
92
+ facetSectionCasesBackground: {
93
+ backgroundColor: '#C0E9D7',
94
+ },
95
+ facetSectionFiles: {
96
+ color: '#E636E4',
97
+ },
98
+ facetSectionFilesBackground: {
99
+ backgroundColor: '#F5C3F1',
100
+ },
101
+ facetSectionSamples: {
102
+ color: '#10BEFF',
103
+ },
104
+ facetSectionSamplesBackground: {
105
+ backgroundColor: '#C3EAF5',
106
+ },
107
+ });
package/src/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { QueryBarGenerator } from './generators/QueryBarGenerator';
2
+ export { default as DEFAULT_STYLES_QUERYBAR } from './generators/styles';
3
+ export { default as DEFAULT_CONFIG_QUERYBAR } from './generators/config';