gnunet-svn
[Top][All Lists]
Advanced

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

[taler-wallet-core] branch master updated: wip wallet activity


From: gnunet
Subject: [taler-wallet-core] branch master updated: wip wallet activity
Date: Thu, 29 Feb 2024 05:24:58 +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 46898aef5 wip wallet activity
46898aef5 is described below

commit 46898aef5f6e238dbfe1b54cf1cf99a276b7d114
Author: Sebastian <sebasjm@gmail.com>
AuthorDate: Thu Feb 29 01:24:49 2024 -0300

    wip wallet activity
---
 packages/taler-wallet-core/src/wallet-api-types.ts |  12 +-
 .../src/components/Modal.tsx                       |  73 ++--
 .../src/components/WalletActivity.tsx              | 433 +++++++++++++++++++--
 .../src/wallet/Application.tsx                     |   5 +-
 .../src/wallet/DeveloperPage.tsx                   |  48 +--
 .../taler-wallet-webextension/src/wxBackend.ts     |   3 +
 6 files changed, 458 insertions(+), 116 deletions(-)

diff --git a/packages/taler-wallet-core/src/wallet-api-types.ts 
b/packages/taler-wallet-core/src/wallet-api-types.ts
index e5ff6cc26..553155ece 100644
--- a/packages/taler-wallet-core/src/wallet-api-types.ts
+++ b/packages/taler-wallet-core/src/wallet-api-types.ts
@@ -1310,10 +1310,10 @@ type Primitives = string | number | boolean;
 
 type RecursivePartial<T extends object> = {
   [P in keyof T]?: T[P] extends Array<infer U extends object>
-    ? Array<RecursivePartial<U>>
-    : T[P] extends Array<infer J extends Primitives>
-      ? Array<J>
-      : T[P] extends object
-        ? RecursivePartial<T[P]>
-        : T[P];
+  ? Array<RecursivePartial<U>>
+  : T[P] extends Array<infer J extends Primitives>
+  ? Array<J>
+  : T[P] extends object
+  ? RecursivePartial<T[P]>
+  : T[P];
 } & object;
diff --git a/packages/taler-wallet-webextension/src/components/Modal.tsx 
b/packages/taler-wallet-webextension/src/components/Modal.tsx
index 11fa72181..5553c72df 100644
--- a/packages/taler-wallet-webextension/src/components/Modal.tsx
+++ b/packages/taler-wallet-webextension/src/components/Modal.tsx
@@ -18,7 +18,7 @@ import { styled } from "@linaria/react";
 import { ComponentChildren, h, VNode } from "preact";
 import { ButtonHandler } from "../mui/handlers.js";
 import closeIcon from "../svg/close_24px.inline.svg";
