@gpa-gemstone/common-pages 0.0.124 → 0.0.125

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/lib/BulkUpload.js CHANGED
@@ -57,6 +57,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
57
57
  exports.default = BulkUpload;
58
58
  var React = __importStar(require("react"));
59
59
  var react_interactive_1 = require("@gpa-gemstone/react-interactive");
60
+ var react_forms_1 = require("@gpa-gemstone/react-forms");
60
61
  var steps = [{ short: 'Upload', long: 'Upload', id: 'Upload' }, { short: 'Process', long: 'Process', id: 'Process' }, { short: "Review", id: 'Review', long: 'Review' }, { short: 'Complete', long: 'Complete', id: 'Complete' }];
61
62
  var fileExtRegex = /(\.[^.]+)$/;
62
63
  function BulkUpload(props) {
@@ -113,10 +114,7 @@ function BulkUpload(props) {
113
114
  return;
114
115
  props.OnComplete(data);
115
116
  }, [props.Step, data, props.OnComplete]);
116
- var handleFileUpload = function (evt) {
117
- if (evt.target == null || evt.target.files == null || evt.target.files.length === 0)
118
- return;
119
- var file = evt.target.files[0];
117
+ var handleFileUpload = function (file) {
120
118
  var matchArray = file.name.match(fileExtRegex);
121
119
  var fileExtension = matchArray != null ? matchArray[0].substring(1) : '';
122
120
  var pipelineIndex = props.Pipelines.findIndex(function (pipe) { return pipe.Select(file.type, fileExtension); });
@@ -134,6 +132,12 @@ function BulkUpload(props) {
134
132
  setRawFileContent(e.target.result);
135
133
  };
136
134
  };
135
+ var handleFileOnClear = function () {
136
+ setIsFileTypeValid(true);
137
+ setCurrentPipelineIndex(null);
138
+ setFileName(null);
139
+ setRawFileContent(null);
140
+ };
137
141
  return (React.createElement("div", { className: "container-fluid d-flex flex-column p-0 h-100" },
138
142
  React.createElement("div", { className: 'row h-100' },
139
143
  React.createElement("div", { className: 'col-12 d-flex flex-column h-100' },
@@ -144,9 +148,7 @@ function BulkUpload(props) {
144
148
  React.createElement(React.Fragment, null,
145
149
  React.createElement("div", { className: 'row justify-content-center' },
146
150
  React.createElement("div", { className: 'col-6' },
147
- React.createElement("div", { className: "custom-file" },
148
- React.createElement("input", { type: "file", className: "custom-file-input", id: "inputGroupFile02", onChange: handleFileUpload, accept: props.FileTypeAttribute, style: { cursor: 'pointer' } }),
149
- React.createElement("label", { className: "custom-file-label", htmlFor: "inputGroupFile02", "aria-describedby": "inputGroupFileAddon02" }, fileName == null ? 'Upload File' : fileName)))),
151
+ React.createElement(react_forms_1.FileUpload, { OnLoadHandler: handleFileUpload, OnClearHandler: handleFileOnClear, FileTypeAttribute: props.FileTypeAttribute }))),
150
152
  React.createElement("div", { className: 'row' },
151
153
  React.createElement("div", { className: 'col-12 h-100' }, currentPipelineIndex != null && ((_a = props.Pipelines[currentPipelineIndex]) === null || _a === void 0 ? void 0 : _a.AdditionalUploadUI) != null ? (_b = props.Pipelines[currentPipelineIndex]) === null || _b === void 0 ? void 0 : _b.AdditionalUploadUI : null)))
152
154
  : null,
@@ -62,6 +62,7 @@ var react_forms_1 = require("@gpa-gemstone/react-forms");
62
62
  var react_table_1 = require("@gpa-gemstone/react-table");
63
63
  var gpa_symbols_1 = require("@gpa-gemstone/gpa-symbols");
64
64
  var react_table_2 = require("@gpa-gemstone/react-table");
65
+ var lodash_1 = require("lodash");
65
66
  var AdditionalUploadUI = function (props) {
66
67
  return (React.createElement("div", { className: 'row justify-content-center m-0' },
67
68
  React.createElement("div", { className: 'col-6 p-0' },
@@ -76,19 +77,19 @@ function useCSVPipeline(csvFields) {
76
77
  };
77
78
  }
78
79
  function CsvPipelineEditStep(props) {
79
- var _a, _b;
80
+ var _a, _b, _c, _d;
80
81
  var rawDataRef = React.useRef();
81
- var _c = React.useState([]), headers = _c[0], setHeaders = _c[1];
82
- var _d = React.useState(new Map()), headerMap = _d[0], setHeaderMap = _d[1];
83
- var _e = React.useState([]), data = _e[0], setData = _e[1];
84
- var _f = React.useState([]), pagedData = _f[0], setPagedData = _f[1];
85
- var _g = React.useState(true), isFileParseable = _g[0], setIsFileParseable = _g[1];
86
- var _h = React.useState(false), isCSVMissingHeaders = _h[0], setIsCSVMissingHeaders = _h[1];
87
- var _j = React.useState(false), isCSVMissingDataCells = _j[0], setIsCSVMissingDataCells = _j[1];
88
- var _k = React.useState(0), page = _k[0], setPage = _k[1];
89
- var _l = React.useState(1), totalPages = _l[0], setTotalPages = _l[1];
90
- var _m = React.useState(true), showDataHeaderAlert = _m[0], setShowDataHeaderAlert = _m[1];
91
- var _o = React.useState(true), showDataOrHeaderAlert = _o[0], setShowDataOrHeaderAlert = _o[1];
82
+ var _e = React.useState([]), headers = _e[0], setHeaders = _e[1];
83
+ var _f = React.useState(new Map()), headerMap = _f[0], setHeaderMap = _f[1];
84
+ var _g = React.useState([]), data = _g[0], setData = _g[1];
85
+ var _h = React.useState([]), pagedData = _h[0], setPagedData = _h[1];
86
+ var _j = React.useState(true), isFileParseable = _j[0], setIsFileParseable = _j[1];
87
+ var _k = React.useState(false), isCSVMissingHeaders = _k[0], setIsCSVMissingHeaders = _k[1];
88
+ var _l = React.useState(false), isCSVMissingDataCells = _l[0], setIsCSVMissingDataCells = _l[1];
89
+ var _m = React.useState(0), page = _m[0], setPage = _m[1];
90
+ var _o = React.useState(1), totalPages = _o[0], setTotalPages = _o[1];
91
+ var _p = React.useState(true), showDataHeaderAlert = _p[0], setShowDataHeaderAlert = _p[1];
92
+ var _q = React.useState(true), showDataOrHeaderAlert = _q[0], setShowDataOrHeaderAlert = _q[1];
92
93
  React.useEffect(function () {
93
94
  if (data.length === 0)
94
95
  return;
@@ -102,7 +103,7 @@ function CsvPipelineEditStep(props) {
102
103
  if (props.AdditionalProps == null)
103
104
  return;
104
105
  props.AdditionalProps.Fields.forEach(function (field) {
105
- var _a;
106
+ var _a, _b;
106
107
  var matchedHeader = (_a = Array.from(headerMap.entries()).find(function (_a) {
107
108
  var value = _a[1];
108
109
  return value === field.Field;
@@ -113,27 +114,43 @@ function CsvPipelineEditStep(props) {
113
114
  return; // return early if the field was never mapped to a header
114
115
  }
115
116
  var fieldIndex = headers.indexOf(matchedHeader);
117
+ var foundDuplicate = false;
118
+ var foundEmpty = false;
119
+ var foundInvalid = false;
116
120
  var uniqueValues = new Set();
117
121
  //Need to also make sure that all the fields that have the Required flag got mapped to a header...
118
122
  data.forEach(function (row) {
119
123
  var value = row[fieldIndex + 1]; //+1 for row index value
120
- // Check uniqueness
124
+ // Unique check
121
125
  if (field.Unique) {
122
126
  if (uniqueValues.has(value))
123
- errors.push("All ".concat(field.Label, " values must be unique."));
127
+ foundDuplicate = true;
124
128
  else
125
129
  uniqueValues.add(value);
126
130
  }
127
- // Check allowed emptiness
128
- if (!field.AllowEmpty && (value == null || (value !== null && value !== void 0 ? value : '').trim() === ""))
129
- errors.push("All ".concat(field.Label, " cannot be empty."));
130
- //Check validity
131
+ // Allowed emptiness
132
+ if (!field.AllowEmpty && (value == null || (value.trim() === '')))
133
+ foundEmpty = true;
134
+ // Validate
131
135
  if (!field.Validate(value))
132
- errors.push("All ".concat(field.Label, " must contain valid values."));
136
+ foundInvalid = true;
133
137
  });
138
+ if (field.Unique && foundDuplicate)
139
+ errors.push("All ".concat(field.Label, " values must be unique."));
140
+ if (foundEmpty)
141
+ errors.push("All ".concat(field.Label, " cannot be empty."));
142
+ if (foundInvalid)
143
+ errors.push("All ".concat(field.Label, " must contain valid values."));
144
+ //Check for SameValueForAllRows
145
+ if ((_b = field.SameValueForAllRows) !== null && _b !== void 0 ? _b : false) {
146
+ var allValues = data.map(function (row) { var _a; return (_a = row[fieldIndex + 1]) !== null && _a !== void 0 ? _a : ''; });
147
+ if (new Set(allValues).size > 1)
148
+ errors.push("All rows for ".concat(field.Label, " must contain the same value."));
149
+ }
134
150
  });
135
- props.SetErrors(errors);
136
- }, [data, headers, headerMap, isFileParseable]);
151
+ if (!(0, lodash_1.isEqual)(props.Errors.sort(), errors.sort()))
152
+ props.SetErrors(errors);
153
+ }, [data, headers, headerMap, isFileParseable, (_a = props.AdditionalProps) === null || _a === void 0 ? void 0 : _a.Fields]);
137
154
  React.useEffect(function () {
138
155
  if (props.RawFileData == null || props.AdditionalProps == null || rawDataRef.current === props.RawFileData)
139
156
  return;
@@ -153,6 +170,31 @@ function CsvPipelineEditStep(props) {
153
170
  setHeaderMap(autoMapHeaders(parsedData.Headers, props.AdditionalProps.Fields.map(function (field) { return field.Field; })));
154
171
  rawDataRef.current = props.RawFileData;
155
172
  }, [props.RawFileData, props.AdditionalProps]);
173
+ React.useEffect(function () {
174
+ var _a, _b;
175
+ if (((_a = props.AdditionalProps) === null || _a === void 0 ? void 0 : _a.Fields) == null || ((_b = props.AdditionalProps) === null || _b === void 0 ? void 0 : _b.Fields.length) === 0 || data.length === 0)
176
+ return;
177
+ var requiredCount = props.AdditionalProps.Fields.filter(function (f) { return f.Required; }).length;
178
+ // If we already have enough columns, do nothing
179
+ if (headers.length >= requiredCount)
180
+ return;
181
+ // Extend 'headers' array (e.g., "A", "B", "C"...)
182
+ var extendedHeaders = __spreadArray([], headers, true);
183
+ for (var i = headers.length; i < requiredCount; i++) {
184
+ extendedHeaders.push(String.fromCharCode(65 + i)); // 'A', 'B', 'C', ...
185
+ }
186
+ // Extend each row in 'data' with blank strings for the new columns
187
+ var extendedData = data.map(function (row) {
188
+ // row already has an index at row[0], plus (headers.length - 1) columns
189
+ var neededCols = requiredCount - (row.length - 1);
190
+ if (neededCols > 0) {
191
+ return __spreadArray(__spreadArray([], row, true), Array(neededCols).fill(''), true);
192
+ }
193
+ return row;
194
+ });
195
+ setHeaders(extendedHeaders);
196
+ setData(extendedData);
197
+ }, [(_b = props.AdditionalProps) === null || _b === void 0 ? void 0 : _b.Fields]);
156
198
  React.useEffect(function () {
157
199
  if (props.AdditionalProps == null || props.Errors.length !== 0)
158
200
  return;
@@ -173,7 +215,7 @@ function CsvPipelineEditStep(props) {
173
215
  mappedData.push(record);
174
216
  });
175
217
  props.SetData(mappedData);
176
- }, [data, headers, headerMap, (_a = props.AdditionalProps) === null || _a === void 0 ? void 0 : _a.Fields, props.Errors]);
218
+ }, [data, headers, headerMap, (_c = props.AdditionalProps) === null || _c === void 0 ? void 0 : _c.Fields, props.Errors]);
177
219
  var getFieldSelect = React.useCallback(function (header) {
178
220
  var _a;
179
221
  if (props.AdditionalProps == null || ((_a = props.AdditionalProps) === null || _a === void 0 ? void 0 : _a.Fields.length) === 0)
@@ -185,7 +227,7 @@ function CsvPipelineEditStep(props) {
185
227
  "=", matchedField === null || matchedField === void 0 ? void 0 :
186
228
  matchedField.Help) : undefined;
187
229
  return React.createElement(react_forms_1.Select, { Record: { Header: header, Value: field }, EmptyOption: true, Options: props.AdditionalProps.Fields.map(function (field) { return ({ Value: field.Field, Label: field.Label }); }), Field: "Value", Setter: function (record) { return updateMap(record.Header, record.Value); }, Label: ' ', Help: help });
188
- }, [(_b = props.AdditionalProps) === null || _b === void 0 ? void 0 : _b.Fields, headerMap]);
230
+ }, [(_d = props.AdditionalProps) === null || _d === void 0 ? void 0 : _d.Fields, headerMap]);
189
231
  var handleValueChange = function (rowIndex, colIndex, value) {
190
232
  setData(function (prevData) {
191
233
  var newData = __spreadArray([], prevData, true);
@@ -225,7 +267,7 @@ function CsvPipelineEditStep(props) {
225
267
  React.createElement("p", { style: { whiteSpace: 'nowrap' } }, isCSVMissingDataCells ? 'Missing data cells were added to meet the number of required fields.' : 'Missing headers were added to meet the number of required fields.'))))) : null,
226
268
  React.createElement("div", { className: 'row flex-grow-1', style: { overflowY: 'hidden' } },
227
269
  React.createElement("div", { className: 'col-12 h-100' },
228
- React.createElement(react_table_1.ConfigurableTable, { Data: pagedData, SortKey: '', Ascending: false, OnSort: function () { }, KeySelector: function (data) { return data[0]; }, TheadStyle: { width: '100%', display: 'table-header-group', }, TbodyStyle: { width: '100%', display: 'block', height: '100%' }, RowStyle: { display: 'table-row', width: '100%', height: 'auto' }, TableStyle: { width: '100%', height: '100%', tableLayout: 'fixed', marginBottom: 0, display: 'block' }, TableClass: 'table', ModalZIndex: 9995 },
270
+ React.createElement(react_table_1.ConfigurableTable, { Data: pagedData, key: headers.join(','), SortKey: '', Ascending: false, OnSort: function () { }, KeySelector: function (data) { return data[0]; }, TheadStyle: { width: '100%', display: 'table-header-group', }, TbodyStyle: { width: '100%', display: 'block', height: '100%' }, RowStyle: { display: 'table-row', width: '100%', height: 'auto' }, TableStyle: { width: '100%', height: '100%', tableLayout: 'fixed', marginBottom: 0, display: 'block' }, TableClass: 'table', ModalZIndex: 9995 },
229
271
  headers.map(function (header, i) {
230
272
  return React.createElement(react_table_1.ConfigurableColumn, { Key: header, Label: header, Default: true },
231
273
  React.createElement(react_table_1.Column, { Key: header, Field: i + 1, AllowSort: false, Content: function (_a) {
@@ -239,6 +281,7 @@ function CsvPipelineEditStep(props) {
239
281
  var value = item[field];
240
282
  var isValid = matchedField.Validate(value);
241
283
  var feedback = matchedField.Feedback;
284
+ var selectOptions = matchedField.SelectOptions;
242
285
  var allValues = {};
243
286
  headers.forEach(function (header, index) {
244
287
  var mappedField = headerMap.get(header);
@@ -246,7 +289,7 @@ function CsvPipelineEditStep(props) {
246
289
  allValues[mappedField] = item[index + 1];
247
290
  }
248
291
  });
249
- return (React.createElement(matchedField.EditComponent, { Value: value, SetValue: function (val) { return handleValueChange(parseInt(item[0]), field, val); }, Valid: isValid, Feedback: feedback, AllRecordValues: allValues }));
292
+ return (React.createElement(matchedField.EditComponent, { Value: value, SetValue: function (val) { return handleValueChange(parseInt(item[0]), field, val); }, Valid: isValid, Feedback: feedback, AllRecordValues: allValues, SelectOptions: selectOptions }));
250
293
  } },
251
294
  getHeader(header),
252
295
  getFieldSelect(header)));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gpa-gemstone/common-pages",
3
- "version": "0.0.124",
3
+ "version": "0.0.125",
4
4
  "description": "Common UI pages for GPA products",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -44,12 +44,12 @@
44
44
  "typescript": "5.5.3"
45
45
  },
46
46
  "dependencies": {
47
- "@gpa-gemstone/application-typings": "0.0.78",
48
- "@gpa-gemstone/gpa-symbols": "0.0.45",
49
- "@gpa-gemstone/helper-functions": "0.0.36",
50
- "@gpa-gemstone/react-forms": "1.1.77",
51
- "@gpa-gemstone/react-interactive": "1.0.137",
52
- "@gpa-gemstone/react-table": "1.2.58",
47
+ "@gpa-gemstone/application-typings": "0.0.79",
48
+ "@gpa-gemstone/gpa-symbols": "0.0.46",
49
+ "@gpa-gemstone/helper-functions": "0.0.37",
50
+ "@gpa-gemstone/react-forms": "1.1.78",
51
+ "@gpa-gemstone/react-interactive": "1.0.138",
52
+ "@gpa-gemstone/react-table": "1.2.59",
53
53
  "@reduxjs/toolkit": "1.8.3",
54
54
  "crypto-js": "^4.2.0",
55
55
  "moment": "^2.29.4",