gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-wallet-core] branch master updated: file upload


From: gnunet
Subject: [taler-wallet-core] branch master updated: file upload
Date: Wed, 10 Nov 2021 19:43:26 +0100

This is an automated email from the git hooks/post-receive script.

sebasjm pushed a commit to branch master
in repository wallet-core.

The following commit(s) were added to refs/heads/master by this push:
     new ea13e19e file upload
ea13e19e is described below

commit ea13e19ece2deeb4ab9731373f68b1dcf5b6fa88
Author: Sebastian <sebasjm@gmail.com>
AuthorDate: Wed Nov 10 15:43:15 2021 -0300

    file upload
---
 .../src/components/fields/FileInput.tsx            | 47 +++++++++++++++-------
 .../src/components/fields/TextInput.tsx            |  2 +
 .../src/pages/home/ReviewPoliciesScreen.tsx        |  5 ++-
 .../src/pages/home/SecretEditorScreen.tsx          | 42 +++++++++++++------
 .../home/authMethod/AuthMethodQuestionSetup.tsx    |  2 +-
 5 files changed, 69 insertions(+), 29 deletions(-)

diff --git a/packages/anastasis-webui/src/components/fields/FileInput.tsx 
b/packages/anastasis-webui/src/components/fields/FileInput.tsx
index 52d6eab4..adf51afb 100644
--- a/packages/anastasis-webui/src/components/fields/FileInput.tsx
+++ b/packages/anastasis-webui/src/components/fields/FileInput.tsx
@@ -20,11 +20,26 @@
  */
 import { h, VNode } from "preact";
 import { useLayoutEffect, useRef, useState } from "preact/hooks";
-import { TextInputProps } from "./TextInput";
 
 const MAX_IMAGE_UPLOAD_SIZE = 1024 * 1024;
 