-import { Link, LinkPrimary, LinkWarning } from "./styled/index.js";
+import { Link } from "./styled/index.js";
 
 interface Props {
   children: ComponentChildren;
@@ -52,40 +52,43 @@ const Body = styled.div`
 
 export function Modal({ title, children, onClose }: Props): VNode {
   return (
-    <FullSize onClick={onClose?.onClick}>
-      <div
-        onClick={(e) => e.stopPropagation()}
-        style={{
-          background: "white",
-          width: 600,
-          height: "80%",
-          margin: "auto",
-          borderRadius: 8,
-          padding: 8,
-          // overflow: "scroll",
-        }}
-      >
-        <Header>
-          <div>
-            <h2>{title}</h2>
-          </div>
-          <Link onClick={onClose?.onClick}>
-            <div
-              style={{
-                height: 24,
-                width: 24,
-                marginLeft: 4,
-                marginRight: 4,
-                // fill: "white",
-              }}
-              dangerouslySetInnerHTML={{ __html: closeIcon }}
-            />
-          </Link>
-        </Header>
-        <hr />
+    <div style={{ position: "fixed", top: 0, width: "100%", height: "100%" }}>
 
-        <Body onClick={(e: any) => e.stopPropagation()}>{children}</Body>
-      </div>
-    </FullSize>
+      <FullSize onClick={onClose?.onClick}>
+        <div
+          onClick={(e) => e.stopPropagation()}
+          style={{
+            background: "white",
+            width: 600,
+            height: "80%",
+            margin: "auto",
+            borderRadius: 8,
+            padding: 8,
+            // overflow: "scroll",
+          }}
+        >
+          <Header>
+            <div>
+              <h2>{title}</h2>
+            </div>
+            <Link onClick={onClose?.onClick}>
+              <div
+                style={{
+                  height: 24,
+                  width: 24,
+                  marginLeft: 4,
+                  marginRight: 4,
+                  // fill: "white",
+                }}
+                dangerouslySetInnerHTML={{ __html: closeIcon }}
+              />
+            </Link>
+          </Header>
+          <hr />
+
+          <Body onClick={(e: any) => e.stopPropagation()}>{children}</Body>
+        </div>
+      </FullSize>
+    </div>
   );
 }
diff --git 
a/packages/taler-wallet-webextension/src/components/WalletActivity.tsx 
b/packages/taler-wallet-webextension/src/components/WalletActivity.tsx
index a63ee97cb..8c55d1fc9 100644
--- a/packages/taler-wallet-webextension/src/components/WalletActivity.tsx
+++ b/packages/taler-wallet-webextension/src/components/WalletActivity.tsx
@@ -14,61 +14,420 @@
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 import {
-  AbsoluteTime,
-  Amounts,
   NotificationType,
-  Transaction,
+  ObservabilityEventType,
+  TalerErrorCode,
+  TalerErrorDetail,
   TransactionMajorState,
+  WalletNotification,
+  assertUnreachable
 } from "@gnu-taler/taler-util";
 import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
-import { Fragment, h, JSX, VNode } from "preact";
-import { useEffect } from "preact/hooks";
-import { useBackendContext } from "../context/backend.js";
 import { useTranslationContext } from "@gnu-taler/web-util/browser";
+import { Fragment, JSX, VNode, h } from "preact";
+import { useEffect, useState } from "preact/hooks";
+import { Pages } from "../NavigationBar.js";
+import { useBackendContext } from "../context/backend.js";
 import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
-import { Avatar } from "../mui/Avatar.js";
-import { Grid } from "../mui/Grid.js";
-import { Typography } from "../mui/Typography.js";
-import Banner from "./Banner.js";
+import { Button } from "../mui/Button.js";
+import { Modal } from "./Modal.js";
 import { Time } from "./Time.js";
+import { useSettings } from "../hooks/useSettings.js";
 
 interface Props extends JSX.HTMLAttributes {
 }
 
-/**
- * this cache will save the tx from the previous render
- */
-const cache = { tx: [] as Transaction[] };
 
-export function WalletActivity({  }: Props): VNode {
-  const api = useBackendContext();
-  const state = useAsyncAsHook(() =>
-    api.wallet.call(WalletApiOperation.GetTransactions, {}),
+export function WalletActivity({ }: Props): VNode {
+  const { i18n } = useTranslationContext()
+  const [settings, updateSettings] = useSettings()
+  useEffect(() => {
+    document.body.style.marginBottom = "250px"
+    return () => {
+      document.body.style.marginBottom = "0px"
+    }
+  })
+  const [table, setTable] = useState<"tasks" | "events" | "calls">("tasks")
+  return (
+    <div style={{ position: "fixed", bottom: 0, background: "white", zIndex: 
1, height: 250, overflowY: "scroll", width: "100%" }}>
+      <div style={{ display: "flex", justifyContent: "space-between", float: 
"right" }}>
+        <div />
+        <div onClick={() => {
+          updateSettings("showWalletActivity", false)
+        }}>
+          close
+        </div>
+      </div>
+      <div>
+        <Button variant={table === "tasks" ? "contained" : "outlined"}
+          onClick={async () => {
+            setTable("tasks")
+          }}
+        >
+          <i18n.Translate>Tasks</i18n.Translate>
+        </Button>
+        <Button variant={table === "events" ? "contained" : "outlined"}
+          onClick={async () => {
+            setTable("events")
+          }}
+        >
+          <i18n.Translate>Events</i18n.Translate>
+        </Button>
+
+        <Button variant={table === "calls" ? "contained" : "outlined"}
+          onClick={async () => {
+            setTable("calls")
+          }}
+        >
+          <i18n.Translate>Calls</i18n.Translate>
+        </Button>
+      </div>
+      {(function (): VNode {
+        switch (table) {
+          case "events": {
+            return <ObservavilityEventsTable />
+          }
+          case "calls": {
+            return <WalletCallsTable />
+          }
+          case "tasks": {
+            return <ActiveTasksTable />
+          }
+          default: {
+            assertUnreachable(table)
+          }
+        }
+      })()}
+    </div>
   );
-  const listenAllEvents = Array.from<NotificationType>({ length: 1 });
+}
 
+export function WalletCallsTable({ }: {}): VNode {
+  return <div />
+}
+const notifications: WalletNotification[] = []
+export function ObservavilityEventsTable({ }: {}): VNode {
+  const { i18n } = useTranslationContext()
+  const listenAllEvents = Array.from<NotificationType>({ length: 1 });
+  listenAllEvents.includes = () => true
+  const api = useBackendContext();
+  const [lastEvent, setLastEvent] = useState<Date>(new Date())
   useEffect(() => {
-    return api.listener.onUpdateNotification( listenAllEvents, (notif) => {
-      console.log(notif)
+    return api.listener.onUpdateNotification(listenAllEvents, (notif) => {
+      notifications.unshift(notif)
+      setLastEvent(new Date())
     });
   });
+  const [showError, setShowError] = useState<TalerErrorDetail>()
+  return <div>
+    {showError && <ErroDetailModal error={showError} onClose={(async () => { 
setShowError(undefined) })} />}
+    {notifications.map((not) => {
+      return (
+        <details>
+          <summary>{not.type}</summary>
+          {(function () {
+            switch (not.type) {
+              case NotificationType.BalanceChange: {
+                return <Fragment>
+                  <dt>Transaction</dt>
+                  <dd>
+                    <a title={not.hintTransactionId} 
href={Pages.balanceTransaction({ tid: not.hintTransactionId 
})}>{not.hintTransactionId.substring(0, 10)}</a>
+                  </dd>
+                </Fragment>
+              }
+              case NotificationType.BackupOperationError: {
+                return <Fragment>
+                  <dt>Error</dt>
+                  <dd>
+                    <a href="#" onClick={(e) => { e.preventDefault(); 
setShowError(not.error) }}>{TalerErrorCode[not.error.code]}</a>
+                  </dd>
+                </Fragment>
+              }
+              case NotificationType.TransactionStateTransition: {
+                return <Fragment>
+                  <dt>Old state</dt>
+                  <dd>
+                    {not.oldTxState.major} - {not.oldTxState.minor ?? ""}
+                  </dd>
+                  <dt>New state</dt>
+                  <dd>
+                    {not.newTxState.major} - {not.newTxState.minor ?? ""}
+                  </dd>
+                  <dt>Transaction</dt>
+                  <dd>
+                    <a title={not.transactionId} 
href={Pages.balanceTransaction({ tid: not.transactionId 
})}>{not.transactionId.substring(0, 10)}</a>
+                  </dd>
+                  {not.errorInfo ? <Fragment>
+                    <dt>Error</dt>
+                    <dd>
+                      <a href="#" onClick={(e) => {
+                        e.preventDefault(); setShowError({
+                          code: not.errorInfo!.code,
+                          hint: not.errorInfo!.hint,
+                          message: not.errorInfo!.message,
+                        })
+                      }}>{TalerErrorCode[not.errorInfo!.code]}</a>
+                    </dd>
+                  </Fragment> : undefined}
+                  <dt>Experimental</dt>
+                  <dd>
+                    <pre>
+                      {JSON.stringify(not.experimentalUserData, undefined, 2)}
+                    </pre>
+                  </dd>
+
+                </Fragment>
+              }
+              case NotificationType.ExchangeStateTransition: {
+                return <Fragment>
+                  <dt>Exchange</dt>
+                  <dd>
+                    {not.exchangeBaseUrl}
+                  </dd>
+                  <dt>Entry status</dt>
+                  <dd>
+                    {not.newExchangeState.exchangeEntryStatus}
+                  </dd>
+                  <dt>Update status</dt>
+                  <dd>
+                    {not.newExchangeState.exchangeUpdateStatus}
+                  </dd>
+                  <dt>Tos status</dt>
+                  <dd>
+                    {not.newExchangeState.tosStatus}
+                  </dd>
+                </Fragment>
+              }
+              case NotificationType.TaskObservabilityEvent: {
+                return <Fragment>
+                  <dt>Task</dt>
+                  <dd>
+                    {not.taskId}
+                  </dd>
+                  <dt>Event</dt>
+                  <dd>
+                    {not.event.type}
+                  </dd>
+                  {(function () {
+                    switch (not.event.type) {
+                      case ObservabilityEventType.HttpFetchStart:
+                      case ObservabilityEventType.HttpFetchFinishError:
+                      case ObservabilityEventType.HttpFetchFinishSuccess: {
+                        return <Fragment>
+                          <dt>Request</dt>
+                          <dd>{not.event.url}</dd>
+                        </Fragment>
+                      }
+                      case ObservabilityEventType.DbQueryStart:
+                      case ObservabilityEventType.DbQueryFinishSuccess:
+                      case ObservabilityEventType.DbQueryFinishError: {
+                        return <Fragment>
+                          <dt>Location</dt>
+                          <dd>{not.event.location}</dd>
+                          <dt>Name</dt>
+                          <dd>{not.event.name}</dd>
+                        </Fragment>
+                      }
+
+                      case ObservabilityEventType.TaskStart:
+                      case ObservabilityEventType.TaskStop:
+                      case ObservabilityEventType.DeclareTaskDependency:
+                      case ObservabilityEventType.TaskReset: {
+                        return <Fragment>
+                          <dt>Task</dt>
+                          <dd>{not.event.taskId}</dd>
+                        </Fragment>
+                      }
+                      case ObservabilityEventType.ShepherdTaskResult: {
+                        return <Fragment>
+                          <dt>result</dt>
+                          <dd>{not.event.resultType}</dd>
+                        </Fragment>
 
-  const transactions =
-    !state || state.hasError
-      ? cache.tx
-      : state.response.transactions.filter(
-        (t) => t.txState.major === TransactionMajorState.Pending,
+                      }
+                      case ObservabilityEventType.CryptoStart:
+                      case ObservabilityEventType.CryptoFinishSuccess:
+                      case ObservabilityEventType.CryptoFinishError: {
+                        return <Fragment>
+                          <dt>operation</dt>
+                          <dd>{not.event.operation}</dd>
+                        </Fragment>
+                      }
+                      case ObservabilityEventType.RequestStart:
+                      case ObservabilityEventType.RequestFinishSuccess:
+                      case ObservabilityEventType.RequestFinishError: {
+                        return <Fragment />
+                      }
+                    }
+                  })()}
+                </Fragment>
+              }
+              case NotificationType.RequestObservabilityEvent: {
+                return <Fragment>
+                  <dt>Operation</dt>
+                  <dd>
+                    {not.operation}
+                  </dd>
+                  <dt>Request</dt>
+                  <dd>
+                    {not.requestId}
+                  </dd>
+                  <dt>Event type</dt>
+                  <dd>
+                    {not.event.type}
+                  </dd>
+                  {(function () {
+                    switch (not.event.type) {
+                      case ObservabilityEventType.HttpFetchStart:
+                      case ObservabilityEventType.HttpFetchFinishError:
+                      case ObservabilityEventType.HttpFetchFinishSuccess: {
+                        return <Fragment>
+                          <dt>Request</dt>
+                          <dd>{not.event.url}</dd>
+                        </Fragment>
+                      }
+                      case ObservabilityEventType.DbQueryStart:
+                      case ObservabilityEventType.DbQueryFinishSuccess:
+                      case ObservabilityEventType.DbQueryFinishError: {
+                        return <Fragment>
+                          <dt>Location</dt>
+                          <dd>{not.event.location}</dd>
+                          <dt>Name</dt>
+                          <dd>{not.event.name}</dd>
+                        </Fragment>
+                      }
+
+                      case ObservabilityEventType.TaskStart:
+                      case ObservabilityEventType.TaskStop:
+                      case ObservabilityEventType.DeclareTaskDependency:
+                      case ObservabilityEventType.TaskReset: {
+                        return <Fragment>
+                          <dt>Task</dt>
+                          <dd>{not.event.taskId}</dd>
+                        </Fragment>
+                      }
+                      case ObservabilityEventType.ShepherdTaskResult: {
+                        return <Fragment>
+                          <dt>result</dt>
+                          <dd>{not.event.resultType}</dd>
+                        </Fragment>
+
+                      }
+                      case ObservabilityEventType.CryptoStart:
+                      case ObservabilityEventType.CryptoFinishSuccess:
+                      case ObservabilityEventType.CryptoFinishError: {
+                        return <Fragment>
+                          <dt>operation</dt>
+                          <dd>{not.event.operation}</dd>
+                        </Fragment>
+                      }
+                      case ObservabilityEventType.RequestStart:
+                      case ObservabilityEventType.RequestFinishSuccess:
+                      case ObservabilityEventType.RequestFinishError: {
+                        return <Fragment />
+                      }
+                    }
+                  })()}
+
+                </Fragment>
+              }
+            }
+          })()}
+
+        </details>
       );
+    })}
+  </div >
+}
 
-  if (state && !state.hasError) {
-    cache.tx = transactions;
-  }
-  if (!transactions.length) {
-    return <Fragment />;
-  }
-  return (
-    <div>
-      this is shown below
-    </div>
-  );
+function ErroDetailModal({ error, onClose }: { error: TalerErrorDetail, 
onClose: () => void }): VNode {
+  return <Modal title="Full detail" onClose={{
+    onClick: onClose as any
+  }}>
+    <dl>
+      <dt>Code</dt>
+      <dd>{TalerErrorCode[error.code]} ({error.code})</dd>
+      <dt>Hint</dt>
+      <dd>{error.hint ?? "--"}</dd>
+      <dt>Time</dt>
+      <dd><Time
+        timestamp={error.when}
+        format="yyyy/MM/dd HH:mm:ss"
+      /></dd>
+    </dl>
+    <pre>
+      {JSON.stringify(error, undefined, 2)}
+    </pre>
+  </Modal>
 }
+
+export function ActiveTasksTable({ }: {}): VNode {
+  const { i18n } = useTranslationContext()
+  const listenAllEvents = Array.from<NotificationType>({ length: 1 });
+  listenAllEvents.includes = () => true
+  const api = useBackendContext();
+  const state = useAsyncAsHook(() =>
+    api.wallet.call(WalletApiOperation.GetActiveTasks, {}),
+  );
+  const [showError, setShowError] = useState<TalerErrorDetail>()
+  const tasks = state && !state.hasError ? state.response.tasks : [];
+  useEffect(() => {
+    return api.listener.onUpdateNotification(listenAllEvents, (notif) => {
+      state?.retry()
+    });
+  });
+  return <Fragment>
+    {showError && <ErroDetailModal error={showError} onClose={(async () => { 
setShowError(undefined) })} />}
+    <table>
+      <thead>
+        <tr>
+          <th>
+            <i18n.Translate>Type</i18n.Translate>
+          </th>
+          <th>
+            <i18n.Translate>Id</i18n.Translate>
+          </th>
+          <th>
+            <i18n.Translate>Since</i18n.Translate>
+          </th>
+          <th>
+            <i18n.Translate>Next try</i18n.Translate>
+          </th>
+          <th>
+            <i18n.Translate>Error</i18n.Translate>
+          </th>
+          <th>
+            <i18n.Translate>Transaction</i18n.Translate>
+          </th>
+        </tr>
+      </thead>
+      <tbody>
+        {tasks.map((task) => {
+          const [type, id] = task.id.split(":")
+          return (
+            <tr>
+              <td>{type}</td>
+              <td title={id}>{id.substring(0, 10)}</td>
+              <td>
+                <Time
+                  timestamp={task.firstTry}
+                  format="yyyy/MM/dd HH:mm:ss"
+                />
+              </td>
+              <td>
+                <Time
+                  timestamp={task.nextTry}
+                  format="yyyy/MM/dd HH:mm:ss"
+                />
+              </td>
+              <td>{!task.lastError?.code ? "" : <a href="#" onClick={(e) => { 
e.preventDefault(); setShowError(task.lastError) 
}}>{TalerErrorCode[task.lastError.code]}</a>}</td>
+              <td>
+                {task.transaction ? <a title={task.transaction} 
href={Pages.balanceTransaction({ tid: task.transaction 
})}>{task.transaction.substring(0, 10)}</a> : "--"}
+              </td>
+            </tr>
+          );
+        })}
+      </tbody>
+    </table>
+  </Fragment>
+}
\ No newline at end of file
diff --git a/packages/taler-wallet-webextension/src/wallet/Application.tsx 
b/packages/taler-wallet-webextension/src/wallet/Application.tsx
index 4fafc73ad..62a519f06 100644
--- a/packages/taler-wallet-webextension/src/wallet/Application.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Application.tsx
@@ -82,6 +82,7 @@ import { SettingsPage } from "./Settings.js";
 import { TransactionPage } from "./Transaction.js";
 import { WelcomePage } from "./Welcome.js";
 import { WalletActivity } from "../components/WalletActivity.js";
+import { EnabledBySettings } from "../components/EnabledBySettings.js";
 
 export function Application(): VNode {
   const { i18n } = useTranslationContext();
@@ -511,6 +512,9 @@ export function Application(): VNode {
             component={() => <Redirect to={Pages.balanceHistory({})} />}
           />
         </Router>
+        <EnabledBySettings name="showWalletActivity">
+          <WalletActivity />
+        </EnabledBySettings>
       </IoCProviderForRuntime>
     </TranslationProvider>
   );
@@ -610,7 +614,6 @@ function WalletTemplate({
           {children}
         </AlertProvider>
       </WalletBox>
-      <WalletActivity />
     </Fragment>
   );
 }
diff --git a/packages/taler-wallet-webextension/src/wallet/DeveloperPage.tsx 
b/packages/taler-wallet-webextension/src/wallet/DeveloperPage.tsx
index adb114862..cdd3994d7 100644
--- a/packages/taler-wallet-webextension/src/wallet/DeveloperPage.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/DeveloperPage.tsx
@@ -46,6 +46,7 @@ import { Paper } from "../mui/Paper.js";
 import { TextField } from "../mui/TextField.js";
 import { Pages } from "../NavigationBar.js";
 import { CoinInfo } from "@gnu-taler/taler-wallet-core/dbless";
+import { ActiveTasksTable } from "../components/WalletActivity.js";
 
 type CoinsInfo = CoinDumpJson["coins"];
 type CalculatedCoinfInfo = {
@@ -95,27 +96,23 @@ export function DeveloperPage({ }: Props): VNode {
   const [settings, updateSettings] = useSettings();
   const { safely } = useAlertContext();
 
-  // const hook = useAsyncAsHook(() =>
-  //   api.wallet.call(WalletApiOperation.ListExchanges, {}),
-  // );
   const listenAllEvents = Array.from<NotificationType>({ length: 1 });
+  listenAllEvents.includes = () => true
 
   const hook = useAsyncAsHook(async () => {
     const list = await api.wallet.call(WalletApiOperation.ListExchanges, {});
     const version = await api.wallet.call(WalletApiOperation.GetVersion, {});
-    const tasks = await api.wallet.call(
-      WalletApiOperation.GetActiveTasks,
-      {},
-    );
     const coins = await api.wallet.call(WalletApiOperation.DumpCoins, {});
-    return { exchanges: list.exchanges, version, coins, tasks:tasks.tasks };
+    return { exchanges: list.exchanges, version, coins };
   });
   const exchangeList = hook && !hook.hasError ? hook.response.exchanges : [];
   const coins = hook && !hook.hasError ? hook.response.coins.coins : [];
-  const tasks = hook && !hook.hasError ? hook.response.tasks : [];
 
   useEffect(() => {
-    return api.listener.onUpdateNotification(listenAllEvents, hook?.retry);
+    return api.listener.onUpdateNotification(listenAllEvents, (ev) => {
+      console.log("event", ev)
+      return hook?.retry()
+    });
   });
 
   const currencies: { [ex: string]: string } = {};
@@ -145,7 +142,6 @@ export function DeveloperPage({ }: Props): VNode {
   );
 
   const [tagName, setTagName] = useState("");
-  const [exchangeURL, setExchangeURL] = useState("");
   const [logLevel, setLogLevel] = useState("info");
   return (
     <div>
@@ -322,7 +318,7 @@ export function DeveloperPage({ }: Props): VNode {
                 return (
                   <tr key={idx}>
                     <td>
-                      <a href={!uri? undefined: Pages.defaultCta({ uri })}>
+                      <a href={!uri ? undefined : Pages.defaultCta({ uri })}>
                         {e.scopeInfo ? `${e.scopeInfo.currency} 
(${e.scopeInfo.type === ScopeType.Global ? "global" : "regional"})` : 
e.currency}
                       </a>
                     </td>
@@ -545,31 +541,9 @@ export function DeveloperPage({ }: Props): VNode {
         );
       })}
       <br />
-      {tasks && tasks.length > 0 && (
-        <Fragment>
-          <p>
-            <i18n.Translate>Pending operations</i18n.Translate>
-          </p>
-          <dl>
-            {tasks.map((o) => {
-              return (
-                <NotifyUpdateFadeOut key={hashObjectId(o)}>
-                  <dt>
-                    {o.id}{" "}
-                    <Time
-                      timestamp={o.nextTry}
-                      format="yy/MM/dd HH:mm:ss"
-                    />
-                  </dt>
-                  <dd>
-                    <pre>{JSON.stringify(o, undefined, 2)}</pre>
-                  </dd>
-                </NotifyUpdateFadeOut>
-              );
-            })}
-          </dl>
-        </Fragment>
-      )}
+      <NotifyUpdateFadeOut>
+        <ActiveTasksTable />
+      </NotifyUpdateFadeOut>
     </div>
   );
 }
diff --git a/packages/taler-wallet-webextension/src/wxBackend.ts 
b/packages/taler-wallet-webextension/src/wxBackend.ts
index 051048e81..2753d57b4 100644
--- a/packages/taler-wallet-webextension/src/wxBackend.ts
+++ b/packages/taler-wallet-webextension/src/wxBackend.ts
@@ -277,6 +277,9 @@ async function reinitWallet(): Promise<void> {
     timer,
     cryptoWorker,
     {
+      testing: {
+        emitObservabilityEvents: true,
+      },
       features: {
         allowHttp: settings.walletAllowHttp,
       },

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