gnunet-svn
[Top][All Lists]
Advanced

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

[taler-wallet-core] branch master updated (a8e4f2d6 -> 26a12809)


From: gnunet
Subject: [taler-wallet-core] branch master updated (a8e4f2d6 -> 26a12809)
Date: Thu, 01 Jul 2021 16:33:57 +0200

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

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

    from a8e4f2d6 take backup info from wallet-core
     new 7ba33273 exported backup types from wallet core
     new 26a12809 first working version of provider

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 packages/taler-wallet-core/src/index.ts            |   2 +
 .../src/hooks/useProvidersByCurrency.ts            |   2 +-
 .../src/popup/Backup.stories.tsx                   |   2 +-
 .../src/popup/BackupPage.tsx                       |   4 +-
 .../src/popup/Provider.stories.tsx                 | 215 +++++++++++++++++++++
 .../src/popup/ProviderPage.tsx                     | 174 +++++++++++++++++
 .../src/popup/Transaction.tsx                      |   2 +-
 .../taler-wallet-webextension/src/popup/popup.tsx  |   1 +
 .../src/popupEntryPoint.tsx                        |   2 +
 packages/taler-wallet-webextension/src/wxApi.ts    |  23 ++-
 10 files changed, 419 insertions(+), 8 deletions(-)
 create mode 100644 
packages/taler-wallet-webextension/src/popup/Provider.stories.tsx
 create mode 100644 
packages/taler-wallet-webextension/src/popup/ProviderPage.tsx

diff --git a/packages/taler-wallet-core/src/index.ts 
b/packages/taler-wallet-core/src/index.ts
index 1c97bf7c..a1489474 100644
--- a/packages/taler-wallet-core/src/index.ts
+++ b/packages/taler-wallet-core/src/index.ts
@@ -43,3 +43,5 @@ export * from "./util/debugFlags.js";
 export { InternalWalletState } from "./common.js";
 export * from "./wallet-api-types.js";
 export * from "./wallet.js";
+
+export * from "./operations/backup/index.js"
\ No newline at end of file
diff --git 
a/packages/taler-wallet-webextension/src/hooks/useProvidersByCurrency.ts 
b/packages/taler-wallet-webextension/src/hooks/useProvidersByCurrency.ts
index dedaf6f8..8c35705e 100644
--- a/packages/taler-wallet-webextension/src/hooks/useProvidersByCurrency.ts
+++ b/packages/taler-wallet-webextension/src/hooks/useProvidersByCurrency.ts
@@ -1,5 +1,5 @@
 import { Amounts } from "@gnu-taler/taler-util";
-import { ProviderInfo } from 
"@gnu-taler/taler-wallet-core/src/operations/backup";
+import { ProviderInfo } from "@gnu-taler/taler-wallet-core";
 import { useEffect, useState } from "preact/hooks";
 
 import * as wxApi from "../wxApi";
diff --git a/packages/taler-wallet-webextension/src/popup/Backup.stories.tsx 
b/packages/taler-wallet-webextension/src/popup/Backup.stories.tsx
index 856360eb..1bd43163 100644
--- a/packages/taler-wallet-webextension/src/popup/Backup.stories.tsx
+++ b/packages/taler-wallet-webextension/src/popup/Backup.stories.tsx
@@ -19,7 +19,7 @@
 * @author Sebastian Javier Marchano (sebasjm)
 */
 
-import { ProviderPaymentType } from 
'@gnu-taler/taler-wallet-core/src/operations/backup';
+import { ProviderPaymentType } from '@gnu-taler/taler-wallet-core';
 import { FunctionalComponent } from 'preact';
 import { BackupView as TestedComponent } from './BackupPage';
 
