@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 +9 -7
- package/lib/Pipelines/CSVPipeline.js +69 -26
- package/package.json +7 -7
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 (
|
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(
|
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
|
82
|
-
var
|
83
|
-
var
|
84
|
-
var
|
85
|
-
var
|
86
|
-
var
|
87
|
-
var
|
88
|
-
var
|
89
|
-
var
|
90
|
-
var
|
91
|
-
var
|
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
|
-
//
|
124
|
+
// Unique check
|
121
125
|
if (field.Unique) {
|
122
126
|
if (uniqueValues.has(value))
|
123
|
-
|
127
|
+
foundDuplicate = true;
|
124
128
|
else
|
125
129
|
uniqueValues.add(value);
|
126
130
|
}
|
127
|
-
//
|
128
|
-
if (!field.AllowEmpty && (value == null || (value
|
129
|
-
|
130
|
-
//
|
131
|
+
// Allowed emptiness
|
132
|
+
if (!field.AllowEmpty && (value == null || (value.trim() === '')))
|
133
|
+
foundEmpty = true;
|
134
|
+
// Validate
|
131
135
|
if (!field.Validate(value))
|
132
|
-
|
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.
|
136
|
-
|
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, (
|
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
|
-
}, [(
|
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.
|
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.
|
48
|
-
"@gpa-gemstone/gpa-symbols": "0.0.
|
49
|
-
"@gpa-gemstone/helper-functions": "0.0.
|
50
|
-
"@gpa-gemstone/react-forms": "1.1.
|
51
|
-
"@gpa-gemstone/react-interactive": "1.0.
|
52
|
-
"@gpa-gemstone/react-table": "1.2.
|
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",
|