@@ -42,8 +42,7 @@ export default {
};
},
methods: {
- processUpload(userFile) {
- console.log(store.documentHeaders);
+ processUpload(userFile, invalidHeaders) {
// handle null
if (userFile === null) {
this.invalidDataHeaders = [];
@@ -55,10 +54,8 @@ export default {
this.userFile = userFile;
// filter the documentHeaders to get the invalid headers
- this.invalidDataHeaders = this.store.documentHeaders.filter(
- (header) => !header.isValidData
- );
- console.log(this.invalidDataHeaders);
+ this.invalidDataHeaders = invalidHeaders;
+ //console.log(this.invalidDataHeaders);
// set isUploaded to true
this.isUploaded = true;
diff --git a/src/components/FileUpload.vue b/src/components/FileUpload.vue
index af357c8..3d88caf 100644
--- a/src/components/FileUpload.vue
+++ b/src/components/FileUpload.vue
@@ -9,7 +9,8 @@
import { read, utils } from "xlsx";
import { store } from '../store.js'
-import { HeaderAssociator } from '../helpers.js'
+import { UserHeader } from "@/userHeader";
+import { HeaderTemplate, associateHeaders } from "@/headerTemplate";
function findFirstNonBlankRow(worksheet) {
const range = utils.decode_range(worksheet['!ref']);
@@ -58,10 +59,21 @@ export default {
const resp = await fetch(process.env.VUE_APP_TEMPLATE_HEADERS_ENDPOINT, configRequestOptions);
let respJson = await resp.json();
console.log(respJson);
- this.headerTemplateList = respJson["HeaderTemplate"];
+ this.headerTemplateList = respJson["HeaderTemplate"].map(headerTemplate => {
+ return new HeaderTemplate (headerTemplate["Header"],headerTemplate["HeaderRegex"],
+ this.validateData, headerTemplate["ValueRegex"], headerTemplate["Nullable"]);
+ });
+ // Sort this list to make association faster
+ this.headerTemplateList.sort((a,b) => {
+ const ha = a.header.toLowerCase();
+ const hb = b.header.toLowerCase();
+ if (ha < hb) return -1;
+ if (ha > hb) return 1;
+ return 0;
+ });
+ console.info("Recieved HeaderTemplateList: ", this.headerTemplateList);
//FIXME: This is only for testing purposes, REMOVE THIS
this.validateData = true;//respJson["ValidateData"];
- console.log(this.headerTemplateList);
console.log(this.validateData);
} catch (error) {
//FIXME: emit error internal issues
@@ -76,6 +88,14 @@ export default {
// Clear old file data
store.missingHeaders = [];
store.documentHeaders = [];
+
+ // If the user had previously selected a file,
+ // we need to clear the old header associations
+ if (this.userFile !== null) {
+ this.headerTemplateList.map(headerTemplate => {
+ headerTemplate.userHeader = null;
+ })
+ }
this.userFile = event.target.files[0];
this.canSubmit = true;
@@ -83,7 +103,6 @@ export default {
getHeaders(worksheet, sheetName, headerIndex) {
// Store the found headers
- var combinedHeadersString = "";
// Use the range to make sure we don't go out of bounds
const range = utils.decode_range(worksheet['!ref']);
for (let col = 0; col < range.e.c; col++){
@@ -91,13 +110,13 @@ export default {
let cellObj = worksheet[cellAddress];
// n represents number type (which is probably the start of cashflow dates)
if (cellObj === undefined || cellObj.t === 'n') { break }
- // Add the header to the combined headers string
- combinedHeadersString += cellObj.v;
- let headerAssociator = new HeaderAssociator(cellObj.v, sheetName, cellAddress);
- if (!this.validateData) {headerAssociator.isValidData = true;}
- store.documentHeaders.push(headerAssociator);
+ let dataAddress = utils.encode_cell({c: col, r: headerIndex + 1});
+ let dataValue = worksheet[dataAddress] ? worksheet[dataAddress].v : null;
+
+ // Record the user header
+ let userHeader = new UserHeader(cellObj.v, sheetName, cellAddress, dataValue);
+ store.documentHeaders.push(userHeader);
}
- return combinedHeadersString;
},
async parseUpload() {
@@ -111,8 +130,7 @@ export default {
return;
}
- var validWorksheets = []
- var combinedHeadersString = '';
+ let validWorksheets = false;
// Go through each worksheet
for (let sheetName of workbook.SheetNames) {
// Open the actual worksheet
@@ -123,73 +141,39 @@ export default {
// Probably not a sheet we need to process
console.warn(`${sheetName} | No header row found!`);
}
- // Add the header to the combined headers string
- // getHeaders will created the AssociatedHeaders objects
- combinedHeadersString += this.getHeaders(worksheet, sheetName, headerIndex);
- // Note which worksheets are actually being processed
- validWorksheets.push(sheetName);
+ // getHeaders will created the UserHeader objects
+ this.getHeaders(worksheet, sheetName, headerIndex);
+ validWorksheets = true;
}
- if (validWorksheets.length === 0) {
+ if (!validWorksheets) {
//FIXME: emit bad spreadsheet to App
console.error("No worksheets found!");
return;
}
- // Check each template regex against the combined headers string
- for (const headerTemplate of this.headerTemplateList) {
- // 'i' option means ignore case
- let headerRegex = RegExp(headerTemplate["HeaderRegex"],"i");
- let headerName = headerTemplate["Header"];
+ // Sort the user headers to make association faster
+ store.documentHeaders.sort((a,b) => {
+ const ha = a.label.toLowerCase();
+ const hb = b.label.toLowerCase();
+ if (ha < hb) return -1;
+ if (ha > hb) return 1;
+ return 0;
+ });
- // Check to see if the template header is present in the combined headers string
- let searchResults = headerRegex.exec(combinedHeadersString);
- if (searchResults === null) {
- store.missingHeaders.push(headerName);
- continue;
- }
- let docHeader = searchResults[0];
+ console.log("User Headers:", this.userHeaders);
+ console.log("Template Headers:", this.headerTemplateList);
+ let processedArrays = associateHeaders(store.documentHeaders, this.headerTemplateList);
+ console.log("UPDATED Template Headers:", this.headerTemplateList);
+ store.missingHeaders = this.headerTemplateList.filter(headerTemplate => !headerTemplate.isAssociated());
+ store.documentHeaders = processedArrays[0];
+ //TODO: Deal with invalid headers
+ let invalidHeaders = processedArrays[1];
- // Find the associated header
- for (let headerAssociator of store.documentHeaders) {
- if (headerAssociator.isSet()) {continue}
- if (headerAssociator.documentHeader === docHeader) {
- // Set the associated template header
- headerAssociator.swapTemplateHeader(headerName);
-
- if (this.validateData) {
- // If we want to validate the data, then check the data against the regex
- let isNullable = headerTemplate["Nullable"];
- let headerAddress = utils.decode_cell(headerAssociator.docHeaderAddress);
- // Now we can get the value of the cell below the header
- let valueCellAddress = utils.encode_cell(headerAddress.r + 1);
- // We need to know which worksheet this cell belongs to
- let worksheet = workbook.Sheets[headerAssociator.docWorksheetName];
- let valueObj = worksheet[valueCellAddress];
- // Check if the cell is null, if so does it matter?
- if (valueObj !== undefined ) {
- // Test the value against regex
- let valueRegex = RegExp(headerTemplate["ValueRegex"],'i');
- let dataValue = valueObj.v.toString();
- let isValid = valueRegex.test(dataValue);
- if (!isValid) {
- // record the invalid data and set isValidData to false
- headerAssociator.invalidData(dataValue);
- }
- } else {
- // isValid matches isNullable
- headerAssociator.isValidData = isNullable;
- }
- }
- // We found the header and processed it so stop looking
- break;
- }
- }
- }
//TODO: Remove logs
console.log(`Document headers (${store.documentHeaders.length}): ${store.documentHeaders}`);
- console.log(`Missing headers (${store.missingHeaders.length}): ${store.missingHeaders}`);
+ console.log(`Missing headers (${store.missingHeaders.length})`, store.missingHeaders);
// emit the uploaded file & parsed data up to parent
- this.$emit('parsed-upload', this.userFile);
+ this.$emit('parsed-upload', this.userFile, invalidHeaders);
}
}
}
diff --git a/src/components/HeaderCorrection.vue b/src/components/HeaderCorrection.vue
index 87c575b..58c99fc 100644
--- a/src/components/HeaderCorrection.vue
+++ b/src/components/HeaderCorrection.vue
@@ -4,11 +4,11 @@
{{itemText}}
-
@@ -22,51 +22,52 @@ export default {
type: String,
required: true
},
+ headerTemplateIndex: Number,
},
data() {
return {
- selectedDocHeaderIndex: null,
+ selectedHeader: "",
+ confirmedHeader: null,
isConfirmed: false,
store
}
},
methods: {
- updateSelectedDocHeader(event) {
- // If a correction was previously made, update the parent a correction was unmade
- if (this.isConfirmed) { this.$emit('header-change', -1); }
- this.isConfirmed = false;
- // If the old index is not null, we need to update it's docHeader to be null
- if (this.selectedDocHeaderIndex !== null) {
- this.store.documentHeaders[this.selectedDocHeaderIndex].swapTemplateHeader(null);
- }
- // Set the new index of the doc header
- this.selectedDocHeaderIndex = event.target.value;
- console.log(this.selectedDocHeaderIndex);
-
+ changeSelectedHeader(event) {
+ this.selectedHeader = event.target.value;
},
changeA() {
- // Change the templateHeader in the docHeader at selectedDocHeader
+ console.warn("BEFORE ",store.documentHeaders);
+ this.confirmedHeader = this.selectedHeader !== "" ? store.documentHeaders.splice(this.selectedHeader,1)[0] : null;
+ console.info("confirmedHeader ",this.confirmedHeader);
+ let oldHeader = store.missingHeaders[this.headerTemplateIndex]
+ .swapUserHeader(this.confirmedHeader);
this.isConfirmed = true;
- this.store.documentHeaders[this.selectedDocHeaderIndex].templateHeader = this.itemText;
+ console.warn("AFTER ",store.documentHeaders);
+
+ if (oldHeader) {
+ store.documentHeaders.push(oldHeader);
+ store.documentHeaders.sort((a,b) => {
+ const ha = a.label.toLowerCase();
+ const hb = b.label.toLowerCase();
+ if (ha < hb) return -1;
+ if (ha > hb) return 1;
+ return 0;
+ });
+ }
+ console.warn("AFTER 2",store.documentHeaders);
+ document.getElementById('sel').value = this.itemText;
this.$emit('header-change', 1);
}
},
computed: {
- filteredHeaders() {
- // Get the index of headers that are invalid
- return store.documentHeaders.reduce((acc, header, index) => {
- if (!header.isSet()) {
- acc.push(index);
- }
- return acc;
- }, []);
- },
firstValue() {
- // When a doc header is confirmed it is removed from the list, we need to set it here
- // If no doc header is confirmed, allow the user to select a null
- return this.isConfirmed ? this.store.documentHeaders[this.selectedDocHeaderIndex].documentHeader : null
+ return this.isConfirmed ? store.missingHeaders[this.headerTemplateIndex].userHeader.label : null;
}
+
}
+
+
}
diff --git a/src/components/MissingHeaderBox.vue b/src/components/MissingHeaderBox.vue
index 34b0a9d..c69142e 100644
--- a/src/components/MissingHeaderBox.vue
+++ b/src/components/MissingHeaderBox.vue
@@ -2,7 +2,7 @@
Missing Headers:
-
+
diff --git a/src/headerTemplate.js b/src/headerTemplate.js
index cb7b66a..8426a59 100644
--- a/src/headerTemplate.js
+++ b/src/headerTemplate.js
@@ -2,6 +2,8 @@
* Represents a HeaderTemplate for associating UserHeaders in an uploaded Excel file.
*/
export class HeaderTemplate {
+
+ userHeader = null;
/**
* Creates a new HeaderTemplate.
* @param {string} header - The label for this HeaderTemplate.
@@ -97,7 +99,7 @@ export class HeaderTemplate {
* Checks if this HeaderTemplate is associated with a UserHeader.
* @returns {boolean} - Returns true if associated, false otherwise.
*/
- isAssociated() { typeof this.userHeaders!== 'undefined' && this.userHeaders!== null; }
+ isAssociated() { return this.userHeader !== null }
swapUserHeader(newUserHeader = null) {
let oldUserHeader = this.userHeader;
diff --git a/src/helpers.js b/src/helpers.js
index 45c8450..634ea41 100644
--- a/src/helpers.js
+++ b/src/helpers.js
@@ -38,12 +38,12 @@ export class HeaderAssociator {
this.docHeaderAddress = address
}
- set isValidData(newValidData) {
+ set validAssociatedData(newValidData) {
if (typeof newValidData !== 'boolean') {
console.error(`${this.documentHeader} | HeaderAssociator.validData must be a boolean: ${newValidData}`);
- this.isValidData = false;
+ this.validAssociatedData = false;
}
- else this.isValidData = newValidData;
+ else this.validAssociatedData = newValidData;
}
swapTemplateHeader(newTemplateHeader) {
@@ -58,7 +58,7 @@ export class HeaderAssociator {
invalidData(dataSample) {
// If data is found to be invalid, set isValidData to false and record the data
this.docData = dataSample
- this.isValidData = false
+ this.validAssociatedData = false
}
isSet() {