@gpa-gemstone/common-pages 0.0.17 → 0.0.22

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,36 +1,31 @@
1
1
  import * as React from 'react';
2
- interface IProps<T> {
3
- CollumnList: Search.IField<T>[];
4
- SetFilter: (filters: Search.IFilter<T>[]) => void;
5
- defaultCollumn?: Search.IField<T>;
6
- Direction?: 'left' | 'right';
7
- Width?: string | number;
8
- Label?: string;
2
+ import { GenericSlice, Search } from '@gpa-gemstone/react-interactive';
3
+ import { OpenXDA, SystemCenter } from '@gpa-gemstone/application-typings';
4
+ interface U {
5
+ ID: number | string;
6
+ }
7
+ interface IProps<T extends U> {
8
+ /** A Generic Slyce for the Search */
9
+ Slice: GenericSlice<T>;
10
+ /** Functions that gets available values for any ENUM Types */
11
+ GetEnum: (setOptions: (options: IOptions[]) => void, field: Search.IField<T>) => () => void;
12
+ /** Function that Grabs any additional Filters that shoudl be available (such as Addl Fields) */
13
+ GetAddlFields: (setAddlFields: (cols: Search.IField<T>[]) => void) => () => void;
9
14
  children: React.ReactNode;
10
- GetEnum?: EnumSetter<T>;
11
- ShowLoading?: boolean;
12
- ResultNote?: string;
13
15
  }
14
16
  interface IOptions {
15
17
  Value: string;
16
18
  Label: string;
17
19
  }
18
- declare type EnumSetter<T> = (setOptions: (options: IOptions[]) => void, field: Search.IField<T>) => () => void;
19
- export declare namespace Search {
20
- type FieldType = ('string' | 'number' | 'enum' | 'integer' | 'datetime' | 'boolean');
21
- interface IField<T> {
22
- label: string;
23
- key: string;
24
- type: FieldType;
25
- enum?: IOptions[];
26
- }
27
- type OperatorType = ('=' | '<>' | '>' | '<' | '>=' | '<=' | 'LIKE' | 'NOT LIKE' | 'IN' | 'NOT IN');
28
- interface IFilter<T> {
29
- FieldName: string;
30
- SearchText: string;
31
- Operator: Search.OperatorType;
32
- Type: Search.FieldType;
33
- }
20
+ /** This Implements a few standardized SearchBars */
21
+ export declare namespace DefaultSearch {
22
+ /** This Implements a standard Meter Search */
23
+ function Meter(props: IProps<SystemCenter.Types.DetailedMeter>): JSX.Element;
24
+ /** This Implements a standard Substation Search */
25
+ function Location(props: IProps<SystemCenter.Types.DetailedLocation>): JSX.Element;
26
+ /** This Implements a standard Transmission Asset Search */
27
+ function Asset(props: IProps<SystemCenter.Types.DetailedAsset>): JSX.Element;
28
+ /** This Implements a standard AssetGroup Search */
29
+ function AssetGroup(props: IProps<OpenXDA.Types.AssetGroup>): JSX.Element;
34
30
  }
35
- export default function SearchBar<T>(props: IProps<T>): JSX.Element;
36
31
  export {};
package/lib/SearchBar.js CHANGED
@@ -2,7 +2,7 @@
2
2
  // ******************************************************************************************************
3
3
  // SearchBar.tsx - Gbtc
4
4
  //
5
- // Copyright © 2020, Grid Protection Alliance. All Rights Reserved.
5
+ // Copyright © 2021, Grid Protection Alliance. All Rights Reserved.
6
6
  //
7
7
  // Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
8
8
  // the NOTICE file distributed with this work for additional information regarding copyright ownership.
@@ -17,287 +17,113 @@
17
17
  //
18
18
  // Code Modification History:
19
19
  // ----------------------------------------------------------------------------------------------------
20
- // 01/06/2020 - Christoph Lackner
20
+ // 12/17/2021 - Samuel Robinson
21
21
  // Generated original version of source code.
22
+ // 12/19/2021 - C. Lackner
23
+ // Cleaned up code.
22
24
  // ******************************************************************************************************
23
- var __assign = (this && this.__assign) || function () {
24
- __assign = Object.assign || function(t) {
25
- for (var s, i = 1, n = arguments.length; i < n; i++) {
26
- s = arguments[i];
27
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
28
- t[p] = s[p];
29
- }
30
- return t;
31
- };
32
- return __assign.apply(this, arguments);
33
- };
34
- var __spreadArrays = (this && this.__spreadArrays) || function () {
35
- for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
36
- for (var r = Array(s), k = 0, i = 0; i < il; i++)
37
- for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
38
- r[k] = a[j];
39
- return r;
25
+ var __spreadArray = (this && this.__spreadArray) || function (to, from) {
26
+ for (var i = 0, il = from.length, j = to.length; i < il; i++, j++)
27
+ to[j] = from[i];
28
+ return to;
40
29
  };
41
30
  Object.defineProperty(exports, "__esModule", { value: true });
31
+ exports.DefaultSearch = void 0;
42
32
  var React = require("react");
43
- var Modal_1 = require("./Modal");
44
- var LoadingIcon_1 = require("./LoadingIcon");
45
- var react_forms_1 = require("@gpa-gemstone/react-forms");
46
- var gpa_symbols_1 = require("@gpa-gemstone/gpa-symbols");
47
- function SearchBar(props) {
48
- var _a = React.useState(false), hover = _a[0], setHover = _a[1];
49
- var _b = React.useState(false), show = _b[0], setShow = _b[1];
50
- var _c = React.useState(false), isNew = _c[0], setIsNew = _c[1];
51
- var _d = React.useState([]), filters = _d[0], setFilters = _d[1];
52
- var _e = React.useState({ FieldName: props.CollumnList[0].key, SearchText: '', Operator: props.CollumnList[0].type === 'string' ? 'LIKE' : '=', Type: props.CollumnList[0].type }), filter = _e[0], setFilter = _e[1];
53
- var _f = React.useState(""), search = _f[0], setSearch = _f[1];
54
- var _g = React.useState(null), searchFilter = _g[0], setSearchFilter = _g[1];
55
- // Update SearchFilter if there are any Character and only do it every 500ms to avoid hammering the server while typing
56
- React.useEffect(function () {
57
- var handle = null;
58
- if (search.length > 0 && props.defaultCollumn !== undefined)
59
- handle = setTimeout(function () {
60
- if (props.defaultCollumn !== undefined)
61
- setSearchFilter({ FieldName: props.defaultCollumn.key, Operator: 'LIKE', Type: props.defaultCollumn.type, SearchText: ('*' + search + '*') });
62
- }, 500);
63
- else
64
- handle = setTimeout(function () {
65
- setSearchFilter(null);
66
- }, 500);
67
- return function () { if (handle !== null)
68
- clearTimeout(handle); };
69
- }, [search]);
70
- React.useEffect(function () {
71
- if (searchFilter !== null)
72
- props.SetFilter(__spreadArrays(filters, [searchFilter]));
73
- if (searchFilter === null)
74
- props.SetFilter(filters);
75
- }, [searchFilter]);
76
- function deleteFilter(f) {
77
- var index = filters.findIndex(function (fs) { return fs === f; });
78
- var filts = __spreadArrays(filters);
79
- filts.splice(index, 1);
80
- setFilters(filts);
81
- setHover(false);
82
- if (props.defaultCollumn !== undefined && searchFilter !== null)
83
- props.SetFilter(__spreadArrays(filts, [searchFilter]));
84
- else
85
- props.SetFilter(filts);
86
- }
87
- function addFilter() {
88
- var oldFilters = __spreadArrays(filters);
89
- var adjustedFilter = __assign({}, filter);
90
- if (adjustedFilter.Type === 'string' && adjustedFilter.Operator === 'LIKE')
91
- adjustedFilter.SearchText = '*' + adjustedFilter.SearchText + '*';
92
- oldFilters.push(adjustedFilter);
93
- setFilters(oldFilters);
94
- setFilter({ FieldName: props.CollumnList[0].key, SearchText: '', Operator: props.CollumnList[0].type === 'string' ? 'LIKE' : '=', Type: props.CollumnList[0].type });
95
- setFilter({ FieldName: props.CollumnList[0].key, SearchText: '', Operator: props.CollumnList[0].type === 'string' ? 'LIKE' : '=', Type: props.CollumnList[0].type });
96
- if (props.defaultCollumn !== undefined && searchFilter !== null)
97
- props.SetFilter(__spreadArrays(oldFilters, [searchFilter]));
98
- else
99
- props.SetFilter(oldFilters);
100
- }
101
- function editFilter(index) {
102
- setIsNew(false);
103
- var oldFilters = __spreadArrays(filters);
104
- var filt = oldFilters[index];
105
- oldFilters.splice(index, 1);
106
- if (filt.Type === 'string' && filt.Operator === 'LIKE')
107
- filt.SearchText = filt.SearchText.substr(1, filt.SearchText.length - 2);
108
- setShow(true);
109
- setFilters(oldFilters);
110
- setFilter(filt);
111
- if (props.defaultCollumn !== undefined && searchFilter !== null)
112
- props.SetFilter(__spreadArrays(oldFilters, [searchFilter]));
113
- else
114
- props.SetFilter(oldFilters);
115
- }
116
- ;
117
- function createFilter() {
118
- setShow(!show);
119
- setIsNew(true);
120
- setFilter({ FieldName: props.CollumnList[0].key, SearchText: '', Operator: props.CollumnList[0].type === 'string' ? 'LIKE' : '=', Type: props.CollumnList[0].type });
121
- }
122
- var content = (React.createElement(React.Fragment, null,
123
- React.createElement("form", null,
124
- React.createElement("div", { className: "row" },
125
- props.defaultCollumn !== undefined ?
126
- React.createElement("div", { className: "col" },
127
- React.createElement("div", { className: "input-group" },
128
- React.createElement("input", { className: "form-control mr-sm-2", type: "search", placeholder: "Search " + props.defaultCollumn.label, onChange: function (event) { return setSearch(event.target.value); } }),
129
- props.ShowLoading !== undefined && props.ShowLoading ? React.createElement("div", { className: "input-group-append" },
130
- " ",
131
- React.createElement(LoadingIcon_1.default, { Show: true }),
132
- " ") : null),
133
- React.createElement("p", { style: { marginTop: 2, marginBottom: 2 } }, props.ResultNote)) : null,
134
- React.createElement("div", { style: { position: 'relative', display: 'inline-block' }, className: 'col' },
135
- React.createElement("button", { className: "btn btn-primary", onClick: function (evt) { evt.preventDefault(); createFilter(); }, onMouseEnter: function () { return setHover(true); }, onMouseLeave: function () { return setHover(false); } }, "Add Filter"),
136
- React.createElement("div", { style: { width: window.innerWidth / 3, display: hover ? 'block' : 'none', position: 'absolute', backgroundColor: '#f1f1f1', boxShadow: '0px 8px 16px 0px rgba(0,0,0,0.2)', zIndex: 1, right: (props.Direction === 'right' ? 0 : undefined), left: (props.Direction === 'left' ? 0 : undefined) }, onMouseEnter: function () { return setHover(true); }, onMouseLeave: function () { return setHover(false); } },
137
- React.createElement("table", { className: 'table' },
138
- React.createElement("thead", null,
139
- React.createElement("tr", null,
140
- React.createElement("th", null, "Column"),
141
- React.createElement("th", null, "Operator"),
142
- React.createElement("th", null, "Search Text"),
143
- React.createElement("th", null, "Edit"),
144
- React.createElement("th", null, "Remove"))),
145
- React.createElement("tbody", null, filters.map(function (f, i) { return React.createElement("tr", { key: i },
146
- React.createElement("td", null, f.FieldName),
147
- React.createElement("td", null, f.Operator),
148
- React.createElement("td", null, f.SearchText),
149
- React.createElement("td", null,
150
- React.createElement("button", { className: "btn btn-sm", onClick: function (e) { return editFilter(i); } },
151
- React.createElement("span", null, gpa_symbols_1.Pencil))),
152
- React.createElement("td", null,
153
- React.createElement("button", { className: "btn btn-sm", onClick: function (e) { return deleteFilter(f); } },
154
- React.createElement("span", null, gpa_symbols_1.TrashCan)))); })))))))));
155
- return (React.createElement("div", { style: { width: '100%' } },
156
- React.createElement("nav", { className: "navbar navbar-expand-lg navbar-light bg-light" },
157
- React.createElement("div", { className: "collapse navbar-collapse", style: { width: '100%' } },
158
- React.createElement("ul", { className: "navbar-nav mr-auto", style: { width: '100%' } },
159
- props.Direction === 'right' ? props.children : null,
160
- props.Label !== undefined ?
161
- React.createElement("li", { className: "nav-item", style: { minWidth: (props.Width === undefined ? '150px' : undefined), width: props.Width, paddingRight: 10 } },
162
- React.createElement("fieldset", { className: "border", style: { padding: '10px', height: '100%' } },
163
- React.createElement("legend", { className: "w-auto", style: { fontSize: 'large' } },
164
- props.Label,
165
- ":"),
166
- content)) :
167
- React.createElement("li", { className: "nav-item", style: { minWidth: (props.Width === undefined ? '150px' : undefined), width: props.Width, paddingRight: 10 } }, content),
168
- props.Direction === 'left' ? props.children : null))),
169
- React.createElement(Modal_1.default, { Title: 'Add Filter', Show: show, CallBack: function (conf) { if (conf)
170
- addFilter(); setShow(false); }, ConfirmText: isNew ? 'Add' : 'Save', CancelText: isNew ? 'Close' : 'Delete' },
171
- React.createElement(react_forms_1.Select, { Record: filter, Field: 'FieldName', Options: props.CollumnList.map(function (fl) { return ({ Value: fl.key, Label: fl.label }); }), Setter: function (record) {
172
- var operator = "IN";
173
- var column = props.CollumnList.find(function (fl) { return fl.key === record.FieldName; });
174
- if (column !== undefined && column.type === 'string')
175
- operator = "LIKE";
176
- setFilter(function (prevFilter) { return (__assign(__assign({}, prevFilter), { FieldName: record.FieldName, SearchText: '', Operator: operator, Type: (column !== undefined ? column.type : 'string') })); });
177
- }, Label: 'Column' }),
178
- React.createElement(FilterCreator, { Filter: filter, Field: props.CollumnList.find(function (fl) { return fl.key === filter.FieldName; }), Setter: function (record) { return setFilter(record); }, Enum: (props.GetEnum === undefined ? undefined : props.GetEnum) }))));
179
- }
180
- exports.default = SearchBar;
181
- function FilterCreator(props) {
182
- var _a = React.useState([]), options = _a[0], setOptions = _a[1];
183
- React.useEffect(function () {
184
- if (props.Field === undefined)
185
- return;
186
- if (props.Field.enum !== undefined)
187
- setOptions(props.Field.enum);
188
- if (props.Enum !== undefined)
189
- return props.Enum(setOptions, props.Field);
190
- if (props.Field.enum === undefined)
191
- setOptions([]);
192
- }, [props.Field, props.Enum]);
193
- if (props.Field === undefined)
194
- return null;
195
- if (props.Field.type === "string") {
196
- return (React.createElement(React.Fragment, null,
197
- React.createElement("label", null, "Column type is string. Wildcard (*) can be used with 'LIKE' and 'NOT LIKE'"),
198
- React.createElement("div", { className: 'row' },
199
- React.createElement("div", { className: 'col-4' },
200
- React.createElement("select", { className: 'form-control', value: props.Filter.Operator, onChange: function (evt) {
201
- var value = evt.target.value;
202
- props.Setter(function (prevState) { return (__assign(__assign({}, prevState), { Operator: value })); });
203
- } },
204
- React.createElement("option", { value: 'LIKE' }, "LIKE"),
205
- React.createElement("option", { value: '=' }, "="),
206
- React.createElement("option", { value: 'NOT LIKE' }, "NOT LIKE"))),
207
- React.createElement("div", { className: 'col' },
208
- React.createElement("input", { className: 'form-control', value: props.Filter.SearchText, onChange: function (evt) {
209
- var value = evt.target.value;
210
- props.Setter(function (prevState) { return (__assign(__assign({}, prevState), { SearchText: value })); });
211
- } })))));
212
- }
213
- else if (props.Field.type === "integer" || props.Field.type === "number") {
214
- return (React.createElement(React.Fragment, null,
215
- React.createElement("label", null,
216
- "Column type is ",
217
- props.Field.type,
218
- "."),
219
- React.createElement("div", { className: 'row' },
220
- React.createElement("div", { className: 'col-4' },
221
- React.createElement("select", { className: 'form-control', value: props.Filter.Operator, onChange: function (evt) {
222
- var value = evt.target.value;
223
- props.Setter(function (prevState) { return (__assign(__assign({}, prevState), { Operator: value })); });
224
- } },
225
- React.createElement("option", { value: '=' }, "="),
226
- React.createElement("option", { value: '<>' }, "!="),
227
- React.createElement("option", { value: '>' }, ">"),
228
- React.createElement("option", { value: '>=' }, ">="),
229
- React.createElement("option", { value: '<' }, "<"),
230
- React.createElement("option", { value: '>=' }, ">="))),
231
- React.createElement("div", { className: 'col' },
232
- React.createElement("input", { type: 'number', className: 'form-control', value: props.Filter.SearchText, onChange: function (evt) {
233
- var value = evt.target.value;
234
- props.Setter(function (prevState) { return (__assign(__assign({}, prevState), { SearchText: value })); });
235
- } })))));
33
+ var react_interactive_1 = require("@gpa-gemstone/react-interactive");
34
+ var react_redux_1 = require("react-redux");
35
+ /** This Implements a few standardized SearchBars */
36
+ var DefaultSearch;
37
+ (function (DefaultSearch) {
38
+ /** This Implements a standard Meter Search */
39
+ function Meter(props) {
40
+ var defaultSearchcols = [
41
+ { label: 'AssetKey', key: 'AssetKey', type: 'string', isPivotField: false },
42
+ { label: 'Name', key: 'Name', type: 'string', isPivotField: false },
43
+ { label: 'Location', key: 'Location', type: 'string', isPivotField: false },
44
+ { label: 'Make', key: 'Make', type: 'string', isPivotField: false },
45
+ { label: 'Model', key: 'Model', type: 'string', isPivotField: false },
46
+ { label: 'Number of Assets', key: 'MappedAssets', type: 'number', isPivotField: false },
47
+ ];
48
+ var dispatch = react_redux_1.useDispatch();
49
+ var _a = React.useState([]), addlFieldCols = _a[0], setAddlFieldCols = _a[1];
50
+ var searchStatus = react_redux_1.useSelector(props.Slice.SearchStatus);
51
+ var sortField = react_redux_1.useSelector(props.Slice.SortField);
52
+ var ascending = react_redux_1.useSelector(props.Slice.Ascending);
53
+ var data = react_redux_1.useSelector(props.Slice.SearchResults);
54
+ React.useEffect(function () {
55
+ return props.GetAddlFields(setAddlFieldCols);
56
+ }, []);
57
+ var standardSearch = { label: 'Name', key: 'Name', type: 'string', isPivotField: false };
58
+ return React.createElement(react_interactive_1.SearchBar, { CollumnList: __spreadArray(__spreadArray([], addlFieldCols), defaultSearchcols), SetFilter: function (flds) { return dispatch(props.Slice.DBSearch({ filter: flds, sortField: sortField, ascending: ascending })); }, Direction: 'left', defaultCollumn: standardSearch, Width: '50%', Label: 'Search', ShowLoading: searchStatus === 'loading', ResultNote: searchStatus === 'error' ? 'Could not complete Search' : 'Found ' + data.length + ' Meter(s)', GetEnum: props.GetEnum }, props.children);
236
59
  }
237
- else if (props.Field.type === "datetime") {
238
- return (React.createElement(React.Fragment, null,
239
- React.createElement("label", null,
240
- "Column type is ",
241
- props.Field.type,
242
- "."),
243
- React.createElement("div", { className: 'row' },
244
- React.createElement("div", { className: 'col-4' },
245
- React.createElement("select", { className: 'form-control', value: props.Filter.Operator, onChange: function (evt) {
246
- var value = evt.target.value;
247
- props.Setter(function (prevState) { return (__assign(__assign({}, prevState), { Operator: value })); });
248
- } },
249
- React.createElement("option", { value: '=' }, "="),
250
- React.createElement("option", { value: '<>' }, "!="),
251
- React.createElement("option", { value: '>' }, ">"),
252
- React.createElement("option", { value: '>=' }, ">="),
253
- React.createElement("option", { value: '<' }, "<"),
254
- React.createElement("option", { value: '>=' }, ">="))),
255
- React.createElement("div", { className: 'col' },
256
- React.createElement("input", { type: 'date', className: 'form-control', value: props.Filter.SearchText.split(' ')[0], onChange: function (evt) {
257
- var value = evt.target.value;
258
- props.Setter(function (prevState) { return (__assign(__assign({}, prevState), { SearchText: (value + ' ' + (prevState.SearchText.split(' ').length > 1 ? prevState.SearchText.split(' ')[1] : '0:00')) })); });
259
- } }),
260
- React.createElement("input", { type: 'time', className: 'form-control', value: props.Filter.SearchText.split(' ').length > 1 ? props.Filter.SearchText.split(' ')[1] : '0:00', onChange: function (evt) {
261
- var value = evt.target.value;
262
- props.Setter(function (prevState) { return (__assign(__assign({}, prevState), { SearchText: (prevState.SearchText.split(' ')[0] + ' ' + value) })); });
263
- } })))));
60
+ DefaultSearch.Meter = Meter;
61
+ /** This Implements a standard Substation Search */
62
+ function Location(props) {
63
+ var standardSearch = { label: 'Name', key: 'Name', type: 'string', isPivotField: false };
64
+ var _a = React.useState([]), addlFieldCols = _a[0], setAddlFieldCols = _a[1];
65
+ var dispatch = react_redux_1.useDispatch();
66
+ var searchStatus = react_redux_1.useSelector(props.Slice.SearchStatus);
67
+ var sortField = react_redux_1.useSelector(props.Slice.SortField);
68
+ var ascending = react_redux_1.useSelector(props.Slice.Ascending);
69
+ var data = react_redux_1.useSelector(props.Slice.SearchResults);
70
+ var defaultSearchcols = [
71
+ { label: 'Name', key: 'Name', type: 'string', isPivotField: false },
72
+ { label: 'Key', key: 'LocationKey', type: 'string', isPivotField: false },
73
+ { label: 'Asset', key: 'Asset', type: 'string', isPivotField: false },
74
+ { label: 'Meter', key: 'Meter', type: 'string', isPivotField: false },
75
+ { label: 'Number of Assets', key: 'Assets', type: 'integer', isPivotField: false },
76
+ { label: 'Number of Meters', key: 'Meters', type: 'integer', isPivotField: false },
77
+ ];
78
+ React.useEffect(function () {
79
+ return props.GetAddlFields(setAddlFieldCols);
80
+ }, []);
81
+ return React.createElement(react_interactive_1.SearchBar, { CollumnList: __spreadArray(__spreadArray([], addlFieldCols), defaultSearchcols), SetFilter: function (flds) { return dispatch(props.Slice.DBSearch({ filter: flds, sortField: sortField, ascending: ascending })); }, Direction: 'left', defaultCollumn: standardSearch, Width: '50%', Label: 'Search', ShowLoading: searchStatus === 'loading', ResultNote: searchStatus === 'error' ? 'Could not complete Search' : 'Found ' + data.length + ' Substation(s)', GetEnum: props.GetEnum }, props.children);
264
82
  }
265
- else if (props.Field.type === "boolean") {
266
- return React.createElement(react_forms_1.CheckBox, { Record: props.Filter, Field: 'SearchText', Setter: function (filter) {
267
- props.Setter(function (prevFilter) { return (__assign(__assign({}, prevFilter), { Operator: '=', SearchText: filter.SearchText.toString() === 'true' ? '1' : '0' })); });
268
- }, Label: "Column type is boolean. Yes/On is checked." });
83
+ DefaultSearch.Location = Location;
84
+ /** This Implements a standard Transmission Asset Search */
85
+ function Asset(props) {
86
+ var standardSearch = { label: 'Name', key: 'AssetName', type: 'string', isPivotField: false };
87
+ var _a = React.useState([]), addlFieldCols = _a[0], setAddlFieldCols = _a[1];
88
+ var dispatch = react_redux_1.useDispatch();
89
+ var searchStatus = react_redux_1.useSelector(props.Slice.SearchStatus);
90
+ var sortField = react_redux_1.useSelector(props.Slice.SortField);
91
+ var ascending = react_redux_1.useSelector(props.Slice.Ascending);
92
+ var data = react_redux_1.useSelector(props.Slice.SearchResults);
93
+ var defaultSearchcols = [
94
+ { label: 'Key', key: 'AssetKey', type: 'string', isPivotField: false },
95
+ { label: 'Name', key: 'AssetName', type: 'string', isPivotField: false },
96
+ { label: 'Voltage (kV)', key: 'VoltageKV', type: 'number', isPivotField: false },
97
+ { label: 'Type', key: 'AssetType', type: 'enum', isPivotField: false },
98
+ { label: 'Meters', key: 'Meters', type: 'integer', isPivotField: false },
99
+ { label: 'Substations', key: 'Locations', type: 'integer', isPivotField: false },
100
+ ];
101
+ React.useEffect(function () {
102
+ return props.GetAddlFields(setAddlFieldCols);
103
+ }, []);
104
+ return React.createElement(react_interactive_1.SearchBar, { CollumnList: __spreadArray(__spreadArray([], addlFieldCols), defaultSearchcols), SetFilter: function (flds) { return dispatch(props.Slice.DBSearch({ filter: flds, sortField: sortField, ascending: ascending })); }, Direction: 'left', defaultCollumn: standardSearch, Width: '50%', Label: 'Search', ShowLoading: searchStatus === 'loading', ResultNote: searchStatus === 'error' ? 'Could not complete Search' : 'Found ' + data.length + ' Transmission Asset(s)', GetEnum: props.GetEnum }, props.children);
269
105
  }
270
- else {
271
- return (React.createElement(React.Fragment, null,
272
- React.createElement("label", null, "Column type is enumerable. Select from below."),
273
- React.createElement("ul", { style: { listStyle: 'none' } },
274
- React.createElement("li", null,
275
- React.createElement("div", { className: "form-check" },
276
- React.createElement("input", { type: "checkbox", className: "form-check-input", style: { zIndex: 1 }, onChange: function (evt) {
277
- if (evt.target.checked)
278
- props.Setter(function (prevSetter) { return (__assign(__assign({}, prevSetter), { SearchText: "(" + options.map(function (x) { return x.Value; }).join(',') + ")" })); });
279
- else
280
- props.Setter(function (prevSetter) { return (__assign(__assign({}, prevSetter), { SearchText: '' })); });
281
- }, defaultValue: 'off' }),
282
- React.createElement("label", { className: "form-check-label" }, "Select All"))),
283
- options.map(function (vli, index) { return React.createElement("li", { key: index },
284
- React.createElement("div", { className: "form-check" },
285
- React.createElement("input", { type: "checkbox", className: "form-check-input", style: { zIndex: 1 }, onChange: function (evt) {
286
- if (evt.target.checked) {
287
- var list = props.Filter.SearchText.replace('(', '').replace(')', '').split(',');
288
- list = list.filter(function (x) { return x !== ""; });
289
- list.push(vli.Value);
290
- var text_1 = "(" + list.join(',') + ")";
291
- props.Setter(function (prevSetter) { return (__assign(__assign({}, prevSetter), { SearchText: text_1 })); });
292
- }
293
- else {
294
- var list = props.Filter.SearchText.replace('(', '').replace(')', '').split(',');
295
- list = list.filter(function (x) { return x !== ""; });
296
- list = list.filter(function (x) { return x !== vli.Value; });
297
- var text_2 = "(" + list.join(',') + ")";
298
- props.Setter(function (prevSetter) { return (__assign(__assign({}, prevSetter), { SearchText: text_2 })); });
299
- }
300
- }, value: props.Filter.SearchText.indexOf(vli.Value) >= 0 ? 'on' : 'off', checked: props.Filter.SearchText.indexOf(vli.Value) >= 0 ? true : false }),
301
- React.createElement("label", { className: "form-check-label" }, vli.Label))); }))));
106
+ DefaultSearch.Asset = Asset;
107
+ /** This Implements a standard AssetGroup Search */
108
+ function AssetGroup(props) {
109
+ var standardSearch = { label: 'Name', key: 'AssetName', type: 'string', isPivotField: false };
110
+ var _a = React.useState([]), addlFieldCols = _a[0], setAddlFieldCols = _a[1];
111
+ var dispatch = react_redux_1.useDispatch();
112
+ var searchStatus = react_redux_1.useSelector(props.Slice.SearchStatus);
113
+ var sortField = react_redux_1.useSelector(props.Slice.SortField);
114
+ var ascending = react_redux_1.useSelector(props.Slice.Ascending);
115
+ var data = react_redux_1.useSelector(props.Slice.SearchResults);
116
+ var defaultSearchcols = [
117
+ { label: 'Name', key: 'Name', type: 'string', isPivotField: false },
118
+ { label: 'Number of Meter', key: 'Meters', type: 'integer', isPivotField: false },
119
+ { label: 'Number of Transmission Assets', key: 'Assets', type: 'integer', isPivotField: false },
120
+ { label: 'Number of Users', key: 'Users', type: 'integer', isPivotField: false },
121
+ { label: 'Show in PQ Dashboard', key: 'DisplayDashboard', type: 'boolean', isPivotField: false },
122
+ ];
123
+ React.useEffect(function () {
124
+ return props.GetAddlFields(setAddlFieldCols);
125
+ }, []);
126
+ return React.createElement(react_interactive_1.SearchBar, { CollumnList: __spreadArray(__spreadArray([], addlFieldCols), defaultSearchcols), SetFilter: function (flds) { return dispatch(props.Slice.DBSearch({ filter: flds, sortField: sortField, ascending: ascending })); }, Direction: 'left', defaultCollumn: standardSearch, Width: '50%', Label: 'Search', ShowLoading: searchStatus === 'loading', ResultNote: searchStatus === 'error' ? 'Could not complete Search' : 'Found ' + data.length + ' Asset Group(s)', GetEnum: props.GetEnum }, props.children);
302
127
  }
303
- }
128
+ DefaultSearch.AssetGroup = AssetGroup;
129
+ })(DefaultSearch = exports.DefaultSearch || (exports.DefaultSearch = {}));
@@ -0,0 +1,35 @@
1
+ /// <reference types="react" />
2
+ import { Column } from "@gpa-gemstone/react-table";
3
+ import { GenericSlice, Search } from "@gpa-gemstone/react-interactive";
4
+ import { OpenXDA, SystemCenter } from "@gpa-gemstone/application-typings";
5
+ interface U {
6
+ ID: number | string;
7
+ }
8
+ interface IProps<T extends U> {
9
+ Slice: GenericSlice<T>;
10
+ Selection: T[];
11
+ OnClose: (selected: T[], conf: boolean) => void;
12
+ Show: boolean;
13
+ Type?: 'single' | 'multiple';
14
+ Columns: Column<T>[];
15
+ Title: string;
16
+ GetEnum: (setOptions: (options: IOptions[]) => void, field: Search.IField<T>) => () => void;
17
+ GetAddlFields: (setAddlFields: (cols: Search.IField<T>[]) => void) => () => void;
18
+ MinSelection?: number;
19
+ }
20
+ interface IOptions {
21
+ Value: string;
22
+ Label: string;
23
+ }
24
+ /** This Implements a few standardized Selection Popups */
25
+ export declare namespace DefaultSelects {
26
+ /** This Implements a standard Meter Selection Modal */
27
+ function Meter(props: IProps<SystemCenter.Types.DetailedMeter>): JSX.Element;
28
+ /** This Implements a standard Substation Selection Modal */
29
+ function Location(props: IProps<SystemCenter.Types.DetailedLocation>): JSX.Element;
30
+ /** This Implements a standard Transmission Asset Selection Modal */
31
+ function Asset(props: IProps<SystemCenter.Types.DetailedAsset>): JSX.Element;
32
+ /** This Implements a standard Asset Group Selection Modal */
33
+ function AssetGroup(props: IProps<OpenXDA.Types.AssetGroup>): JSX.Element;
34
+ }
35
+ export {};
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ // ******************************************************************************************************
3
+ // SelectionPopup.tsx - Gbtc
4
+ //
5
+ // Copyright © 2021, Grid Protection Alliance. All Rights Reserved.
6
+ //
7
+ // Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
8
+ // the NOTICE file distributed with this work for additional information regarding copyright ownership.
9
+ // The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this
10
+ // file except in compliance with the License. You may obtain a copy of the License at:
11
+ //
12
+ // http://opensource.org/licenses/MIT
13
+ //
14
+ // Unless agreed to in writing, the subject software distributed under the License is distributed on an
15
+ // "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
16
+ // License for the specific language governing permissions and limitations.
17
+ //
18
+ // Code Modification History:
19
+ // ----------------------------------------------------------------------------------------------------
20
+ // 12/19/2021 - C. Lackner
21
+ // Generated original version of source code.
22
+ // ******************************************************************************************************
23
+ var __assign = (this && this.__assign) || function () {
24
+ __assign = Object.assign || function(t) {
25
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
26
+ s = arguments[i];
27
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
28
+ t[p] = s[p];
29
+ }
30
+ return t;
31
+ };
32
+ return __assign.apply(this, arguments);
33
+ };
34
+ Object.defineProperty(exports, "__esModule", { value: true });
35
+ exports.DefaultSelects = void 0;
36
+ var React = require("react");
37
+ var StandardSelectPopup_1 = require("./StandardSelectPopup");
38
+ var SearchBar_1 = require("./SearchBar");
39
+ /** This Implements a few standardized Selection Popups */
40
+ var DefaultSelects;
41
+ (function (DefaultSelects) {
42
+ /** This Implements a standard Meter Selection Modal */
43
+ function Meter(props) {
44
+ return React.createElement(StandardSelectPopup_1.default, __assign({}, props, { Searchbar: function (children) { return React.createElement(SearchBar_1.DefaultSearch.Meter, { Slice: props.Slice, GetAddlFields: props.GetAddlFields, GetEnum: props.GetEnum }, children); } }));
45
+ }
46
+ DefaultSelects.Meter = Meter;
47
+ /** This Implements a standard Substation Selection Modal */
48
+ function Location(props) {
49
+ return React.createElement(StandardSelectPopup_1.default, __assign({}, props, { Searchbar: function (children) { return React.createElement(SearchBar_1.DefaultSearch.Location, { Slice: props.Slice, GetAddlFields: props.GetAddlFields, GetEnum: props.GetEnum }, children); } }));
50
+ }
51
+ DefaultSelects.Location = Location;
52
+ /** This Implements a standard Transmission Asset Selection Modal */
53
+ function Asset(props) {
54
+ return React.createElement(StandardSelectPopup_1.default, __assign({}, props, { Searchbar: function (children) { return React.createElement(SearchBar_1.DefaultSearch.Asset, { Slice: props.Slice, GetAddlFields: props.GetAddlFields, GetEnum: props.GetEnum }, children); } }));
55
+ }
56
+ DefaultSelects.Asset = Asset;
57
+ /** This Implements a standard Asset Group Selection Modal */
58
+ function AssetGroup(props) {
59
+ return React.createElement(StandardSelectPopup_1.default, __assign({}, props, { Searchbar: function (children) { return React.createElement(SearchBar_1.DefaultSearch.AssetGroup, { Slice: props.Slice, GetAddlFields: props.GetAddlFields, GetEnum: props.GetEnum }, children); } }));
60
+ }
61
+ DefaultSelects.AssetGroup = AssetGroup;
62
+ })(DefaultSelects = exports.DefaultSelects || (exports.DefaultSelects = {}));
@@ -0,0 +1,19 @@
1
+ import { Column } from "@gpa-gemstone/react-table";
2
+ import * as React from 'react';
3
+ import { GenericSlice } from "@gpa-gemstone/react-interactive";
4
+ interface U {
5
+ ID: number | string;
6
+ }
7
+ interface IProps<T extends U> {
8
+ Slice: GenericSlice<T>;
9
+ Selection: T[];
10
+ OnClose: (selected: T[], conf: boolean) => void;
11
+ Show: boolean;
12
+ Searchbar: (children: React.ReactNode) => React.ReactNode;
13
+ Type?: 'single' | 'multiple';
14
+ Columns: Column<T>[];
15
+ Title: string;
16
+ MinSelection?: number;
17
+ }
18
+ export default function SelectPopup<T extends U>(props: IProps<T>): JSX.Element;
19
+ export {};
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+ // ******************************************************************************************************
3
+ // StandardSelectPopup.tsx - Gbtc
4
+ //
5
+ // Copyright © 2021, Grid Protection Alliance. All Rights Reserved.
6
+ //
7
+ // Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
8
+ // the NOTICE file distributed with this work for additional information regarding copyright ownership.
9
+ // The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this
10
+ // file except in compliance with the License. You may obtain a copy of the License at:
11
+ //
12
+ // http://opensource.org/licenses/MIT
13
+ //
14
+ // Unless agreed to in writing, the subject software distributed under the License is distributed on an
15
+ // "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
16
+ // License for the specific language governing permissions and limitations.
17
+ //
18
+ // Code Modification History:
19
+ // ----------------------------------------------------------------------------------------------------
20
+ // 12/19/2021 - C. Lackner
21
+ // Generated original version of source code.
22
+ // ******************************************************************************************************
23
+ var __spreadArray = (this && this.__spreadArray) || function (to, from) {
24
+ for (var i = 0, il = from.length, j = to.length; i < il; i++, j++)
25
+ to[j] = from[i];
26
+ return to;
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ var react_table_1 = require("@gpa-gemstone/react-table");
30
+ var React = require("react");
31
+ var react_redux_1 = require("react-redux");
32
+ var react_interactive_1 = require("@gpa-gemstone/react-interactive");
33
+ var _ = require("lodash");
34
+ var gpa_symbols_1 = require("@gpa-gemstone/gpa-symbols");
35
+ function SelectPopup(props) {
36
+ var dispatch = react_redux_1.useDispatch();
37
+ var sortField = react_redux_1.useSelector(props.Slice.SortField);
38
+ var ascending = react_redux_1.useSelector(props.Slice.Ascending);
39
+ var data = react_redux_1.useSelector(props.Slice.SearchResults);
40
+ var _a = React.useState(props.Selection), selectedData = _a[0], setSelectedData = _a[1];
41
+ var _b = React.useState(''), sortKeySelected = _b[0], setSortKeySelected = _b[1];
42
+ var _c = React.useState(false), ascendingSelected = _c[0], setAscendingSelected = _c[1];
43
+ React.useEffect(function () {
44
+ setSelectedData(props.Selection);
45
+ }, [props.Selection]);
46
+ function AddCurrentList() {
47
+ var updatedData;
48
+ updatedData = selectedData.concat(data);
49
+ setSelectedData(_.uniqBy(updatedData, function (d) { return d.ID; }));
50
+ }
51
+ return (React.createElement(React.Fragment, null,
52
+ React.createElement(react_interactive_1.Modal, { Show: props.Show, Title: props.Title, ShowX: true, Size: 'xlg', CallBack: function (conf) { return props.OnClose(selectedData, conf); }, DisableConfirm: props.MinSelection !== undefined && selectedData.length < props.MinSelection, ConfirmShowToolTip: props.MinSelection !== undefined && selectedData.length < props.MinSelection, ConfirmToolTipContent: React.createElement("p", null,
53
+ gpa_symbols_1.CrossMark,
54
+ " At least ",
55
+ props.MinSelection,
56
+ " items must be selected. ") },
57
+ React.createElement("div", { className: "row" },
58
+ React.createElement("div", { className: "col" }, props.Searchbar(props.Type === 'multiple' ? React.createElement("li", { className: "nav-item", style: { width: '20%', paddingRight: 10 } },
59
+ React.createElement("fieldset", { className: "border", style: { padding: '10px', height: '100%' } },
60
+ React.createElement("legend", { className: "w-auto", style: { fontSize: 'large' } }, "Quick Selects:"),
61
+ React.createElement("form", null,
62
+ React.createElement("div", { className: "form-group" },
63
+ React.createElement("div", { className: "btn btn-primary", onClick: function (event) { event.preventDefault(); AddCurrentList(); } }, "Add Current List to Selection")),
64
+ React.createElement("div", { className: "form-group" },
65
+ React.createElement("div", { className: "btn btn-danger", onClick: function (event) { event.preventDefault(); setSelectedData([]); } }, "Remove All"))))) : null))),
66
+ React.createElement("div", { className: "row" },
67
+ React.createElement("div", { className: "col", style: { width: (props.Type === undefined || props.Type === 'single' ? '100%' : '60%') } },
68
+ React.createElement(react_table_1.default, { cols: props.Columns, tableClass: "table table-hover", data: data, sortKey: sortField, ascending: ascending, onSort: function (d) {
69
+ if (d.colKey === "Scroll")
70
+ return;
71
+ if (d.colKey === sortField)
72
+ dispatch(props.Slice.Sort({ SortField: sortField, Ascending: ascending }));
73
+ else {
74
+ dispatch(props.Slice.Sort({ SortField: d.colField, Ascending: true }));
75
+ }
76
+ }, onClick: function (d) { return setSelectedData(__spreadArray(__spreadArray([], selectedData.filter(function (item) { return item.ID !== d.row.ID; })), [d.row])); }, theadStyle: { fontSize: 'smaller', display: 'table', tableLayout: 'fixed', width: '100%' }, tbodyStyle: { display: 'block', overflowY: 'scroll', maxHeight: '400px', width: '100%' }, rowStyle: { fontSize: 'smaller', display: 'table', tableLayout: 'fixed', width: '100%' }, selected: props.Type === undefined || props.Type === 'single' ? function (item) { return selectedData.findIndex(function (d) { return d.ID === item.ID; }) > -1; } : function (item) { return false; } })),
77
+ props.Type === 'multiple' ? React.createElement("div", { className: "col", style: { width: '40%' } },
78
+ React.createElement("div", { style: { width: '100%' } },
79
+ React.createElement("h3", null, " Selected Assets ")),
80
+ React.createElement(react_table_1.default, { cols: props.Columns, tableClass: "table table-hover", data: selectedData, sortKey: sortKeySelected, ascending: ascendingSelected, onSort: function (d) {
81
+ if (d.colKey === sortKeySelected) {
82
+ var ordered = _.orderBy(selectedData, [d.colKey], [(!ascendingSelected ? "asc" : "desc")]);
83
+ setAscendingSelected(!ascendingSelected);
84
+ setSelectedData(ordered);
85
+ }
86
+ else {
87
+ var ordered = _.orderBy(selectedData, [d.colKey], ["asc"]);
88
+ setAscendingSelected(!ascendingSelected);
89
+ setSelectedData(ordered);
90
+ setSortKeySelected(d.colKey);
91
+ }
92
+ }, onClick: function () { return true; }, theadStyle: { fontSize: 'smaller', display: 'table', tableLayout: 'fixed', width: '100%' }, tbodyStyle: { display: 'block', overflowY: 'scroll', maxHeight: '400px', width: '100%' }, rowStyle: { fontSize: 'smaller', display: 'table', tableLayout: 'fixed', width: '100%' }, selected: function (item) { return false; } })) : null))));
93
+ }
94
+ exports.default = SelectPopup;
package/lib/index.d.ts CHANGED
@@ -4,4 +4,7 @@ import ByValueList from './ValueList/ByValueList';
4
4
  import ValueList from './ValueList/Group';
5
5
  import ByUser from './user/ByUser';
6
6
  import User from './user/User';
7
- export { Setting, Note, ValueList, ByValueList, User, ByUser };
7
+ import { DefaultSearch } from './SearchBar';
8
+ import SelectPopup from './StandardSelectPopup';
9
+ import DefaultSelects from './StandardSelectPopup';
10
+ export { Setting, Note, ValueList, ByValueList, User, ByUser, DefaultSearch, SelectPopup, DefaultSelects };
package/lib/index.js CHANGED
@@ -22,7 +22,7 @@
22
22
  //
23
23
  // ******************************************************************************************************
24
24
  Object.defineProperty(exports, "__esModule", { value: true });
25
- exports.ByUser = exports.User = exports.ByValueList = exports.ValueList = exports.Note = exports.Setting = void 0;
25
+ exports.DefaultSelects = exports.SelectPopup = exports.DefaultSearch = exports.ByUser = exports.User = exports.ByValueList = exports.ValueList = exports.Note = exports.Setting = void 0;
26
26
  var Setting_1 = require("./Setting");
27
27
  exports.Setting = Setting_1.default;
28
28
  var Note_1 = require("./Note");
@@ -35,3 +35,9 @@ var ByUser_1 = require("./user/ByUser");
35
35
  exports.ByUser = ByUser_1.default;
36
36
  var User_1 = require("./user/User");
37
37
  exports.User = User_1.default;
38
+ var SearchBar_1 = require("./SearchBar");
39
+ Object.defineProperty(exports, "DefaultSearch", { enumerable: true, get: function () { return SearchBar_1.DefaultSearch; } });
40
+ var StandardSelectPopup_1 = require("./StandardSelectPopup");
41
+ exports.SelectPopup = StandardSelectPopup_1.default;
42
+ var StandardSelectPopup_2 = require("./StandardSelectPopup");
43
+ exports.DefaultSelects = StandardSelectPopup_2.default;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gpa-gemstone/common-pages",
3
- "version": "0.0.17",
3
+ "version": "0.0.22",
4
4
  "description": "Common UI pages for GPA products",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -36,29 +36,29 @@
36
36
  },
37
37
  "homepage": "https://github.com/GridProtectionAlliance/gpa-gemstone#readme",
38
38
  "devDependencies": {
39
+ "@types/crypto-js": "4.0.2",
39
40
  "@types/jest": "^26.0.4",
41
+ "@types/jquery": "3.5.6",
40
42
  "jest": "^27.0.6",
41
43
  "prettier": "^2.3.2",
42
44
  "ts-jest": "^27.0.3",
43
45
  "tslint": "^6.1.3",
44
46
  "tslint-config-prettier": "^1.18.0",
45
- "typescript": "4.3.4",
46
- "@types/jquery": "3.5.6",
47
- "@types/crypto-js": "4.0.2"
47
+ "typescript": "4.3.4"
48
48
  },
49
49
  "dependencies": {
50
- "@gpa-gemstone/application-typings": "0.0.30",
50
+ "@gpa-gemstone/application-typings": "0.0.37",
51
51
  "@gpa-gemstone/gpa-symbols": "0.0.13",
52
- "@gpa-gemstone/react-forms": "1.1.12",
53
- "@gpa-gemstone/react-interactive": "1.0.23",
54
- "@gpa-gemstone/react-table": "1.2.4",
55
- "@gpa-gemstone/helper-functions": "0.0.8",
52
+ "@gpa-gemstone/helper-functions": "0.0.9",
53
+ "@gpa-gemstone/react-forms": "1.1.15",
54
+ "@gpa-gemstone/react-interactive": "1.0.32",
55
+ "@gpa-gemstone/react-table": "1.2.5",
56
+ "@reduxjs/toolkit": "1.6.0",
57
+ "crypto-js": "4.0.0",
56
58
  "moment": "^2.29.1",
57
59
  "react": "^17.0.2",
58
- "styled-components": "^5.3.0",
59
- "crypto-js": "4.0.0",
60
- "react-redux": "7.2.4",
61
- "@reduxjs/toolkit": "1.6.0"
60
+ "react-redux": "7.2.6",
61
+ "styled-components": "^5.3.3"
62
62
  },
63
63
  "publishConfig": {
64
64
  "access": "public"