summaryrefslogtreecommitdiff
path: root/packages
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2024-02-29 01:24:49 -0300
committerSebastian <sebasjm@gmail.com>2024-02-29 01:24:49 -0300
commit46898aef5f6e238dbfe1b54cf1cf99a276b7d114 (patch)
tree22a482a5ba4f6cf7981d460d38d7987cbb39d3e2 /packages
parent74b9ee559fc57f48a591140eb342cc8e2bbd3dd3 (diff)
downloadwallet-core-46898aef5f6e238dbfe1b54cf1cf99a276b7d114.tar.gz
wallet-core-46898aef5f6e238dbfe1b54cf1cf99a276b7d114.tar.bz2
wallet-core-46898aef5f6e238dbfe1b54cf1cf99a276b7d114.zip
wip wallet activity
Diffstat (limited to 'packages')
-rw-r--r--packages/taler-wallet-core/src/wallet-api-types.ts12
-rw-r--r--packages/taler-wallet-webextension/src/components/Modal.tsx73
-rw-r--r--packages/taler-wallet-webextension/src/components/WalletActivity.tsx433
-rw-r--r--packages/taler-wallet-webextension/src/wallet/Application.tsx5
-rw-r--r--packages/taler-wallet-webextension/src/wallet/DeveloperPage.tsx48
-rw-r--r--packages/taler-wallet-webextension/src/wxBackend.ts3
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,
},