-export function FileInput(props: TextInputProps): VNode {
+export interface FileTypeContent {
+  content: string;
+  type: string;
+  name: string;
+}
+
+export interface FileInputProps {
+  label: string;
+  grabFocus?: boolean;
+  disabled?: boolean;
+  error?: string;
+  placeholder?: string;
+  tooltip?: string;
+  onChange: (v: FileTypeContent | undefined) => void;
+}
+
+export function FileInput(props: FileInputProps): VNode {
   const inputRef = useRef<HTMLInputElement>(null);
   useLayoutEffect(() => {
     if (props.grabFocus) {
@@ -32,18 +47,19 @@ export function FileInput(props: TextInputProps): VNode {
     }
   }, [props.grabFocus]);
 
-  const value = props.bind[0];
-  // const [dirty, setDirty] = useState(false)
-  const image = useRef<HTMLInputElement>(null);
+  const fileInputRef = useRef<HTMLInputElement>(null);
   const [sizeError, setSizeError] = useState(false);
-  function onChange(v: string): void {
-    // setDirty(true);
-    props.bind[1](v);
-  }
   return (
     <div class="field">
       <label class="label">
-        <a onClick={() => image.current?.click()}>{props.label}</a>
+        <a class="button" onClick={(e) => fileInputRef.current?.click()}>
+          <div class="icon is-small ">
+            <i class="mdi mdi-folder" />
+          </div>
+          <span>
+            {props.label}
+          </span>
+        </a>
         {props.tooltip && (
           <span class="icon has-tooltip-right" data-tooltip={props.tooltip}>
             <i class="mdi mdi-information" />
@@ -52,18 +68,19 @@ export function FileInput(props: TextInputProps): VNode {
       </label>
       <div class="control">
         <input
-          ref={image}
+          ref={fileInputRef}
           style={{ display: "none" }}
           type="file"
-          name={String(name)}
+          // name={String(name)}
           onChange={(e) => {
             const f: FileList | null = e.currentTarget.files;
             if (!f || f.length != 1) {
-              return onChange("");
+              return props.onChange(undefined);
             }
+            console.log(f)
             if (f[0].size > MAX_IMAGE_UPLOAD_SIZE) {
               setSizeError(true);
-              return onChange("");
+              return props.onChange(undefined);
             }
             setSizeError(false);
             return f[0].arrayBuffer().then((b) => {
@@ -73,7 +90,7 @@ export function FileInput(props: TextInputProps): VNode {
                   "",
                 ),
               );
-              return onChange(`data:${f[0].type};base64,${b64}` as any);
+              return props.onChange({content: 
`data:${f[0].type};base64,${b64}`, name: f[0].name, type: f[0].type});
             });
           }}
         />
diff --git a/packages/anastasis-webui/src/components/fields/TextInput.tsx 
b/packages/anastasis-webui/src/components/fields/TextInput.tsx
index fd0c658e..4f417730 100644
--- a/packages/anastasis-webui/src/components/fields/TextInput.tsx
+++ b/packages/anastasis-webui/src/components/fields/TextInput.tsx
@@ -4,6 +4,7 @@ import { useLayoutEffect, useRef, useState } from 
"preact/hooks";
 export interface TextInputProps {
   label: string;
   grabFocus?: boolean;
+  disabled?: boolean;
   error?: string;
   placeholder?: string;
   tooltip?: string;
@@ -33,6 +34,7 @@ export function TextInput(props: TextInputProps): VNode {
       <div class="control has-icons-right">
         <input
           value={value}
+          disabled={props.disabled}
           placeholder={props.placeholder}
           class={showError ? "input is-danger" : "input"}
           onInput={(e) => {
diff --git a/packages/anastasis-webui/src/pages/home/ReviewPoliciesScreen.tsx 
b/packages/anastasis-webui/src/pages/home/ReviewPoliciesScreen.tsx
index c301b287..3b3b441e 100644
--- a/packages/anastasis-webui/src/pages/home/ReviewPoliciesScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/ReviewPoliciesScreen.tsx
@@ -1,3 +1,4 @@
+import { AuthenticationProviderStatusOk } from "anastasis-core";
 import { h, VNode } from "preact";
 import { useState } from "preact/hooks";
 import { useAnastasisContext } from "../../context/anastasis";
@@ -22,6 +23,7 @@ export function ReviewPoliciesScreen(): VNode {
     reducer.currentReducerState.authentication_methods ?? [];
   const policies = reducer.currentReducerState.policies ?? [];
 
+  const providers = reducer.currentReducerState.authentication_providers ?? {}
   
   if (editingPolicy !== undefined) {
     return (
@@ -96,6 +98,7 @@ export function ReviewPoliciesScreen(): VNode {
               </h3>
               {!methods.length && <p>No auth method found</p>}
               {methods.map((m, i) => {
+                const p = providers[m.provider] as 
AuthenticationProviderStatusOk
                 return (
                   <p
                     key={i}
@@ -107,7 +110,7 @@ export function ReviewPoliciesScreen(): VNode {
                     </span>
                     <span>
                       {m.instructions} recovery provided by{" "}
-                      <a href={m.provider}>{m.provider}</a>
+                      <a href={m.provider} target="_blank" rel="noreferrer" 
>{p.business_name}</a>
                     </span>
                   </p>
                 );
diff --git a/packages/anastasis-webui/src/pages/home/SecretEditorScreen.tsx 
b/packages/anastasis-webui/src/pages/home/SecretEditorScreen.tsx
index 59af8a9e..226e43dd 100644
--- a/packages/anastasis-webui/src/pages/home/SecretEditorScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/SecretEditorScreen.tsx
@@ -5,11 +5,16 @@ import { useState } from "preact/hooks";
 import { useAnastasisContext } from "../../context/anastasis";
 import { AnastasisClientFrame } from "./index";
 import { TextInput } from "../../components/fields/TextInput";
-import { FileInput } from "../../components/fields/FileInput";
+import { FileInput, FileTypeContent } from "../../components/fields/FileInput";
 
 export function SecretEditorScreen(): VNode {
   const reducer = useAnastasisContext();
   const [secretValue, setSecretValue] = useState("");
+  const [secretFile, _setSecretFile] = useState<FileTypeContent | 
undefined>(undefined);
+  function setSecretFile(v) {
+    setSecretValue("") // reset secret value when uploading a file
+    _setSecretFile(v)
+  }
 
   const currentSecretName =
     reducer?.currentReducerState &&
@@ -29,15 +34,20 @@ export function SecretEditorScreen(): VNode {
   }
 
   const secretNext = async (): Promise<void> => {
+    const secret = secretFile ? {
+      value: encodeCrock(stringToBytes(secretValue)),
+      filename: secretFile.name,
+      mime: secretFile.type,
+    } : {
+      value: encodeCrock(stringToBytes(secretValue)),
+      mime: "text/plain",
+    }
     return reducer.runTransaction(async (tx) => {
       await tx.transition("enter_secret_name", {
         name: secretName,
       });
       await tx.transition("enter_secret", {
-        secret: {
-          value: encodeCrock(stringToBytes(secretValue)),
-          mime: "text/plain",
-        },
+        secret,
         expiration: {
           t_ms: new Date().getTime() + 1000 * 60 * 60 * 24 * 365 * 5,
         },
@@ -45,12 +55,16 @@ export function SecretEditorScreen(): VNode {
       await tx.transition("next", {});
     });
   };
+  const errors = !secretName ? 'Add a secret name' : (
+    (!secretValue && !secretFile) ? 'Add a secret value or a choose a file to 
upload' : undefined
+  )
   return (
     <AnastasisClientFrame
+      hideNext={errors}
       title="Backup: Provide secret to backup"
       onNext={() => secretNext()}
     >
-      <div>
+      <div class="block">
         <TextInput
           label="Secret name:"
           tooltip="The secret name allows you to identify your secret when 
restoring it. It is a label that you can choose freely."
@@ -58,16 +72,20 @@ export function SecretEditorScreen(): VNode {
           bind={[secretName, setSecretName]}
         />
       </div>
-      <div>
+      <div class="block">
         <TextInput
+          disabled={!!secretFile}
           label="Enter the secret as text:"
           bind={[secretValue, setSecretValue]}
         />
-        {/* <div style={{ display: "flex" }}>
-          or&nbsp;
-          <FileInput label="click here" bind={[secretValue, setSecretValue]} />
-          &nbsp;to import a file
-        </div> */}
+      </div>
+      <div class="block">
+        Or upload a secret file
+        <FileInput label="Choose file" onChange={setSecretFile} />
+        {secretFile && <div>
+          Uploading secret file <b>{secretFile.name}</b> <a onClick={() => 
setSecretFile(undefined)}>cancel</a>
+        </div>
+        }
       </div>
     </AnastasisClientFrame>
   );
diff --git 
a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodQuestionSetup.tsx
 
b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodQuestionSetup.tsx
index 0a14021d..03725621 100644
--- 
a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodQuestionSetup.tsx
+++ 
b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodQuestionSetup.tsx
@@ -30,7 +30,7 @@ export function AuthMethodQuestionSetup({
     <AnastasisClientFrame hideNav title="Add Security Question">
       <div>
         <p>
-          For2 security question authentication, you need to provide a question
+          For security question authentication, you need to provide a question
           and its answer. When recovering your secret, you will be shown the
           question and you will need to type the answer exactly as you typed it
           here.

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]