@gpa-gemstone/common-pages 0.0.124 → 0.0.125

Sign up to get free protection for your applications and to get access to all the features.
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",