@teselagen/ui 0.5.19 → 0.5.20

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.
@@ -1,4 +1,4 @@
1
- import React, { useEffect, useMemo, useRef, useState } from "react";
1
+ import React, { useEffect, useRef, useState } from "react";
2
2
  import {
3
3
  Button,
4
4
  Callout,
@@ -16,6 +16,7 @@ import classnames from "classnames";
16
16
  import { nanoid } from "nanoid";
17
17
  import papaparse, { unparse } from "papaparse";
18
18
  import downloadjs from "downloadjs";
19
+ import { configure, makeObservable, observable } from "mobx";
19
20
  import { observer } from "mobx-react";
20
21
  import UploadCsvWizardDialog, {
21
22
  SimpleInsertDataDialog
@@ -29,7 +30,7 @@ import {
29
30
  removeExt
30
31
  } from "@teselagen/file-utils";
31
32
  import tryToMatchSchemas from "./tryToMatchSchemas";
32
- import { isArray, isFunction, isPlainObject, noop } from "lodash-es";
33
+ import { forEach, isArray, isFunction, isPlainObject, noop } from "lodash-es";
33
34
  import { flatMap } from "lodash-es";
34
35
  import urljoin from "url-join";
35
36
  import popoverOverflowModifiers from "../utils/popoverOverflowModifiers";
@@ -37,12 +38,14 @@ import writeXlsxFile from "write-excel-file";
37
38
  import { startCase } from "lodash-es";
38
39
  import { getNewName } from "./getNewName";
39
40
  import { isObject } from "lodash-es";
40
- import { useDispatch } from "react-redux";
41
+ import { connect } from "react-redux";
41
42
  import { initialize } from "redux-form";
42
43
  import classNames from "classnames";
44
+ import { compose } from "recompose";
43
45
  import convertSchema from "../DataTable/utils/convertSchema";
44
46
  import { LoadingDots } from "./LoadingDots";
45
47
 
48
+ configure({ isolateGlobalState: true });
46
49
  const helperText = [
47
50
  `How to Use This Template to Upload New Data`,
48
51
  `1. Go to the first tab and delete the example data.`,
@@ -61,106 +64,58 @@ const helperSchema = [
61
64
  }
62
65
  ];
63
66
 
64
- const setValidateAgainstSchema = newValidateAgainstSchema => {
65
- if (!newValidateAgainstSchema) return { fields: [] };
66
- const schema = convertSchema(newValidateAgainstSchema);
67
- if (
68
- schema.fields.some(f => {
69
- if (f.path === "id") {
70
- return true;
71
- }
72
- return false;
73
- })
74
- ) {
75
- throw new Error(
76
- `Uploader was passed a validateAgainstSchema with a fields array that contains a field with a path of "id". This is not allowed.`
77
- );
67
+ class ValidateAgainstSchema {
68
+ fields = [];
69
+
70
+ constructor() {
71
+ makeObservable(this, {
72
+ fields: observable.shallow
73
+ });
78
74
  }
79
- return schema;
80
- };
81
75
 
82
- const InnerDropZone = ({
83
- getRootProps,
84
- getInputProps,
85
- isDragAccept,
86
- isDragReject,
87
- isDragActive,
88
- className,
89
- minimal,
90
- dropzoneDisabled,
91
- contentOverride,
92
- simpleAccept,
93
- innerIcon,
94
- innerText,
95
- validateAgainstSchema,
96
- handleManuallyEnterData,
97
- noBuildCsvOption,
98
- showFilesCount,
99
- fileList
100
- // isDragActive
101
- // isDragReject
102
- // isDragAccept
103
- }) => (
104
- <section>
105
- <div
106
- {...getRootProps()}
107
- className={classnames("tg-dropzone", className, {
108
- "tg-dropzone-minimal": minimal,
109
- "tg-dropzone-active": isDragActive,
110
- "tg-dropzone-reject": isDragReject, // tnr: the acceptClassName/rejectClassName doesn't work with file extensions (only mimetypes are supported when dragging). Thus we'll just always turn the drop area blue when dragging and let the filtering occur on drop. See https://github.com/react-dropzone/react-dropzone/issues/888#issuecomment-773938074
111
- "tg-dropzone-accept": isDragAccept,
112
- "tg-dropzone-disabled": dropzoneDisabled,
113
- "bp3-disabled": dropzoneDisabled
114
- })}
115
- >
116
- <input {...getInputProps()} />
117
- {contentOverride || (
118
- <div
119
- title={
120
- simpleAccept
121
- ? "Accepts only the following file types: " + simpleAccept
122
- : "Accepts any file input"
123
- }
124
- className="tg-upload-inner"
125
- >
126
- {innerIcon || <Icon icon="upload" iconSize={minimal ? 15 : 30} />}
127
- {innerText || (minimal ? "Upload" : "Click or drag to upload")}
128
- {validateAgainstSchema && !noBuildCsvOption && (
129
- <div
130
- style={{
131
- textAlign: "center",
132
- // fontSize: 18,
133
- marginTop: 7,
134
- marginBottom: 5
135
- }}
136
- onClick={handleManuallyEnterData}
137
- className="link-button"
138
- >
139
- ...or {manualEnterMessage}
140
- {/* <div
141
- style={{
142
- fontSize: 11,
143
- color: Colors.GRAY3,
144
- fontStyle: "italic"
145
- }}
146
- >
147
- {manualEnterSubMessage}
148
- </div> */}
149
- </div>
150
- )}
151
- </div>
152
- )}
153
- </div>
76
+ setValidateAgainstSchema(newValidateAgainstSchema) {
77
+ if (!newValidateAgainstSchema) {
78
+ this.fields = [];
79
+ return;
80
+ }
81
+ const schema = convertSchema(newValidateAgainstSchema);
82
+ if (
83
+ schema.fields.some(f => {
84
+ if (f.path === "id") {
85
+ return true;
86
+ }
87
+ return false;
88
+ })
89
+ ) {
90
+ throw new Error(
91
+ `Uploader was passed a validateAgainstSchema with a fields array that contains a field with a path of "id". This is not allowed.`
92
+ );
93
+ }
94
+ forEach(schema, (v, k) => {
95
+ this[k] = v;
96
+ });
97
+ }
98
+ }
154
99
 
155
- {showFilesCount ? (
156
- <div className="tg-upload-file-list-counter">
157
- Files: {fileList ? fileList.length : 0}
158
- </div>
159
- ) : null}
160
- </section>
161
- );
100
+ // autorun(() => {
101
+ // console.log(
102
+ // `validateAgainstSchemaStore?.fields:`,
103
+ // JSON.stringify(validateAgainstSchemaStore?.fields, null, 4)
104
+ // );
105
+ // });
106
+ // validateAgainstSchemaStore.fields = ["hahah"];
107
+ // validateAgainstSchemaStore.fields.push("yaa");
162
108
 
163
- const UploaderInner = ({
109
+ // const validateAgainstSchema = observable.shallow({
110
+ // fields: []
111
+ // })
112
+
113
+ // validateAgainstSchema.fields = ["hahah"];
114
+
115
+ // wink wink
116
+ const emptyPromise = Promise.resolve.bind(Promise);
117
+
118
+ function UploaderInner({
164
119
  accept: __accept,
165
120
  contentOverride: maybeContentOverride,
166
121
  innerIcon,
@@ -175,9 +130,7 @@ const UploaderInner = ({
175
130
  showUploadList = true,
176
131
  beforeUpload,
177
132
  fileList, //list of files with options: {name, loading, error, url, originalName, downloadName}
178
- onFileSuccess = async () => {
179
- return;
180
- }, //called each time a file is finished and before the file.loading gets set to false, needs to return a promise!
133
+ onFileSuccess = emptyPromise, //called each time a file is finished and before the file.loading gets set to false, needs to return a promise!
181
134
  onFieldSubmit = noop, //called when all files have successfully uploaded
182
135
  // fileFinished = noop,
183
136
  onRemove = noop, //called when a file has been selected to be removed
@@ -188,27 +141,22 @@ const UploaderInner = ({
188
141
  autoUnzip,
189
142
  disabled: _disabled,
190
143
  noBuildCsvOption,
144
+ initializeForm,
191
145
  showFilesCount,
192
146
  threeDotMenuItems,
193
147
  onPreviewClick
194
- }) => {
195
- const dispatch = useDispatch();
148
+ }) {
196
149
  let dropzoneDisabled = _disabled;
197
150
  let _accept = __accept;
151
+ const validateAgainstSchemaStore = useRef(new ValidateAgainstSchema());
198
152
  const [acceptLoading, setAcceptLoading] = useState();
199
153
  const [resolvedAccept, setResolvedAccept] = useState();
200
-
201
154
  if (resolvedAccept) {
202
155
  _accept = resolvedAccept;
203
156
  }
204
-
205
- const isAcceptPromise = useMemo(
206
- () =>
207
- __accept?.then ||
208
- (Array.isArray(__accept) ? __accept.some(a => a?.then) : false),
209
- [__accept]
210
- );
211
-
157
+ const isAcceptPromise =
158
+ __accept?.then ||
159
+ (Array.isArray(__accept) ? __accept.some(a => a?.then) : false);
212
160
  useEffect(() => {
213
161
  if (isAcceptPromise) {
214
162
  setAcceptLoading(true);
@@ -221,36 +169,35 @@ const UploaderInner = ({
221
169
  );
222
170
  }
223
171
  }, [__accept, isAcceptPromise]);
224
-
225
172
  if (isAcceptPromise && !resolvedAccept) {
226
173
  _accept = [];
227
174
  }
228
-
229
175
  if (acceptLoading) dropzoneDisabled = true;
230
- const accept = useMemo(
231
- () =>
232
- !_accept
233
- ? undefined
234
- : isAcceptPromise && !resolvedAccept
235
- ? []
236
- : isPlainObject(_accept)
237
- ? [_accept]
238
- : isArray(_accept)
239
- ? _accept
240
- : _accept.split(",").map(a => ({ type: a })),
241
- [_accept, isAcceptPromise, resolvedAccept]
242
- );
243
-
176
+ const accept = !_accept
177
+ ? undefined
178
+ : isAcceptPromise && !resolvedAccept
179
+ ? []
180
+ : isPlainObject(_accept)
181
+ ? [_accept]
182
+ : isArray(_accept)
183
+ ? _accept
184
+ : _accept.split(",").map(a => ({ type: a }));
244
185
  const callout = _callout || accept?.find?.(a => a?.callout)?.callout;
245
186
 
246
- const validateAgainstSchema = useMemo(
247
- () =>
248
- setValidateAgainstSchema(
249
- _validateAgainstSchema ||
250
- accept?.find?.(a => a?.validateAgainstSchema)?.validateAgainstSchema
251
- ),
252
- [_validateAgainstSchema, accept]
253
- );
187
+ const validateAgainstSchemaToUse =
188
+ _validateAgainstSchema ||
189
+ accept?.find?.(a => a?.validateAgainstSchema)?.validateAgainstSchema;
190
+
191
+ useEffect(() => {
192
+ // validateAgainstSchema
193
+ validateAgainstSchemaStore.current.setValidateAgainstSchema(
194
+ validateAgainstSchemaToUse
195
+ );
196
+ }, [validateAgainstSchemaToUse]);
197
+ let validateAgainstSchema;
198
+ if (validateAgainstSchemaToUse) {
199
+ validateAgainstSchema = validateAgainstSchemaStore.current;
200
+ }
254
201
 
255
202
  if (
256
203
  (validateAgainstSchema || autoUnzip) &&
@@ -268,7 +215,6 @@ const UploaderInner = ({
268
215
  const { showDialogPromise: showUploadCsvWizardDialog, comp } = useDialog({
269
216
  ModalComponent: UploadCsvWizardDialog
270
217
  });
271
-
272
218
  const { showDialogPromise: showSimpleInsertDataDialog, comp: comp2 } =
273
219
  useDialog({
274
220
  ModalComponent: SimpleInsertDataDialog
@@ -607,7 +553,7 @@ const UploaderInner = ({
607
553
  }
608
554
  {...getFileDownloadAttr(exampleFile)}
609
555
  key={i}
610
- />
556
+ ></MenuItem>
611
557
  );
612
558
  }
613
559
  )}
@@ -673,7 +619,7 @@ const UploaderInner = ({
673
619
  }}
674
620
  size={10}
675
621
  icon="download"
676
- />
622
+ ></Icon>
677
623
  )}
678
624
  </CustomTag>
679
625
  </PopOrTooltip>
@@ -685,8 +631,7 @@ const UploaderInner = ({
685
631
  // make the dots below "load"
686
632
 
687
633
  <>
688
- Accept Loading
689
- <LoadingDots />
634
+ Accept Loading<LoadingDots></LoadingDots>
690
635
  </>
691
636
  ) : (
692
637
  <>Accepts {simpleAccept}</>
@@ -705,135 +650,135 @@ const UploaderInner = ({
705
650
  .join(", ")
706
651
  : undefined
707
652
  }
708
- onDrop={async (_acceptedFiles, rejectedFiles) => {
709
- let acceptedFiles = [];
710
- for (const file of _acceptedFiles) {
711
- if ((validateAgainstSchema || autoUnzip) && isZipFile(file)) {
712
- const files = await filterFilesInZip(
713
- file,
714
- simpleAccept
715
- ?.split(", ")
716
- ?.map(a => (a.startsWith(".") ? a : "." + a)) || []
717
- );
718
- acceptedFiles.push(...files.map(f => f.originFileObj));
719
- } else {
720
- acceptedFiles.push(file);
653
+ {...{
654
+ onDrop: async (_acceptedFiles, rejectedFiles) => {
655
+ let acceptedFiles = [];
656
+ for (const file of _acceptedFiles) {
657
+ if ((validateAgainstSchema || autoUnzip) && isZipFile(file)) {
658
+ const files = await filterFilesInZip(
659
+ file,
660
+ simpleAccept
661
+ ?.split(", ")
662
+ ?.map(a => (a.startsWith(".") ? a : "." + a)) || []
663
+ );
664
+ acceptedFiles.push(...files.map(f => f.originFileObj));
665
+ } else {
666
+ acceptedFiles.push(file);
667
+ }
721
668
  }
722
- }
723
- cleanupFiles();
724
- if (rejectedFiles.length) {
725
- let msg = "";
726
- rejectedFiles.forEach(file => {
727
- if (msg) msg += "\n";
728
- msg +=
729
- `${file.file.name}: ` +
730
- file.errors.map(err => err.message).join(", ");
669
+ cleanupFiles();
670
+ if (rejectedFiles.length) {
671
+ let msg = "";
672
+ rejectedFiles.forEach(file => {
673
+ if (msg) msg += "\n";
674
+ msg +=
675
+ `${file.file.name}: ` +
676
+ file.errors.map(err => err.message).join(", ");
677
+ });
678
+ window.toastr &&
679
+ window.toastr.warning(
680
+ <div className="preserve-newline">{msg}</div>
681
+ );
682
+ }
683
+ if (!acceptedFiles.length) return;
684
+ setLoading(true);
685
+ acceptedFiles = trimFiles(acceptedFiles, fileLimit);
686
+
687
+ acceptedFiles.forEach(file => {
688
+ file.preview = URL.createObjectURL(file);
689
+ file.loading = true;
690
+ if (!file.id) {
691
+ file.id = nanoid();
692
+ }
693
+ filesToClean.current.push(file);
731
694
  });
732
- window.toastr &&
733
- window.toastr.warning(
734
- <div className="preserve-newline">{msg}</div>
735
- );
736
- }
737
- if (!acceptedFiles.length) return;
738
- setLoading(true);
739
- acceptedFiles = trimFiles(acceptedFiles, fileLimit);
740
695
 
741
- acceptedFiles.forEach(file => {
742
- file.preview = URL.createObjectURL(file);
743
- file.loading = true;
744
- if (!file.id) {
745
- file.id = nanoid();
696
+ if (readBeforeUpload) {
697
+ acceptedFiles = await Promise.all(
698
+ acceptedFiles.map(file => {
699
+ return new Promise((resolve, reject) => {
700
+ const reader = new FileReader();
701
+ reader.readAsText(file, "UTF-8");
702
+ reader.onload = evt => {
703
+ file.parsedString = evt.target.result;
704
+ resolve(file);
705
+ };
706
+ reader.onerror = err => {
707
+ console.error("err:", err);
708
+ reject(err);
709
+ };
710
+ });
711
+ })
712
+ );
746
713
  }
747
- filesToClean.current.push(file);
748
- });
714
+ const cleanedAccepted = acceptedFiles.map(file => {
715
+ return {
716
+ originFileObj: file,
717
+ originalFileObj: file,
718
+ id: file.id,
719
+ lastModified: file.lastModified,
720
+ lastModifiedDate: file.lastModifiedDate,
721
+ loading: file.loading,
722
+ name: file.name,
723
+ preview: file.preview,
724
+ size: file.size,
725
+ type: file.type,
726
+ ...(file.parsedString
727
+ ? { parsedString: file.parsedString }
728
+ : {})
729
+ };
730
+ });
749
731
 
750
- if (readBeforeUpload) {
751
- acceptedFiles = await Promise.all(
752
- acceptedFiles.map(file => {
753
- return new Promise((resolve, reject) => {
754
- const reader = new FileReader();
755
- reader.readAsText(file, "UTF-8");
756
- reader.onload = evt => {
757
- file.parsedString = evt.target.result;
758
- resolve(file);
759
- };
760
- reader.onerror = err => {
761
- console.error("err:", err);
762
- reject(err);
763
- };
764
- });
765
- })
766
- );
767
- }
768
- const cleanedAccepted = acceptedFiles.map(file => {
769
- return {
770
- originFileObj: file,
771
- originalFileObj: file,
772
- id: file.id,
773
- lastModified: file.lastModified,
774
- lastModifiedDate: file.lastModifiedDate,
775
- loading: file.loading,
776
- name: file.name,
777
- preview: file.preview,
778
- size: file.size,
779
- type: file.type,
780
- ...(file.parsedString
781
- ? { parsedString: file.parsedString }
782
- : {})
783
- };
784
- });
732
+ const toKeep = [];
733
+ if (validateAgainstSchema) {
734
+ const filesWIssues = [];
735
+ const filesWOIssues = [];
736
+ for (const [i, file] of cleanedAccepted.entries()) {
737
+ if (isCsvOrExcelFile(file)) {
738
+ let parsedF;
739
+ try {
740
+ parsedF = await parseCsvOrExcelFile(file, {
741
+ csvParserOptions: isFunction(
742
+ validateAgainstSchema.csvParserOptions
743
+ )
744
+ ? validateAgainstSchema.csvParserOptions({
745
+ validateAgainstSchema
746
+ })
747
+ : validateAgainstSchema.csvParserOptions
748
+ });
749
+ } catch (error) {
750
+ console.error("error:", error);
751
+ window.toastr &&
752
+ window.toastr.error(
753
+ `There was an error parsing your file. Please try again. ${
754
+ error.message || error
755
+ }`
756
+ );
757
+ return;
758
+ }
785
759
 
786
- const toKeep = [];
787
- if (validateAgainstSchema) {
788
- const filesWIssues = [];
789
- const filesWOIssues = [];
790
- for (const [i, file] of cleanedAccepted.entries()) {
791
- if (isCsvOrExcelFile(file)) {
792
- let parsedF;
793
- try {
794
- parsedF = await parseCsvOrExcelFile(file, {
795
- csvParserOptions: isFunction(
796
- validateAgainstSchema.csvParserOptions
797
- )
798
- ? validateAgainstSchema.csvParserOptions({
799
- validateAgainstSchema
800
- })
801
- : validateAgainstSchema.csvParserOptions
760
+ const {
761
+ csvValidationIssue: _csvValidationIssue,
762
+ matchedHeaders,
763
+ userSchema,
764
+ searchResults,
765
+ ignoredHeadersMsg
766
+ } = await tryToMatchSchemas({
767
+ incomingData: parsedF.data,
768
+ validateAgainstSchema
802
769
  });
803
- } catch (error) {
804
- console.error("error:", error);
805
- window.toastr &&
806
- window.toastr.error(
807
- `There was an error parsing your file. Please try again. ${
808
- error.message || error
809
- }`
770
+ if (userSchema?.userData?.length === 0) {
771
+ console.error(
772
+ `userSchema, parsedF.data:`,
773
+ userSchema,
774
+ parsedF.data
810
775
  );
811
- return;
812
- }
813
-
814
- const {
815
- csvValidationIssue: _csvValidationIssue,
816
- matchedHeaders,
817
- userSchema,
818
- searchResults,
819
- ignoredHeadersMsg
820
- } = await tryToMatchSchemas({
821
- incomingData: parsedF.data,
822
- validateAgainstSchema
823
- });
824
- if (userSchema?.userData?.length === 0) {
825
- console.error(
826
- `userSchema, parsedF.data:`,
827
- userSchema,
828
- parsedF.data
829
- );
830
- } else {
831
- toKeep.push(file);
832
- let csvValidationIssue = _csvValidationIssue;
833
- if (csvValidationIssue) {
834
- if (isObject(csvValidationIssue)) {
835
- dispatch(
836
- initialize(
776
+ } else {
777
+ toKeep.push(file);
778
+ let csvValidationIssue = _csvValidationIssue;
779
+ if (csvValidationIssue) {
780
+ if (isObject(csvValidationIssue)) {
781
+ initializeForm(
837
782
  `editableCellTable${
838
783
  cleanedAccepted.length > 1 ? `-${i}` : ""
839
784
  }`,
@@ -845,142 +790,149 @@ const UploaderInner = ({
845
790
  keepValues: true,
846
791
  updateUnregisteredFields: true
847
792
  }
848
- )
849
- );
850
- const err = Object.values(csvValidationIssue)[0];
851
- // csvValidationIssue = `It looks like there was an error with your data - \n\n${
852
- // err && err.message ? err.message : err
853
- // }.\n\nPlease review your headers and then correct any errors on the next page.`; //pass just the first error as a string
854
- const errMsg = err && err.message ? err.message : err;
855
- if (isPlainObject(errMsg)) {
856
- throw new Error(
857
- `errMsg is an object ${JSON.stringify(
858
- errMsg,
859
- null,
860
- 4
861
- )}`
862
793
  );
863
- }
864
- csvValidationIssue = (
865
- <div>
866
- <div>
867
- It looks like there was an error with your data
868
- (Correct on the Review Data page):
869
- </div>
870
- <div style={{ color: "red" }}>{errMsg}</div>
794
+ const err = Object.values(csvValidationIssue)[0];
795
+ // csvValidationIssue = `It looks like there was an error with your data - \n\n${
796
+ // err && err.message ? err.message : err
797
+ // }.\n\nPlease review your headers and then correct any errors on the next page.`; //pass just the first error as a string
798
+ const errMsg =
799
+ err && err.message ? err.message : err;
800
+ if (isPlainObject(errMsg)) {
801
+ throw new Error(
802
+ `errMsg is an object ${JSON.stringify(
803
+ errMsg,
804
+ null,
805
+ 4
806
+ )}`
807
+ );
808
+ }
809
+ csvValidationIssue = (
871
810
  <div>
872
- Please review your headers and then correct any
873
- errors on the next page.
811
+ <div>
812
+ It looks like there was an error with your
813
+ data (Correct on the Review Data page):
814
+ </div>
815
+ <div style={{ color: "red" }}>{errMsg}</div>
816
+ <div>
817
+ Please review your headers and then correct
818
+ any errors on the next page.
819
+ </div>
874
820
  </div>
875
- </div>
821
+ );
822
+ }
823
+ filesWIssues.push({
824
+ file,
825
+ csvValidationIssue,
826
+ ignoredHeadersMsg,
827
+ matchedHeaders,
828
+ userSchema,
829
+ searchResults
830
+ });
831
+ } else {
832
+ filesWOIssues.push({
833
+ file,
834
+ csvValidationIssue,
835
+ ignoredHeadersMsg,
836
+ matchedHeaders,
837
+ userSchema,
838
+ searchResults
839
+ });
840
+ const newFileName = removeExt(file.name) + `.csv`;
841
+
842
+ const { newFile, cleanedEntities } = getNewCsvFile(
843
+ userSchema.userData,
844
+ newFileName
876
845
  );
846
+
847
+ file.meta = parsedF.meta;
848
+ file.hasEditClick = true;
849
+ file.parsedData = cleanedEntities;
850
+ file.name = newFileName;
851
+ file.originFileObj = newFile;
852
+ file.originalFileObj = newFile;
877
853
  }
878
- filesWIssues.push({
879
- file,
880
- csvValidationIssue,
881
- ignoredHeadersMsg,
882
- matchedHeaders,
883
- userSchema,
884
- searchResults
885
- });
886
- } else {
887
- filesWOIssues.push({
888
- file,
889
- csvValidationIssue,
890
- ignoredHeadersMsg,
891
- matchedHeaders,
892
- userSchema,
893
- searchResults
854
+ }
855
+ } else {
856
+ toKeep.push(file);
857
+ }
858
+ }
859
+ if (filesWIssues.length) {
860
+ const { file } = filesWIssues[0];
861
+ const allFiles = [...filesWIssues, ...filesWOIssues];
862
+ const doAllFilesHaveSameHeaders = allFiles.every(f => {
863
+ if (f.userSchema.fields && f.userSchema.fields.length) {
864
+ return f.userSchema.fields.every((h, i) => {
865
+ return (
866
+ h.path === allFiles[0].userSchema.fields[i].path
867
+ );
894
868
  });
895
- const newFileName = removeExt(file.name) + `.csv`;
869
+ }
870
+ return false;
871
+ });
872
+ const multipleFiles = allFiles.length > 1;
873
+ const { res } = await showUploadCsvWizardDialog(
874
+ "onUploadWizardFinish",
875
+ {
876
+ dialogProps: {
877
+ title: `Fix Up File${multipleFiles ? "s" : ""} ${
878
+ multipleFiles
879
+ ? ""
880
+ : file.name
881
+ ? `"${file.name}"`
882
+ : ""
883
+ }`
884
+ },
885
+ doAllFilesHaveSameHeaders,
886
+ filesWIssues: allFiles,
887
+ validateAgainstSchema
888
+ }
889
+ );
896
890
 
891
+ if (!res) {
892
+ window.toastr.warning(`File Upload Aborted`);
893
+ return;
894
+ } else {
895
+ allFiles.forEach(({ file }, i) => {
896
+ const newEntities = res[i];
897
+ // const newFileName = removeExt(file.name) + `_updated.csv`;
898
+ //swap out file with a new csv file
897
899
  const { newFile, cleanedEntities } = getNewCsvFile(
898
- userSchema.userData,
899
- newFileName
900
+ newEntities,
901
+ file.name
900
902
  );
901
903
 
902
- file.meta = parsedF.meta;
903
904
  file.hasEditClick = true;
904
905
  file.parsedData = cleanedEntities;
905
- file.name = newFileName;
906
+ // file.name = newFileName;
906
907
  file.originFileObj = newFile;
907
908
  file.originalFileObj = newFile;
908
- }
909
- }
910
- } else {
911
- toKeep.push(file);
912
- }
913
- }
914
- if (filesWIssues.length) {
915
- const { file } = filesWIssues[0];
916
- const allFiles = [...filesWIssues, ...filesWOIssues];
917
- const doAllFilesHaveSameHeaders = allFiles.every(f => {
918
- if (f.userSchema.fields && f.userSchema.fields.length) {
919
- return f.userSchema.fields.every((h, i) => {
920
- return h.path === allFiles[0].userSchema.fields[i].path;
921
909
  });
910
+ setTimeout(() => {
911
+ //inside a timeout for cypress purposes
912
+ window.toastr.success(
913
+ `Added Fixed Up File${
914
+ allFiles.length > 1 ? "s" : ""
915
+ } ${allFiles.map(({ file }) => file.name).join(", ")}`
916
+ );
917
+ }, 200);
922
918
  }
923
- return false;
924
- });
925
- const multipleFiles = allFiles.length > 1;
926
- const { res } = await showUploadCsvWizardDialog(
927
- "onUploadWizardFinish",
928
- {
929
- dialogProps: {
930
- title: `Fix Up File${multipleFiles ? "s" : ""} ${
931
- multipleFiles ? "" : file.name ? `"${file.name}"` : ""
932
- }`
933
- },
934
- doAllFilesHaveSameHeaders,
935
- filesWIssues: allFiles,
936
- validateAgainstSchema
937
- }
938
- );
939
-
940
- if (!res) {
941
- window.toastr.warning(`File Upload Aborted`);
942
- return;
943
- } else {
944
- allFiles.forEach(({ file }, i) => {
945
- const newEntities = res[i];
946
- // const newFileName = removeExt(file.name) + `_updated.csv`;
947
- //swap out file with a new csv file
948
- const { newFile, cleanedEntities } = getNewCsvFile(
949
- newEntities,
950
- file.name
951
- );
952
-
953
- file.hasEditClick = true;
954
- file.parsedData = cleanedEntities;
955
- // file.name = newFileName;
956
- file.originFileObj = newFile;
957
- file.originalFileObj = newFile;
958
- });
959
- setTimeout(() => {
960
- //inside a timeout for cypress purposes
961
- window.toastr.success(
962
- `Added Fixed Up File${
963
- allFiles.length > 1 ? "s" : ""
964
- } ${allFiles.map(({ file }) => file.name).join(", ")}`
965
- );
966
- }, 200);
967
919
  }
920
+ } else {
921
+ toKeep.push(...cleanedAccepted);
968
922
  }
969
- } else {
970
- toKeep.push(...cleanedAccepted);
971
- }
972
923
 
973
- if (toKeep.length === 0) {
974
- window.toastr &&
975
- window.toastr.error(
976
- `It looks like there wasn't any data in your file. Please add some data and try again`
977
- );
924
+ if (toKeep.length === 0) {
925
+ window.toastr &&
926
+ window.toastr.error(
927
+ `It looks like there wasn't any data in your file. Please add some data and try again`
928
+ );
929
+ }
930
+ const cleanedFileList = trimFiles(
931
+ [...toKeep, ...fileListToUse],
932
+ fileLimit
933
+ );
934
+ handleSecondHalfOfUpload({ acceptedFiles, cleanedFileList });
978
935
  }
979
- const cleanedFileList = trimFiles(
980
- [...toKeep, ...fileListToUse],
981
- fileLimit
982
- );
983
- handleSecondHalfOfUpload({ acceptedFiles, cleanedFileList });
984
936
  }}
985
937
  {...dropzoneProps}
986
938
  >
@@ -990,26 +942,71 @@ const UploaderInner = ({
990
942
  isDragAccept,
991
943
  isDragReject,
992
944
  isDragActive
945
+ // isDragActive
946
+ // isDragReject
947
+ // isDragAccept
993
948
  }) => (
994
- <InnerDropZone
995
- getRootProps={getRootProps}
996
- getInputProps={getInputProps}
997
- isDragAccept={isDragAccept}
998
- isDragReject={isDragReject}
999
- isDragActive={isDragActive}
1000
- className={className}
1001
- minimal={minimal}
1002
- dropzoneDisabled={dropzoneDisabled}
1003
- contentOverride={contentOverride}
1004
- simpleAccept={simpleAccept}
1005
- innerIcon={innerIcon}
1006
- innerText={innerText}
1007
- validateAgainstSchema={validateAgainstSchema}
1008
- handleManuallyEnterData={handleManuallyEnterData}
1009
- noBuildCsvOption={noBuildCsvOption}
1010
- showFilesCount={showFilesCount}
1011
- fileList={fileList}
1012
- />
949
+ <section>
950
+ <div
951
+ {...getRootProps()}
952
+ className={classnames("tg-dropzone", className, {
953
+ "tg-dropzone-minimal": minimal,
954
+ "tg-dropzone-active": isDragActive,
955
+ "tg-dropzone-reject": isDragReject, // tnr: the acceptClassName/rejectClassName doesn't work with file extensions (only mimetypes are supported when dragging). Thus we'll just always turn the drop area blue when dragging and let the filtering occur on drop. See https://github.com/react-dropzone/react-dropzone/issues/888#issuecomment-773938074
956
+ "tg-dropzone-accept": isDragAccept,
957
+ "tg-dropzone-disabled": dropzoneDisabled,
958
+ "bp3-disabled": dropzoneDisabled
959
+ })}
960
+ >
961
+ <input {...getInputProps()} />
962
+ {contentOverride || (
963
+ <div
964
+ title={
965
+ simpleAccept
966
+ ? "Accepts only the following file types: " +
967
+ simpleAccept
968
+ : "Accepts any file input"
969
+ }
970
+ className="tg-upload-inner"
971
+ >
972
+ {innerIcon || (
973
+ <Icon icon="upload" iconSize={minimal ? 15 : 30} />
974
+ )}
975
+ {innerText ||
976
+ (minimal ? "Upload" : "Click or drag to upload")}
977
+ {validateAgainstSchema && !noBuildCsvOption && (
978
+ <div
979
+ style={{
980
+ textAlign: "center",
981
+ // fontSize: 18,
982
+ marginTop: 7,
983
+ marginBottom: 5
984
+ }}
985
+ onClick={handleManuallyEnterData}
986
+ className="link-button"
987
+ >
988
+ ...or {manualEnterMessage}
989
+ {/* <div
990
+ style={{
991
+ fontSize: 11,
992
+ color: Colors.GRAY3,
993
+ fontStyle: "italic"
994
+ }}
995
+ >
996
+ {manualEnterSubMessage}
997
+ </div> */}
998
+ </div>
999
+ )}
1000
+ </div>
1001
+ )}
1002
+ </div>
1003
+
1004
+ {showFilesCount ? (
1005
+ <div className="tg-upload-file-list-counter">
1006
+ Files: {fileList ? fileList.length : 0}
1007
+ </div>
1008
+ ) : null}
1009
+ </section>
1013
1010
  )}
1014
1011
  </Dropzone>
1015
1012
  {/* {validateAgainstSchema && <CsvWizardHelper bindToggle={{}} validateAgainstSchema={validateAgainstSchema}></CsvWizardHelper>} */}
@@ -1191,9 +1188,12 @@ const UploaderInner = ({
1191
1188
  </div>
1192
1189
  </>
1193
1190
  );
1194
- };
1191
+ }
1195
1192
 
1196
- const Uploader = observer(UploaderInner);
1193
+ const Uploader = compose(
1194
+ connect(undefined, { initializeForm: initialize }),
1195
+ observer
1196
+ )(UploaderInner);
1197
1197
 
1198
1198
  export default Uploader;
1199
1199