Browse Source

Merge pull request #676 from Joystream/master

Merge master into sideproject branch
Bedeho Mender 4 years ago
parent
commit
3ee06db82c

+ 34 - 6
pioneer/packages/joy-proposals/src/forms/FileDropdown.tsx

@@ -69,30 +69,58 @@ const innerSpanStyle = (): React.CSSProperties => {
   };
 };
 
-// Here we define a way of coverting the file into string for Formik purposes
-// This may change depnding on how we decide to actually send the data
-const parseFile = async (file: any): Promise<string> => {
+// Interpret the file as a UTF-8 string
+// https://developer.mozilla.org/en-US/docs/Web/API/Blob/text
+const parseFileAsUtf8 = async (file: any): Promise<string> => {
   const text = await file.text();
   return text;
 };
 
+// Interpret the file as containing binary data. This will load the entire
+// file into memory which may crash the brower with very large files.
+const parseFileAsBinary = async (file: any): Promise<ArrayBuffer> => {
+  // return file.arrayBuffer();
+  // This newer API not fully supported yet in all browsers
+  // https://developer.mozilla.org/en-US/docs/Web/API/Blob/arrayBuffer
+
+  return new Promise((resolve): void => {
+    const reader = new FileReader();
+
+    reader.onload = ({ target }: ProgressEvent<FileReader>): void => {
+      if (target && target.result) {
+        resolve(target.result as ArrayBuffer);
+      }
+    };
+
+    reader.readAsArrayBuffer(file);
+  });
+};
+
 type FileDropdownProps<FormValuesT> = {
   error: string | undefined;
   name: keyof FormValuesT & string;
   setFieldValue: FormikProps<FormValuesT>['setFieldValue'];
+  setFieldTouched: FormikProps<FormValuesT>['setFieldTouched'];
   acceptedFormats: string | string[];
   defaultText: string;
+  interpretAs: 'utf-8' | 'binary';
 };
 
 export default function FileDropdown<ValuesT = {}> (props: FileDropdownProps<ValuesT>) {
   const [parsing, setParsing] = useState(false);
-  const { error, name, setFieldValue, acceptedFormats, defaultText } = props;
+  const { error, name, setFieldValue, setFieldTouched, acceptedFormats, defaultText, interpretAs } = props;
   return (
     <Dropzone
       onDropAccepted={async acceptedFiles => {
         setParsing(true);
-        const fileAsString: string = await parseFile(acceptedFiles[0]);
-        setFieldValue(name, fileAsString, true);
+        let contents;
+        if (interpretAs === 'utf-8') {
+          contents = await parseFileAsUtf8(acceptedFiles[0]);
+        } else {
+          contents = await parseFileAsBinary(acceptedFiles[0]);
+        }
+        setFieldValue(name, contents, true);
+        setFieldTouched(name, true);
         setParsing(false);
       }}
       multiple={false}

+ 7 - 4
pioneer/packages/joy-proposals/src/forms/RuntimeUpgradeForm.tsx

@@ -17,12 +17,13 @@ import './forms.css';
 import FileDropdown from './FileDropdown';
 
 type FormValues = GenericFormValues & {
-  WASM: string;
+  // wasm blob as ArrayBuffer, or an Error string
+  WASM: ArrayBuffer | string;
 };
 
 const defaultValues: FormValues = {
   ...genericFormDefaultValues,
-  WASM: ''
+  WASM: new ArrayBuffer(0)
 };
 
 type FormAdditionalProps = {}; // Aditional props coming all the way from export comonent into the inner form.
@@ -31,7 +32,7 @@ type FormContainerProps = ProposalFormContainerProps<ExportComponentProps>;
 type FormInnerProps = ProposalFormInnerProps<FormContainerProps, FormValues>;
 
 const RuntimeUpgradeForm: React.FunctionComponent<FormInnerProps> = props => {
-  const { errors, setFieldValue, values } = props;
+  const { errors, setFieldValue, setFieldTouched, values, touched } = props;
   return (
     <GenericProposalForm
       {...props}
@@ -42,10 +43,12 @@ const RuntimeUpgradeForm: React.FunctionComponent<FormInnerProps> = props => {
       <Form.Field>
         <FileDropdown<FormValues>
           setFieldValue={setFieldValue}
+          setFieldTouched={setFieldTouched}
           defaultText="Drag-n-drop WASM bytecode of a runtime upgrade (*.wasm)"
           acceptedFormats=".wasm"
           name="WASM"
-          error={errors.WASM}
+          error={touched.WASM ? errors.WASM : undefined}
+          interpretAs='binary'
         />
       </Form.Field>
     </GenericProposalForm>

+ 5 - 5
pioneer/packages/joy-proposals/src/validationSchema.ts

@@ -100,7 +100,7 @@ type ValidationType = {
     description: Yup.StringSchema<string>;
   };
   RuntimeUpgrade: {
-    WASM: Yup.StringSchema<string>;
+    WASM: Yup.MixedSchema<any>;
   };
   SetElectionParameters: {
     announcingPeriod: Yup.NumberSchema<number>;
@@ -157,10 +157,10 @@ const Validation: ValidationType = {
       .max(DESCRIPTION_MAX_LENGTH, `Description should be under ${DESCRIPTION_MAX_LENGTH}`)
   },
   RuntimeUpgrade: {
-    WASM: Yup.string()
-      .required('A file is required')
-      .min(FILE_SIZE_BYTES_MIN, 'File is empty.')
-      .max(FILE_SIZE_BYTES_MAX, `The maximum file size is ${FILE_SIZE_BYTES_MAX} bytes.`)
+    WASM: Yup.mixed()
+      .test('fileArrayBuffer', 'Unexpected data format, file cannot be processed.', value => typeof value.byteLength !== 'undefined')
+      .test('fileSizeMin', `Minimum file size is ${FILE_SIZE_BYTES_MIN} bytes.`, value => value.byteLength >= FILE_SIZE_BYTES_MIN)
+      .test('fileSizeMax', `Maximum file size is ${FILE_SIZE_BYTES_MAX} bytes.`, value => value.byteLength <= FILE_SIZE_BYTES_MAX)
   },
   SetElectionParameters: {
     announcingPeriod: Yup.number()