diff --git a/packages/taler-wallet-webextension/src/popup/BackupPage.tsx 
b/packages/taler-wallet-webextension/src/popup/BackupPage.tsx
index 9900720d..968898a6 100644
--- a/packages/taler-wallet-webextension/src/popup/BackupPage.tsx
+++ b/packages/taler-wallet-webextension/src/popup/BackupPage.tsx
@@ -16,10 +16,10 @@
 
 
 import { Timestamp } from "@gnu-taler/taler-util";
-// import { ProviderPaymentStatus } from 
"@gnu-taler/taler-wallet-core/src/operations/backup";
 import { formatDuration, intervalToDuration } from "date-fns";
 import { JSX, VNode } from "preact";
 import { ProvidersByCurrency, useBackupStatus } from 
"../hooks/useProvidersByCurrency";
+import { Pages } from "./popup";
 
 export function BackupPage(): VNode {
   const status = useBackupStatus()
@@ -99,7 +99,7 @@ function BackupLayout(props: TransactionLayoutProps): 
JSX.Element {
         {dateStr && <div style={{ fontSize: "small", color: "gray" 
}}>{dateStr}</div>}
         {!dateStr && <div style={{ fontSize: "small", color: "red" }}>never 
synced</div>}
         <div style={{ fontVariant: "small-caps", fontSize: "x-large" }}>
-          <a href=""><span>{props.title}</span></a>
+          <a href={Pages.provider.replace(':currency', 
props.id)}><span>{props.title}</span></a>
         </div>
 
         <div>{props.subtitle}</div>
diff --git a/packages/taler-wallet-webextension/src/popup/Provider.stories.tsx 
b/packages/taler-wallet-webextension/src/popup/Provider.stories.tsx
new file mode 100644
index 00000000..7b059103
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/popup/Provider.stories.tsx
@@ -0,0 +1,215 @@
+/*
+ This file is part of GNU Taler
+ (C) 2021 Taler Systems S.A.
+
+ GNU Taler is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+
+/**
+*
+* @author Sebastian Javier Marchano (sebasjm)
+*/
+
+import { ProviderPaymentType } from '@gnu-taler/taler-wallet-core';
+import { FunctionalComponent } from 'preact';
+import { ProviderView as TestedComponent } from './ProviderPage';
+
+export default {
+  title: 'popup/backup/details',
+  component: TestedComponent,
+  argTypes: {
+    onRetry: { action: 'onRetry' },
+    onDelete: { action: 'onDelete' },
+    onBack: { action: 'onBack' },
+  }
+};
+
+
+function createExample<Props>(Component: FunctionalComponent<Props>, props: 
Partial<Props>) {
+  const r = (args: any) => <Component {...args} />
+  r.args = props
+  return r
+}
+
+export const NotDefined = createExample(TestedComponent, {
+  currency: 'ARS',
+});
+
+export const Active = createExample(TestedComponent, {
+  currency: 'ARS',
+  info: {
+    "active": true,
+    "syncProviderBaseUrl": "http://sync.taler:9967/";,
+    "lastSuccessfulBackupTimestamp": {
+      "t_ms": 1625063925078
+    },
+    "paymentProposalIds": [
+      "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG"
+    ],
+    "paymentStatus": {
+      "type": ProviderPaymentType.Paid,
+      "paidUntil": {
+        "t_ms": 1656599921000
+      }
+    },
+    "terms": {
+      "annualFee": "ARS:1",
+      "storageLimitInMegabytes": 16,
+      "supportedProtocolVersion": "0.0"
+    }
+  }
+});
+
+export const ActiveErrorSync = createExample(TestedComponent, {
+  currency: 'ARS',
+  info: {
+    "active": true,
+    "syncProviderBaseUrl": "http://sync.taler:9967/";,
+    "lastSuccessfulBackupTimestamp": {
+      "t_ms": 1625063925078
+    },
+    "paymentProposalIds": [
+      "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG"
+    ],
+    "paymentStatus": {
+      "type": ProviderPaymentType.Paid,
+      "paidUntil": {
+        "t_ms": 1656599921000
+      }
+    },
+    lastError: {
+      code: 2002,
+      details: 'details',
+      hint: 'error hint from the server',
+      message: 'message'
+    },
+    "terms": {
+      "annualFee": "ARS:1",
+      "storageLimitInMegabytes": 16,
+      "supportedProtocolVersion": "0.0"
+    }
+  }
+});
+
+export const ActiveBackupProblemUnreadable = createExample(TestedComponent, {
+  currency: 'ARS',
+  info: {
+    "active": true,
+    "syncProviderBaseUrl": "http://sync.taler:9967/";,
+    "lastSuccessfulBackupTimestamp": {
+      "t_ms": 1625063925078
+    },
+    "paymentProposalIds": [
+      "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG"
+    ],
+    "paymentStatus": {
+      "type": ProviderPaymentType.Paid,
+      "paidUntil": {
+        "t_ms": 1656599921000
+      }
+    },
+    backupProblem: {
+      type: 'backup-unreadable'
+    },
+    "terms": {
+      "annualFee": "ARS:1",
+      "storageLimitInMegabytes": 16,
+      "supportedProtocolVersion": "0.0"
+    }
+  }
+});
+
+export const ActiveBackupProblemDevice = createExample(TestedComponent, {
+  currency: 'ARS',
+  info: {
+    "active": true,
+    "syncProviderBaseUrl": "http://sync.taler:9967/";,
+    "lastSuccessfulBackupTimestamp": {
+      "t_ms": 1625063925078
+    },
+    "paymentProposalIds": [
+      "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG"
+    ],
+    "paymentStatus": {
+      "type": ProviderPaymentType.Paid,
+      "paidUntil": {
+        "t_ms": 1656599921000
+      }
+    },
+    backupProblem: {
+      type: 'backup-conflicting-device',
+      myDeviceId: 'my-device-id',
+      otherDeviceId: 'other-device-id',
+      backupTimestamp: {
+        "t_ms": 1656599921000
+      }
+    },
+    "terms": {
+      "annualFee": "ARS:1",
+      "storageLimitInMegabytes": 16,
+      "supportedProtocolVersion": "0.0"
+    }
+  }
+});
+
+export const InactiveUnpaid = createExample(TestedComponent, {
+  currency: 'ARS',
+  info: {
+    "active": false,
+    "syncProviderBaseUrl": "http://sync.demo.taler.net/";,
+    "paymentProposalIds": [],
+    "paymentStatus": {
+      "type": ProviderPaymentType.Unpaid,
+    },
+    "terms": {
+      "annualFee": "ARS:0.1",
+      "storageLimitInMegabytes": 16,
+      "supportedProtocolVersion": "0.0"
+    }
+  }
+});
+
+export const InactiveInsufficientBalance = createExample(TestedComponent, {
+  currency: 'ARS',
+  info: {
+    "active": false,
+    "syncProviderBaseUrl": "http://sync.demo.taler.net/";,
+    "paymentProposalIds": [],
+    "paymentStatus": {
+      "type": ProviderPaymentType.InsufficientBalance,
+    },
+    "terms": {
+      "annualFee": "ARS:0.1",
+      "storageLimitInMegabytes": 16,
+      "supportedProtocolVersion": "0.0"
+    }
+  }
+});
+
+export const InactivePending = createExample(TestedComponent, {
+  currency: 'ARS',
+  info: {
+    "active": false,
+    "syncProviderBaseUrl": "http://sync.demo.taler.net/";,
+    "paymentProposalIds": [],
+    "paymentStatus": {
+      "type": ProviderPaymentType.Pending,
+    },
+    "terms": {
+      "annualFee": "ARS:0.1",
+      "storageLimitInMegabytes": 16,
+      "supportedProtocolVersion": "0.0"
+    }
+  }
+});
+
+
diff --git a/packages/taler-wallet-webextension/src/popup/ProviderPage.tsx 
b/packages/taler-wallet-webextension/src/popup/ProviderPage.tsx
new file mode 100644
index 00000000..1112017f
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/popup/ProviderPage.tsx
@@ -0,0 +1,174 @@
+/*
+ This file is part of TALER
+ (C) 2016 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+*/
+
+
+import { i18n, Timestamp } from "@gnu-taler/taler-util";
+import { ProviderInfo, ProviderPaymentType } from 
"@gnu-taler/taler-wallet-core";
+import { formatDuration, intervalToDuration } from "date-fns";
+import { VNode } from "preact";
+import { useRef, useState } from "preact/hooks";
+import { useBackupStatus } from "../hooks/useProvidersByCurrency";
+import * as wxApi from "../wxApi";
+
+interface Props {
+  currency: string;
+}
+
+export function ProviderPage({ currency }: Props): VNode {
+  const status = useBackupStatus()
+  const [adding, setAdding] = useState<boolean>(false)
+  if (!status) {
+    return <div>Loading...</div>
+  }
+  if (adding) {
+    return <AddProviderView onConfirm={(value) => {
+      console.log(value)
+      wxApi.addBackupProvider(value).then(_ => history.go(-1))
+      setAdding(false)
+    }} />
+  }
+  const info = status.providers[currency];
+  return <ProviderView currency={currency} info={info}
+    onSync={() => { null }}
+    onDelete={() => { null }}
+    onBack={() => { history.go(-1); }}
+    onAddProvider={() => { setAdding(true) }}
+  />;
+}
+
+function AddProviderView({ onConfirm }: { onConfirm: (s: string) => void }) {
+  const textInput = useRef<HTMLInputElement>(null)
+  return <div>
+    <input ref={textInput} />
+    <button onClick={() => 
onConfirm(textInput?.current.value)}>confirm</button>
+  </div>
+}
+
+export interface ViewProps {
+  currency: string;
+  info?: ProviderInfo;
+  onDelete: () => void;
+  onSync: () => void;
+  onBack: () => void;
+  onAddProvider: () => void;
+}
+
+export function ProviderView({ currency, info, onDelete, onSync, onBack, 
onAddProvider }: ViewProps): VNode {
+  function Footer() {
+    return <footer style={{ marginTop: 'auto', display: 'flex', flexShrink: 0 
}}>
+      <button onClick={onBack}><i18n.Translate>back</i18n.Translate></button>
+      <div style={{ width: '100%', flexDirection: 'row', justifyContent: 
'flex-end', display: 'flex' }}>
+        {info && <button class="pure-button button-destructive" 
onClick={onDelete}><i18n.Translate>remove</i18n.Translate></button>}
+        {info && <button class="pure-button button-secondary" style={{ 
marginLeft: 5 }} onClick={onSync}><i18n.Translate>sync 
now</i18n.Translate></button>}
+        {!info && <button class="pure-button button-success" style={{ 
marginLeft: 5 }} onClick={onAddProvider}><i18n.Translate>add 
provider</i18n.Translate></button>}
+      </div>
+    </footer>
+  }
+  function Error() {
+    if (info?.lastError) {
+      return <div class="errorbox" style={{ marginTop: 10 }} >
+        <p>{info.lastError.hint}</p>
+      </div>
+    }
+    if (info?.backupProblem) {
+      switch (info.backupProblem.type) {
+        case "backup-conflicting-device":
+          return <div class="errorbox" style={{ marginTop: 10 }}>
+            <p>There is another backup from 
<b>{info.backupProblem.otherDeviceId}</b></p>
+          </div>
+        case "backup-unreadable":
+          return <div class="errorbox" style={{ marginTop: 10 }}>
+            <p>Backup is not readable</p>
+          </div>
+        default:
+          return <div class="errorbox" style={{ marginTop: 10 }}>
+            <p>Unkown backup problem: {JSON.stringify(info.backupProblem)}</p>
+          </div>
+      }
+    }
+    return null
+  }
+  function colorByStatus(status: ProviderPaymentType | undefined) {
+    switch (status) {
+      case ProviderPaymentType.InsufficientBalance:
+        return 'rgb(223, 117, 20)'
+      case ProviderPaymentType.Unpaid:
+        return 'rgb(202, 60, 60)'
+      case ProviderPaymentType.Paid:
+        return 'rgb(28, 184, 65)'
+      case ProviderPaymentType.Pending:
+        return 'gray'
+      case ProviderPaymentType.InsufficientBalance:
+        return 'rgb(202, 60, 60)'
+      case ProviderPaymentType.TermsChanged:
+        return 'rgb(202, 60, 60)'
+      default:
+        break;
+    }
+    return undefined
+  }
+
+  return (
+    <div style={{ height: 'calc(320px - 34px - 16px)', overflow: 'auto' }}>
+      <style>{`
+      table td {
+        padding: 5px 10px;
+      }
+      `}</style>
+      <div style={{ display: 'flex', flexDirection: 'column' }}>
+        <section style={{ flex: '1 0 auto', height: 'calc(320px - 34px - 45px 
- 16px)', overflow: 'auto' }}>
+          <span style={{ padding: 5, display: 'inline-block', backgroundColor: 
colorByStatus(info?.paymentStatus.type), borderRadius: 5, color: 'white' 
}}>{info?.paymentStatus.type}</span>
+          {info && <span style={{ float: "right", fontSize: "small", color: 
"gray", padding: 5 }}>
+            From <b>{info.syncProviderBaseUrl}</b>
+          </span>}
+
+          <Error />
+
+          <div style={{ display: "flex", flexDirection: "row", justifyContent: 
"space-between", }}>
+            <h1>{currency}</h1>
+            {info && <div style={{ marginTop: 'auto', marginBottom: 'auto' 
}}>{info.terms?.annualFee} / year</div>}
+          </div>
+
+          <div>{daysSince(info?.lastSuccessfulBackupTimestamp)} </div>
+        </section>
+        <Footer />
+      </div>
+    </div>
+  )
+}
+
+function daysSince(d?: Timestamp) {
+  if (!d || d.t_ms === 'never') return 'never synced'
+  const duration = intervalToDuration({
+    start: d.t_ms,
+    end: new Date(),
+  })
+  const str = formatDuration(duration, {
+    delimiter: ', ',
+    format: [
+      duration?.years ? 'years' : (
+        duration?.months ? 'months' : (
+          duration?.days ? 'days' : (
+            duration?.hours ? 'hours' : (
+              duration?.minutes ? 'minutes' : 'seconds'
+            )
+          )
+        )
+      )
+    ]
+  })
+  return `synced ${str} ago`
+}
diff --git a/packages/taler-wallet-webextension/src/popup/Transaction.tsx 
b/packages/taler-wallet-webextension/src/popup/Transaction.tsx
index 7a66d7a0..d6a85d64 100644
--- a/packages/taler-wallet-webextension/src/popup/Transaction.tsx
+++ b/packages/taler-wallet-webextension/src/popup/Transaction.tsx
@@ -97,7 +97,7 @@ export function TransactionView({ transaction, onDelete, 
onRetry, onBack }: Wall
     return (
       <div style={{ display: 'flex', flexDirection: 'column' }} >
         <section style={{ color: transaction.pending ? 'gray' : '', flex: '1 0 
auto', height: 'calc(320px - 34px - 45px - 16px)', overflow: 'auto' }}>
-          <span style="flat: left; font-size:small; 
color:gray">{transaction.timestamp.t_ms === "never" ? "never" : 
format(transaction.timestamp.t_ms, 'dd/MM/yyyy HH:mm:ss')}</span>
+          <span style="font-size:small; 
color:gray">{transaction.timestamp.t_ms === "never" ? "never" : 
format(transaction.timestamp.t_ms, 'dd/MM/yyyy HH:mm:ss')}</span>
           <span style="float: right; font-size:small; color:gray">
             From <b>{transaction.exchangeBaseUrl}</b>
           </span>
diff --git a/packages/taler-wallet-webextension/src/popup/popup.tsx 
b/packages/taler-wallet-webextension/src/popup/popup.tsx
index 288e0447..6b8f110e 100644
--- a/packages/taler-wallet-webextension/src/popup/popup.tsx
+++ b/packages/taler-wallet-webextension/src/popup/popup.tsx
@@ -36,6 +36,7 @@ export enum Pages {
   backup = '/backup',
   history = '/history',
   transaction = '/transaction/:tid',
+  provider = '/provider/:currency',
 }
 
 interface TabProps {
diff --git a/packages/taler-wallet-webextension/src/popupEntryPoint.tsx 
b/packages/taler-wallet-webextension/src/popupEntryPoint.tsx
index c777e01d..8fb5121e 100644
--- a/packages/taler-wallet-webextension/src/popupEntryPoint.tsx
+++ b/packages/taler-wallet-webextension/src/popupEntryPoint.tsx
@@ -38,6 +38,7 @@ import { useTalerActionURL } from "./hooks/useTalerActionURL";
 import { createHashHistory } from "history";
 import { DevContextProvider } from "./context/useDevContext";
 import { BackupPage } from "./popup/BackupPage";
+import { ProviderPage } from "./popup/ProviderPage.js";
 
 function main(): void {
   try {
@@ -99,6 +100,7 @@ function Application() {
             <Route path={Pages.dev} component={DeveloperPage} />
             <Route path={Pages.history} component={HistoryPage} />
             <Route path={Pages.backup} component={BackupPage} />
+            <Route path={Pages.provider} component={ProviderPage} />
             <Route path={Pages.transaction} component={TransactionPage} />
             <Route default component={Redirect} to={Pages.balance} />
           </Router>
diff --git a/packages/taler-wallet-webextension/src/wxApi.ts 
b/packages/taler-wallet-webextension/src/wxApi.ts
index 81f418d4..393c4110 100644
--- a/packages/taler-wallet-webextension/src/wxApi.ts
+++ b/packages/taler-wallet-webextension/src/wxApi.ts
@@ -38,8 +38,8 @@ import {
   DeleteTransactionRequest,
   RetryTransactionRequest,
 } from "@gnu-taler/taler-util";
-import { BackupProviderState, OperationFailedError } from 
"@gnu-taler/taler-wallet-core";
-import { BackupInfo } from 
"@gnu-taler/taler-wallet-core/src/operations/backup";
+import { AddBackupProviderRequest, BackupProviderState, OperationFailedError } 
from "@gnu-taler/taler-wallet-core";
+import { BackupInfo } from "@gnu-taler/taler-wallet-core";
 
 export interface ExtendedPermissionsResponse {
   newValue: boolean;
@@ -166,9 +166,26 @@ export function listKnownCurrencies(): 
Promise<ListOfKnownCurrencies> {
 /**
  * Get information about the current state of wallet backups.
  */
- export function getBackupInfo(): Promise<BackupInfo> {
+export function getBackupInfo(): Promise<BackupInfo> {
   return callBackend("getBackupInfo", {})
 }
+
+/**
+ * Add a backup provider and activate it
+ */
+export function addBackupProvider(backupProviderBaseUrl: string): 
Promise<void> {
+  return callBackend("addBackupProvider", {
+    backupProviderBaseUrl, activate: true
+  } as AddBackupProviderRequest)
+}
+
+export function syncAllProviders(): Promise<void> {
+  return callBackend("runBackupCycle", {})
+}
+
+
+
+
 /**
  * Retry a transaction
  * @param transactionId 

-- 
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]