summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2024-02-27 12:30:24 -0300
committerSebastian <sebasjm@gmail.com>2024-02-27 12:30:24 -0300
commit3a889c177dd35a114d2c95efd296274cd185ce52 (patch)
treed140b74495c7169996b6ddae6835d107a00271c0
parentff46a080e55bff821f823256bed1bcebdcc1efe9 (diff)
downloadwallet-core-3a889c177dd35a114d2c95efd296274cd185ce52.tar.gz
wallet-core-3a889c177dd35a114d2c95efd296274cd185ce52.tar.bz2
wallet-core-3a889c177dd35a114d2c95efd296274cd185ce52.zip
fix #8469
-rw-r--r--packages/taler-wallet-webextension/src/NavigationBar.tsx2
-rw-r--r--packages/taler-wallet-webextension/src/components/TermsOfService/state.ts7
-rw-r--r--packages/taler-wallet-webextension/src/cta/Withdraw/views.tsx17
-rw-r--r--packages/taler-wallet-webextension/src/hooks/useSettings.ts3
-rw-r--r--packages/taler-wallet-webextension/src/platform/api.ts6
-rw-r--r--packages/taler-wallet-webextension/src/wallet/AddExchange/test.ts1
-rw-r--r--packages/taler-wallet-webextension/src/wallet/DestinationSelection/test.ts1
-rw-r--r--packages/taler-wallet-webextension/src/wallet/DestinationSelection/views.tsx6
-rw-r--r--packages/taler-wallet-webextension/src/wallet/DeveloperPage.stories.tsx2
-rw-r--r--packages/taler-wallet-webextension/src/wallet/DeveloperPage.tsx362
-rw-r--r--packages/taler-wallet-webextension/src/wallet/Settings.stories.tsx53
-rw-r--r--packages/taler-wallet-webextension/src/wallet/Settings.tsx193
-rw-r--r--packages/taler-wallet-webextension/src/wallet/Transaction.tsx2
-rw-r--r--packages/taler-wallet-webextension/src/wxApi.ts8
-rw-r--r--packages/taler-wallet-webextension/src/wxBackend.ts12
-rw-r--r--packages/taler-wallet-webextension/static/wallet.html1
16 files changed, 293 insertions, 383 deletions
diff --git a/packages/taler-wallet-webextension/src/NavigationBar.tsx b/packages/taler-wallet-webextension/src/NavigationBar.tsx
index fe4fcc2d9..1837f0508 100644
--- a/packages/taler-wallet-webextension/src/NavigationBar.tsx
+++ b/packages/taler-wallet-webextension/src/NavigationBar.tsx
@@ -259,7 +259,7 @@ export function WalletNavBar({ path }: { path?: WalletNavBarOptions }): VNode {
<Fragment />
)}
- <EnabledBySettings name="advanceMode">
+ <EnabledBySettings name="advancedMode">
<a href={Pages.dev} class={path === "dev" ? "active" : ""}>
<i18n.Translate>Dev tools</i18n.Translate>
</a>
diff --git a/packages/taler-wallet-webextension/src/components/TermsOfService/state.ts b/packages/taler-wallet-webextension/src/components/TermsOfService/state.ts
index 0b27c9dcf..88d97af81 100644
--- a/packages/taler-wallet-webextension/src/components/TermsOfService/state.ts
+++ b/packages/taler-wallet-webextension/src/components/TermsOfService/state.ts
@@ -39,7 +39,7 @@ export function useComponentState({ showEvenIfaccepted, exchangeUrl, readOnly, c
WalletApiOperation.GetExchangeTos,
{
exchangeBaseUrl: exchangeUrl,
- acceptedFormat: ["text/html"],
+ acceptedFormat: ["text/xml"],
acceptLanguage: acceptedLang,
},
);
@@ -77,14 +77,9 @@ export function useComponentState({ showEvenIfaccepted, exchangeUrl, readOnly, c
if (accepted) {
await api.wallet.call(WalletApiOperation.SetExchangeTosAccepted, {
exchangeBaseUrl: exchangeUrl,
- etag: state.version,
});
} else {
// mark as not accepted
- await api.wallet.call(WalletApiOperation.SetExchangeTosAccepted, {
- exchangeBaseUrl: exchangeUrl,
- etag: undefined,
- });
}
terms?.retry()
}
diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw/views.tsx b/packages/taler-wallet-webextension/src/cta/Withdraw/views.tsx
index 4ceaad010..aade67835 100644
--- a/packages/taler-wallet-webextension/src/cta/Withdraw/views.tsx
+++ b/packages/taler-wallet-webextension/src/cta/Withdraw/views.tsx
@@ -33,6 +33,7 @@ import {
getAmountWithFee,
} from "../../wallet/Transaction.js";
import { State } from "./index.js";
+import { EnabledBySettings } from "../../components/EnabledBySettings.js";
export function FinalStateOperation(state: State.AlreadyCompleted): VNode {
const { i18n } = useTranslationContext();
@@ -77,13 +78,15 @@ export function SuccessView(state: State.Success): VNode {
}}
>
<i18n.Translate>Exchange</i18n.Translate>
- <Button onClick={state.doSelectExchange.onClick} variant="text">
- <SvgIcon
- title="Edit"
- dangerouslySetInnerHTML={{ __html: editIcon }}
- color="black"
- />
- </Button>
+ <EnabledBySettings name="showExchangeManagement">
+ <Button onClick={state.doSelectExchange.onClick} variant="text">
+ <SvgIcon
+ title="Edit"
+ dangerouslySetInnerHTML={{ __html: editIcon }}
+ color="black"
+ />
+ </Button>
+ </EnabledBySettings>
</div>
}
text={
diff --git a/packages/taler-wallet-webextension/src/hooks/useSettings.ts b/packages/taler-wallet-webextension/src/hooks/useSettings.ts
index 29449cd59..09fe28888 100644
--- a/packages/taler-wallet-webextension/src/hooks/useSettings.ts
+++ b/packages/taler-wallet-webextension/src/hooks/useSettings.ts
@@ -36,13 +36,14 @@ export const codecForSettings = (): Codec<Settings> =>
.property("walletAllowHttp", codecForBoolean())
.property("injectTalerSupport", codecForBoolean())
.property("autoOpen", codecForBoolean())
- .property("advanceMode", codecForBoolean())
+ .property("advancedMode", codecForBoolean())
.property("backup", codecForBoolean())
.property("langSelector", codecForBoolean())
.property("showJsonOnError", codecForBoolean())
.property("extendedAccountTypes", codecForBoolean())
.property("suspendIndividualTransaction", codecForBoolean())
.property("showRefeshTransactions", codecForBoolean())
+ .property("showExchangeManagement", codecForBoolean())
.build("Settings");
const SETTINGS_KEY = buildStorageKey("wallet-settings", codecForSettings());
diff --git a/packages/taler-wallet-webextension/src/platform/api.ts b/packages/taler-wallet-webextension/src/platform/api.ts
index 5bc7fd6c5..a16200cc5 100644
--- a/packages/taler-wallet-webextension/src/platform/api.ts
+++ b/packages/taler-wallet-webextension/src/platform/api.ts
@@ -113,25 +113,27 @@ type WebexWalletConfig = {
export interface Settings extends WebexWalletConfig {
injectTalerSupport: boolean;
autoOpen: boolean;
- advanceMode: boolean;
+ advancedMode: boolean;
backup: boolean;
langSelector: boolean;
showJsonOnError: boolean;
extendedAccountTypes: boolean;
showRefeshTransactions: boolean;
suspendIndividualTransaction: boolean;
+ showExchangeManagement: boolean;
}
export const defaultSettings: Settings = {
injectTalerSupport: false,
autoOpen: true,
- advanceMode: false,
+ advancedMode: false,
backup: false,
langSelector: false,
showRefeshTransactions: false,
suspendIndividualTransaction: false,
showJsonOnError: false,
extendedAccountTypes: false,
+ showExchangeManagement: false,
walletAllowHttp: false,
};
diff --git a/packages/taler-wallet-webextension/src/wallet/AddExchange/test.ts b/packages/taler-wallet-webextension/src/wallet/AddExchange/test.ts
index 60d5b274c..aa6384df2 100644
--- a/packages/taler-wallet-webextension/src/wallet/AddExchange/test.ts
+++ b/packages/taler-wallet-webextension/src/wallet/AddExchange/test.ts
@@ -49,6 +49,7 @@ describe("AddExchange states", () => {
exchangeBaseUrl: "http://exchange.local/",
ageRestrictionOptions: [],
scopeInfo: undefined,
+ masterPub: "123qwe123",
currency: "ARS",
exchangeEntryStatus: ExchangeEntryStatus.Ephemeral,
tosStatus: ExchangeTosStatus.Pending,
diff --git a/packages/taler-wallet-webextension/src/wallet/DestinationSelection/test.ts b/packages/taler-wallet-webextension/src/wallet/DestinationSelection/test.ts
index 3082ae7a4..0a99e6af9 100644
--- a/packages/taler-wallet-webextension/src/wallet/DestinationSelection/test.ts
+++ b/packages/taler-wallet-webextension/src/wallet/DestinationSelection/test.ts
@@ -36,6 +36,7 @@ import { useComponentState } from "./state.js";
const exchangeArs: ExchangeListItem = {
currency: "ARS",
exchangeBaseUrl: "http://",
+ masterPub:"123qwe123",
scopeInfo: undefined,
tosStatus: ExchangeTosStatus.Accepted,
exchangeEntryStatus: ExchangeEntryStatus.Used,
diff --git a/packages/taler-wallet-webextension/src/wallet/DestinationSelection/views.tsx b/packages/taler-wallet-webextension/src/wallet/DestinationSelection/views.tsx
index f8e2c6707..c40a3a64c 100644
--- a/packages/taler-wallet-webextension/src/wallet/DestinationSelection/views.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/DestinationSelection/views.tsx
@@ -14,6 +14,7 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
+import { useTranslationContext } from "@gnu-taler/web-util/browser";
import { styled } from "@linaria/react";
import { Fragment, h, VNode } from "preact";
import { AmountField } from "../../components/AmountField.js";
@@ -25,7 +26,6 @@ import {
LinkPrimary,
SvgIcon,
} from "../../components/styled/index.js";
-import { useTranslationContext } from "@gnu-taler/web-util/browser";
import { Button } from "../../mui/Button.js";
import { Grid } from "../../mui/Grid.js";
import { Paper } from "../../mui/Paper.js";
@@ -34,8 +34,6 @@ import arrowIcon from "../../svg/chevron-down.inline.svg";
import bankIcon from "../../svg/ri-bank-line.inline.svg";
import { assertUnreachable } from "../../utils/index.js";
import { Contact, State } from "./index.js";
-import { useEffect } from "preact/hooks";
-import { Checkbox } from "../../components/Checkbox.js";
export function SelectCurrencyView({
currencies,
@@ -303,7 +301,7 @@ export function ReadySendView({
required
handler={amountHandler}
/>
- <EnabledBySettings name="advanceMode">
+ <EnabledBySettings name="advancedMode">
<Button onClick={selectMax.onClick}>
<i18n.Translate>Send all</i18n.Translate>
</Button>
diff --git a/packages/taler-wallet-webextension/src/wallet/DeveloperPage.stories.tsx b/packages/taler-wallet-webextension/src/wallet/DeveloperPage.stories.tsx
index c2c794e89..e7c9111fd 100644
--- a/packages/taler-wallet-webextension/src/wallet/DeveloperPage.stories.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/DeveloperPage.stories.tsx
@@ -21,7 +21,7 @@
import { AbsoluteTime } from "@gnu-taler/taler-util";
import * as tests from "@gnu-taler/web-util/testing";
-import { View as TestedComponent } from "./DeveloperPage.js";
+import { DeveloperPage as TestedComponent } from "./DeveloperPage.js";
export default {
title: "developer",
diff --git a/packages/taler-wallet-webextension/src/wallet/DeveloperPage.tsx b/packages/taler-wallet-webextension/src/wallet/DeveloperPage.tsx
index 0db7a07eb..d19fef155 100644
--- a/packages/taler-wallet-webextension/src/wallet/DeveloperPage.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/DeveloperPage.tsx
@@ -20,8 +20,12 @@ import {
CoinDumpJson,
CoinStatus,
ExchangeListItem,
+ ExchangeTosStatus,
LogLevel,
NotificationType,
+ ScopeType,
+ parseWithdrawUri,
+ stringifyWithdrawExchange,
} from "@gnu-taler/taler-util";
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
import { useTranslationContext } from "@gnu-taler/web-util/browser";
@@ -31,7 +35,7 @@ import { useEffect, useRef, useState } from "preact/hooks";
import { Checkbox } from "../components/Checkbox.js";
import { SelectList } from "../components/SelectList.js";
import { Time } from "../components/Time.js";
-import { NotifyUpdateFadeOut } from "../components/styled/index.js";
+import { DestructiveText, LinkPrimary, NotifyUpdateFadeOut, SubTitle, SuccessText, WarningText } from "../components/styled/index.js";
import { useAlertContext } from "../context/alert.js";
import { useBackendContext } from "../context/backend.js";
import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
@@ -40,50 +44,8 @@ import { Button } from "../mui/Button.js";
import { Grid } from "../mui/Grid.js";
import { Paper } from "../mui/Paper.js";
import { TextField } from "../mui/TextField.js";
-
-export function DeveloperPage(): VNode {
- const listenAllEvents = Array.from<NotificationType>({ length: 1 });
-
- const api = useBackendContext();
-
- const response = useAsyncAsHook(async () => {
- const op = await api.wallet.call(
- WalletApiOperation.GetPendingOperations,
- {},
- );
- const c = await api.wallet.call(WalletApiOperation.DumpCoins, {});
- const ex = await api.wallet.call(WalletApiOperation.ListExchanges, {});
- return {
- operations: op.pendingOperations,
- coins: c.coins,
- exchanges: ex.exchanges,
- };
- });
-
- useEffect(() => {
- return api.listener.onUpdateNotification(listenAllEvents, response?.retry);
- });
-
- const nonResponse = { operations: [], coins: [], exchanges: [] };
- const { operations, coins, exchanges } =
- response === undefined
- ? nonResponse
- : response.hasError
- ? nonResponse
- : response.response;
-
- return (
- <View
- operations={operations}
- coins={coins}
- exchanges={exchanges}
- onDownloadDatabase={async () => {
- const db = await api.wallet.call(WalletApiOperation.ExportDb, {});
- return JSON.stringify(db);
- }}
- />
- );
-}
+import { Pages } from "../NavigationBar.js";
+import { CoinInfo } from "@gnu-taler/taler-wallet-core/dbless";
type CoinsInfo = CoinDumpJson["coins"];
type CalculatedCoinfInfo = {
@@ -103,23 +65,20 @@ type SplitedCoinInfo = {
export interface Props {
// FIXME: Pending operations don't exist anymore.
- operations: any[];
- coins: CoinsInfo;
- exchanges: ExchangeListItem[];
- onDownloadDatabase: () => Promise<string>;
}
function hashObjectId(o: any): string {
return JSON.stringify(o);
}
-export function View({ operations, coins, onDownloadDatabase }: Props): VNode {
+export function DeveloperPage({ }: Props): VNode {
const { i18n } = useTranslationContext();
const [downloadedDatabase, setDownloadedDatabase] = useState<
{ time: Date; content: string } | undefined
>(undefined);
async function onExportDatabase(): Promise<void> {
- const content = await onDownloadDatabase();
+ const db = await api.wallet.call(WalletApiOperation.ExportDb, {});
+ const content = JSON.stringify(db);
setDownloadedDatabase({
time: new Date(),
content,
@@ -136,10 +95,28 @@ export function View({ operations, coins, onDownloadDatabase }: Props): VNode {
const [settings, updateSettings] = useSettings();
const { safely } = useAlertContext();
- const hook = useAsyncAsHook(() =>
- api.wallet.call(WalletApiOperation.ListExchanges, {}),
- );
+ // const hook = useAsyncAsHook(() =>
+ // api.wallet.call(WalletApiOperation.ListExchanges, {}),
+ // );
+ const listenAllEvents = Array.from<NotificationType>({ length: 1 });
+
+ const hook = useAsyncAsHook(async () => {
+ const list = await api.wallet.call(WalletApiOperation.ListExchanges, {});
+ const version = await api.wallet.call(WalletApiOperation.GetVersion, {});
+ const operations: any[] = await api.wallet.call(
+ WalletApiOperation.GetPendingOperations,
+ {},
+ );
+ const coins = await api.wallet.call(WalletApiOperation.DumpCoins, {});
+ return { exchanges: list.exchanges, version, coins, operations };
+ });
const exchangeList = hook && !hook.hasError ? hook.response.exchanges : [];
+ const coins = hook && !hook.hasError ? hook.response.coins.coins : [];
+ const operations = hook && !hook.hasError ? hook.response.operations : [];
+
+ useEffect(() => {
+ return api.listener.onUpdateNotification(listenAllEvents, hook?.retry);
+ });
const currencies: { [ex: string]: string } = {};
const money_by_exchange = coins.reduce(
@@ -205,30 +182,6 @@ export function View({ operations, coins, onDownloadDatabase }: Props): VNode {
<Grid item>
<Button
variant="contained"
- onClick={() => {
- return api.background.call("sum", [1, 2, 3]).then((r) => {
- console.log("SUM", r);
- });
- }}
- >
- <i18n.Translate>sum 123</i18n.Translate>
- </Button>
- </Grid>
- <Grid item>
- <Button
- variant="contained"
- onClick={() => {
- return api.background.call("freeze", 4000).then(() => {
- console.log("WAIT");
- });
- }}
- >
- <i18n.Translate>freeze 4000</i18n.Translate>
- </Button>
- </Grid>
- <Grid item>
- <Button
- variant="contained"
onClick={async () => fileRef?.current?.click()}
>
<i18n.Translate>import database</i18n.Translate>
@@ -260,64 +213,6 @@ export function View({ operations, coins, onDownloadDatabase }: Props): VNode {
<Button
variant="contained"
onClick={async () => {
- navigator.registerProtocolHandler(
- "taler",
- `${window.location.origin}/static/wallet.html#/cta/withdraw?talerWithdrawUri=%s`,
- );
- }}
- >
- <i18n.Translate>Register taler:// handler</i18n.Translate>
- </Button>
- </Grid>
- <Grid item>
- <Button
- variant="contained"
- onClick={async () => {
- const n = navigator as any;
- if ("unregisterProtocolHandler" in n) {
- n.unregisterProtocolHandler(
- "taler",
- `${window.location.origin}/static/wallet.html#/cta/withdraw?talerWithdrawUri=%s`,
- );
- }
- }}
- >
- <i18n.Translate>Remove taler:// handler</i18n.Translate>
- </Button>
- </Grid>{" "}
- <Grid item>
- <Button
- variant="contained"
- onClick={async () => {
- navigator.registerProtocolHandler(
- "ext+taler",
- `${window.location.origin}/static/wallet.html#/cta/withdraw?talerWithdrawUri=%s`,
- );
- }}
- >
- <i18n.Translate>Register ext+taler:// handler</i18n.Translate>
- </Button>
- </Grid>
- <Grid item>
- <Button
- variant="contained"
- onClick={async () => {
- const n = navigator as any;
- if ("unregisterProtocolHandler" in n) {
- n.unregisterProtocolHandler(
- "ext+taler",
- `${window.location.origin}/static/wallet.html#/cta/withdraw?talerWithdrawUri=%s`,
- );
- }
- }}
- >
- <i18n.Translate>Remove ext+taler:// handler</i18n.Translate>
- </Button>
- </Grid>
- <Grid item>
- <Button
- variant="contained"
- onClick={async () => {
const result = await Promise.all(
exchangeList.map(async (exchange) => {
const url = exchange.exchangeBaseUrl;
@@ -359,6 +254,201 @@ export function View({ operations, coins, onDownloadDatabase }: Props): VNode {
})}
/>
+
+ <SubTitle>
+ <i18n.Translate>Exchange Entries</i18n.Translate>
+ </SubTitle>
+ {!exchangeList || !exchangeList.length ? (
+ <div>
+ <i18n.Translate>No exchange yet</i18n.Translate>
+ </div>
+ ) : (
+ <Fragment>
+ <table>
+ <thead>
+ <tr>
+ <th>
+ <i18n.Translate>Currency</i18n.Translate>
+ </th>
+ <th>
+ <i18n.Translate>URL</i18n.Translate>
+ </th>
+ <th>
+ <i18n.Translate>Status</i18n.Translate>
+ </th>
+ <th>
+ <i18n.Translate>Terms of Service</i18n.Translate>
+ </th>
+ <th>
+ <i18n.Translate>Last Update</i18n.Translate>
+ </th>
+ <th>
+ <i18n.Translate>Actions</i18n.Translate>
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ {exchangeList.map((e, idx) => {
+ function TosStatus(): VNode {
+ switch (e.tosStatus) {
+ case ExchangeTosStatus.Accepted:
+ return (
+ <SuccessText>
+ <i18n.Translate>ok</i18n.Translate>
+ </SuccessText>
+ );
+ case ExchangeTosStatus.Pending:
+ return (
+ <WarningText>
+ <i18n.Translate>pending</i18n.Translate>
+ </WarningText>
+ );
+ case ExchangeTosStatus.Proposed:
+ return <i18n.Translate>proposed</i18n.Translate>;
+ default:
+ return (
+ <DestructiveText>
+ <i18n.Translate>
+ unknown (exchange status should be updated)
+ </i18n.Translate>
+ </DestructiveText>
+ );
+ }
+ }
+ const uri = !e.masterPub ? undefined : stringifyWithdrawExchange({
+ exchangeBaseUrl: e.exchangeBaseUrl,
+ exchangePub: e.masterPub,
+ });
+ return (
+ <tr key={idx}>
+ <td>
+ <a href={!uri? undefined: Pages.defaultCta({ uri })}>
+ {e.scopeInfo ? `${e.scopeInfo.currency} (${e.scopeInfo.type === ScopeType.Global ? "global" : "regional"})` : e.currency}
+ </a>
+ </td>
+ <td>
+ <a href={new URL(`/keys`, e.exchangeBaseUrl).href} target="_blank">{e.exchangeBaseUrl}</a>
+ </td>
+ <td>
+ {e.exchangeEntryStatus} / {e.exchangeUpdateStatus}
+ </td>
+ <td>
+ <TosStatus />
+ </td>
+ <td>
+ {e.lastUpdateTimestamp
+ ? AbsoluteTime.toIsoString(
+ AbsoluteTime.fromPreciseTimestamp(
+ e.lastUpdateTimestamp,
+ ),
+ )
+ : "never"}
+ </td>
+ <td>
+ <button
+ onClick={() => {
+ api.wallet.call(
+ WalletApiOperation.UpdateExchangeEntry,
+ {
+ exchangeBaseUrl: e.exchangeBaseUrl,
+ force: true,
+ },
+ );
+ }}
+ >
+ Reload
+ </button>
+ <button
+ onClick={() => {
+ api.wallet.call(
+ WalletApiOperation.DeleteExchange,
+ {
+ exchangeBaseUrl: e.exchangeBaseUrl,
+ },
+ );
+ }}
+ >
+ Delete
+ </button>
+ <button
+ onClick={() => {
+ api.wallet.call(
+ WalletApiOperation.DeleteExchange,
+ {
+ exchangeBaseUrl: e.exchangeBaseUrl,
+ purge: true,
+ },
+ );
+ }}
+ >
+ Purge
+ </button>
+ {e.scopeInfo && e.masterPub && e.currency ?
+ (e.scopeInfo.type === ScopeType.Global ?
+ <button
+ onClick={() => {
+ api.wallet.call(
+ WalletApiOperation.RemoveGlobalCurrencyExchange,
+ {
+ exchangeBaseUrl: e.exchangeBaseUrl,
+ currency: e.currency!,
+ exchangeMasterPub: e.masterPub!,
+ },
+ );
+ }}
+ >
+
+ Make regional
+ </button>
+ : e.scopeInfo.type === ScopeType.Auditor ?
+ undefined
+
+ : e.scopeInfo.type === ScopeType.Exchange ?
+ <button
+ onClick={() => {
+ api.wallet.call(
+ WalletApiOperation.AddGlobalCurrencyExchange,
+ {
+ exchangeBaseUrl: e.exchangeBaseUrl,
+ currency: e.currency!,
+ exchangeMasterPub: e.masterPub!,
+ },
+ );
+ }}
+ >
+
+ Make global
+ </button>
+ : undefined) : undefined
+ }
+ <button
+ onClick={() => {
+ api.wallet.call(
+ WalletApiOperation.SetExchangeTosForgotten,
+ {
+ exchangeBaseUrl: e.exchangeBaseUrl,
+ },
+ );
+ }}
+ >
+ Forget ToS
+ </button>
+ </td>
+ </tr>
+ );
+ })}
+ </tbody>
+ </table>
+ </Fragment>
+ )}
+ <div style={{ display: "flex", justifyContent: "space-between" }}>
+ <div />
+ <LinkPrimary href={Pages.settingsExchangeAdd({})}>
+ <i18n.Translate>Add an exchange</i18n.Translate>
+ </LinkPrimary>
+ </div>
+
+
<Paper style={{ padding: 10, margin: 10 }}>
<h3>Logging</h3>
<div>
diff --git a/packages/taler-wallet-webextension/src/wallet/Settings.stories.tsx b/packages/taler-wallet-webextension/src/wallet/Settings.stories.tsx
index a5d6972de..cd43c4526 100644
--- a/packages/taler-wallet-webextension/src/wallet/Settings.stories.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Settings.stories.tsx
@@ -75,19 +75,6 @@ export const WithOneExchange = tests.createExample(TestedComponent, {
autoOpenToggle: { value: false, button: {} },
langToggle: { value: false, button: {} },
setDeviceName: () => Promise.resolve(),
- knownExchanges: [
- {
- currency: "USD",
- exchangeBaseUrl: "http://exchange.taler",
- tos: {
- currentVersion: "1",
- acceptedVersion: "1",
- content: "content of tos",
- contentType: "text/plain",
- },
- paytoUris: ["payto://x-taler-bank/bank.rpi.sebasjm.com/exchangeminator"],
- } as any, //TODO: complete with auditors, wireInfo and denominations
- ],
...version,
});
@@ -99,46 +86,6 @@ export const WithExchangeInDifferentState = tests.createExample(
autoOpenToggle: { value: false, button: {} },
langToggle: { value: false, button: {} },
setDeviceName: () => Promise.resolve(),
- knownExchanges: [
- {
- currency: "USD",
- exchangeBaseUrl: "http://exchange1.taler",
- tos: {
- currentVersion: "1",
- acceptedVersion: "1",
- content: "content of tos",
- contentType: "text/plain",
- },
- paytoUris: [
- "payto://x-taler-bank/bank.rpi.sebasjm.com/exchangeminator",
- ],
- },
- {
- currency: "USD",
- exchangeBaseUrl: "http://exchange2.taler",
- tos: {
- currentVersion: "2",
- acceptedVersion: "1",
- content: "content of tos",
- contentType: "text/plain",
- },
- paytoUris: [
- "payto://x-taler-bank/bank.rpi.sebasjm.com/exchangeminator",
- ],
- } as any, //TODO: complete with auditors, wireInfo and denominations
- {
- currency: "USD",
- exchangeBaseUrl: "http://exchange3.taler",
- tos: {
- currentVersion: "1",
- content: "content of tos",
- contentType: "text/plain",
- },
- paytoUris: [
- "payto://x-taler-bank/bank.rpi.sebasjm.com/exchangeminator",
- ],
- },
- ],
...version,
},
);
diff --git a/packages/taler-wallet-webextension/src/wallet/Settings.tsx b/packages/taler-wallet-webextension/src/wallet/Settings.tsx
index ec716cb87..b8fc14469 100644
--- a/packages/taler-wallet-webextension/src/wallet/Settings.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Settings.tsx
@@ -16,9 +16,11 @@
import {
AbsoluteTime,
+ ExchangeDetailedResponse,
ExchangeListItem,
ExchangeTosStatus,
LibtoolVersion,
+ ScopeType,
TranslatedString,
WalletCoreVersion,
} from "@gnu-taler/taler-util";
@@ -58,19 +60,15 @@ export function SettingsPage(): VNode {
const webex = platform.getWalletWebExVersion();
const api = useBackendContext();
- const exchangesHook = useAsyncAsHook(async () => {
- const list = await api.wallet.call(WalletApiOperation.ListExchanges, {});
+ const hook = useAsyncAsHook(async () => {
const version = await api.wallet.call(WalletApiOperation.GetVersion, {});
- return { exchanges: list.exchanges, version };
+ return { version };
});
- const { exchanges, version } =
- !exchangesHook || exchangesHook.hasError
- ? { exchanges: [], version: undefined }
- : exchangesHook.response;
+
+ const version = hook && !hook.hasError ? hook.response.version : undefined
return (
<SettingsView
- knownExchanges={exchanges}
deviceName={name}
setDeviceName={update}
autoOpenToggle={{
@@ -82,10 +80,10 @@ export function SettingsPage(): VNode {
},
}}
advanceToggle={{
- value: settings.advanceMode,
+ value: settings.advancedMode,
button: {
onClick: safely("update advance mode", async () => {
- updateSettings("advanceMode", !settings.advanceMode);
+ updateSettings("advancedMode", !settings.advancedMode);
}),
},
}}
@@ -112,7 +110,6 @@ export interface ViewProps {
autoOpenToggle: ToggleHandler;
advanceToggle: ToggleHandler;
langToggle: ToggleHandler;
- knownExchanges: Array<ExchangeListItem>;
coreVersion: WalletCoreVersion | undefined;
webexVersion: {
version: string;
@@ -121,7 +118,6 @@ export interface ViewProps {
}
export function SettingsView({
- knownExchanges,
autoOpenToggle,
advanceToggle,
langToggle,
@@ -136,143 +132,6 @@ export function SettingsView({
<Fragment>
<section>
<SubTitle>
- <i18n.Translate>Exchange Entries</i18n.Translate>
- </SubTitle>
- {!knownExchanges || !knownExchanges.length ? (
- <div>
- <i18n.Translate>No exchange yet</i18n.Translate>
- </div>
- ) : (
- <Fragment>
- <table>
- <thead>
- <tr>
- <th>
- <i18n.Translate>Currency</i18n.Translate>
- </th>
- <th>
- <i18n.Translate>URL</i18n.Translate>
- </th>
- <th>
- <i18n.Translate>Status</i18n.Translate>
- </th>
- <th>
- <i18n.Translate>Terms of Service</i18n.Translate>
- </th>
- <th>
- <i18n.Translate>Last Update</i18n.Translate>
- </th>
- <th>
- <i18n.Translate>Actions</i18n.Translate>
- </th>
- </tr>
- </thead>
- <tbody>
- {knownExchanges.map((e, idx) => {
- function TosStatus(): VNode {
- switch (e.tosStatus) {
- case ExchangeTosStatus.Accepted:
- return (
- <SuccessText>
- <i18n.Translate>ok</i18n.Translate>
- </SuccessText>
- );
- case ExchangeTosStatus.Pending:
- return (
- <WarningText>
- <i18n.Translate>pending</i18n.Translate>
- </WarningText>
- );
- case ExchangeTosStatus.Proposed:
- return <i18n.Translate>proposed</i18n.Translate>;
- default:
- return (
- <DestructiveText>
- <i18n.Translate>
- unknown (exchange status should be updated)
- </i18n.Translate>
- </DestructiveText>
- );
- }
- }
- return (
- <tr key={idx}>
- <td>{e.currency}</td>
- <td>
- <a href={e.exchangeBaseUrl}>{e.exchangeBaseUrl}</a>
- </td>
- <td>
- {e.exchangeEntryStatus} / {e.exchangeUpdateStatus}
- </td>
- <td>
- <TosStatus />
- </td>
- <td>
- {e.lastUpdateTimestamp
- ? AbsoluteTime.toIsoString(
- AbsoluteTime.fromPreciseTimestamp(
- e.lastUpdateTimestamp,
- ),
- )
- : "never"}
- </td>
- <td>
- <button
- onClick={() => {
- console.log(`force-updating ${e.exchangeBaseUrl}`);
- api.wallet.call(
- WalletApiOperation.UpdateExchangeEntry,
- {
- exchangeBaseUrl: e.exchangeBaseUrl,
- force: true,
- },
- );
- }}
- >
- Reload
- </button>
- </td>
- </tr>
- );
- })}
- </tbody>
- </table>
- </Fragment>
- )}
- <div style={{ display: "flex", justifyContent: "space-between" }}>
- <div />
- <LinkPrimary href={Pages.settingsExchangeAdd({})}>
- <i18n.Translate>Add an exchange</i18n.Translate>
- </LinkPrimary>
- </div>
- <SubTitle>
- <i18n.Translate>Advanced mode</i18n.Translate>
- </SubTitle>
- <Checkbox
- label={i18n.str`Enable advanced mode`}
- name="devMode"
- description={i18n.str`Show more information and options in the UI`}
- enabled={advanceToggle.value!}
- onToggle={advanceToggle.button.onClick!}
- />
- <EnabledBySettings name="advanceMode">
- <AdvanceSettings />
- </EnabledBySettings>
- <EnabledBySettings name="langSelector">
- <SubTitle>
- <i18n.Translate>Display</i18n.Translate>
- </SubTitle>
- <Input>
- <SelectList
- label={<i18n.Translate>Current Language</i18n.Translate>}
- list={supportedLang}
- name="lang"
- value={lang}
- onChange={(v) => changeLanguage(v)}
- />
- </Input>
- </EnabledBySettings>
- <SubTitle>
<i18n.Translate>Navigator</i18n.Translate>
</SubTitle>
<Checkbox
@@ -286,6 +145,7 @@ export function SettingsView({
enabled={autoOpenToggle.value!}
onToggle={autoOpenToggle.button.onClick!}
/>
+
<SubTitle>
<i18n.Translate>Version Info</i18n.Translate>
</SubTitle>
@@ -294,7 +154,7 @@ export function SettingsView({
text={
<span>
{webexVersion.version}{" "}
- <EnabledBySettings name="advanceMode">
+ <EnabledBySettings name="advancedMode">
{webexVersion.hash}
</EnabledBySettings>
</span>
@@ -313,7 +173,7 @@ export function SettingsView({
</i18n.Translate>
</WarningBox>
)}
- <EnabledBySettings name="advanceMode">
+ <EnabledBySettings name="advancedMode">
<Part
title={i18n.str`Exchange compatibility`}
text={<span>{coreVersion.exchange}</span>}
@@ -333,6 +193,33 @@ export function SettingsView({
</EnabledBySettings>
</Fragment>
)}
+ <SubTitle>
+ <i18n.Translate>Settings</i18n.Translate>
+ </SubTitle>
+ <Checkbox
+ label={i18n.str`Enable developer mode`}
+ name="devMode"
+ description={i18n.str`Show more information and options in the UI`}
+ enabled={advanceToggle.value!}
+ onToggle={advanceToggle.button.onClick!}
+ />
+ <EnabledBySettings name="advancedMode">
+ <AdvanceSettings />
+ </EnabledBySettings>
+ <EnabledBySettings name="langSelector">
+ <SubTitle>
+ <i18n.Translate>Display</i18n.Translate>
+ </SubTitle>
+ <Input>
+ <SelectList
+ label={<i18n.Translate>Current Language</i18n.Translate>}
+ list={supportedLang}
+ name="lang"
+ value={lang}
+ onChange={(v) => changeLanguage(v)}
+ />
+ </Input>
+ </EnabledBySettings>
</section>
</Fragment>
);
@@ -374,6 +261,10 @@ function AdvanceSettings(): VNode {
label: i18n.str`Lang selector`,
description: i18n.str`Allows to manually change the language of the UI. Otherwise it will be automatically selected by your browser configuration.`,
},
+ showExchangeManagement: {
+ label: i18n.str`Edit exchange management`,
+ description: i18n.str`Allows to see the list of exchange, remove, add and switch before withdrawal.`,
+ },
};
return (
<Fragment>
diff --git a/packages/taler-wallet-webextension/src/wallet/Transaction.tsx b/packages/taler-wallet-webextension/src/wallet/Transaction.tsx
index 65fc90f44..65ba6cc85 100644
--- a/packages/taler-wallet-webextension/src/wallet/Transaction.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Transaction.tsx
@@ -1960,7 +1960,7 @@ function ShowWithdrawalDetailForBankIntegrated({
const raw = Amounts.parseOrThrow(transaction.amountRaw);
return (
<Fragment>
- <EnabledBySettings name="advanceMode">
+ <EnabledBySettings name="advancedMode">
<a
href="#"
onClick={(e) => {
diff --git a/packages/taler-wallet-webextension/src/wxApi.ts b/packages/taler-wallet-webextension/src/wxApi.ts
index d989c9662..b73b12263 100644
--- a/packages/taler-wallet-webextension/src/wxApi.ts
+++ b/packages/taler-wallet-webextension/src/wxApi.ts
@@ -60,14 +60,6 @@ export interface ExtendedPermissionsResponse {
}
export interface BackgroundOperations {
- freeze: {
- request: number;
- response: void;
- };
- sum: {
- request: number[];
- response: number;
- };
resetDb: {
request: void;
response: void;
diff --git a/packages/taler-wallet-webextension/src/wxBackend.ts b/packages/taler-wallet-webextension/src/wxBackend.ts
index 70db60eca..051048e81 100644
--- a/packages/taler-wallet-webextension/src/wxBackend.ts
+++ b/packages/taler-wallet-webextension/src/wxBackend.ts
@@ -111,16 +111,6 @@ async function runGarbageCollector(): Promise<void> {
logger.info("imported");
}
-function freeze(time: number): Promise<void> {
- return new Promise((res, rej) => {
- setTimeout(res, time);
- });
-}
-
-async function sum(ns: Array<number>): Promise<number> {
- return ns.reduce((prev, cur) => prev + cur, 0);
-}
-
const extensionHandlers: ExtensionHandlerType = {
isAutoOpenEnabled,
isDomainTrusted,
@@ -137,8 +127,6 @@ async function isDomainTrusted(): Promise<boolean> {
}
const backendHandlers: BackendHandlerType = {
- freeze,
- sum,
resetDb,
runGarbageCollector,
setLoggingLevel,
diff --git a/packages/taler-wallet-webextension/static/wallet.html b/packages/taler-wallet-webextension/static/wallet.html
index c8baa7e4d..3025901d8 100644
--- a/packages/taler-wallet-webextension/static/wallet.html
+++ b/packages/taler-wallet-webextension/static/wallet.html
@@ -4,6 +4,7 @@
<head>
<title>GNU Taler Wallet - WebExtension</title>
<meta charset="utf-8" />
+ <meta name="taler-support" content="uri,api" />
<link rel="stylesheet" type="text/css" href="/dist/walletEntryPoint.css" />
<link rel="stylesheet" type="text/css" href="/static/font/import.css" />
<link rel="icon"