From 8153c5026f3e7a100564e6dd9944e054cbb1b910 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Thu, 22 Feb 2024 12:42:54 +0100 Subject: webextension: render more info about exchanges --- packages/taler-util/src/time.ts | 16 ++++++++++++++- packages/taler-util/src/wallet-types.ts | 5 +++++ packages/taler-wallet-core/src/exchanges.ts | 1 + .../src/wallet/AddExchange/test.ts | 15 +++++++------- .../src/wallet/DestinationSelection/test.ts | 3 ++- .../src/wallet/Settings.tsx | 23 ++++++++++++++++++++-- 6 files changed, 52 insertions(+), 11 deletions(-) (limited to 'packages') diff --git a/packages/taler-util/src/time.ts b/packages/taler-util/src/time.ts index 5702b2947..66bde4fa2 100644 --- a/packages/taler-util/src/time.ts +++ b/packages/taler-util/src/time.ts @@ -639,7 +639,21 @@ export const codecForTimestamp: Codec = { if (typeof t_s === "number") { return { t_s }; } - throw Error(`expected timestamp at ${renderContext(c)}`); + throw Error(`expected protocol timestamp at ${renderContext(c)}`); + }, +}; + +export const codecForPreciseTimestamp: Codec = { + decode(x: any, c?: Context): TalerPreciseTimestamp { + const t_ms = x.t_ms; + if (typeof t_ms === "string") { + if (t_ms === "never") { + return { t_s: "never" }; + } + } else if (typeof t_ms === "number") { + return { t_s: Math.floor(t_ms / 1000) }; + } + throw Error(`expected precise timestamp at ${renderContext(c)}`); }, }; diff --git a/packages/taler-util/src/wallet-types.ts b/packages/taler-util/src/wallet-types.ts index 5293fcd55..771d4d1f9 100644 --- a/packages/taler-util/src/wallet-types.ts +++ b/packages/taler-util/src/wallet-types.ts @@ -79,6 +79,7 @@ import { TalerProtocolDuration, TalerProtocolTimestamp, codecForAbsoluteTime, + codecForPreciseTimestamp, codecForTimestamp, } from "./time.js"; import { @@ -1342,6 +1343,8 @@ export interface ExchangeListItem { scopeInfo: ScopeInfo | undefined; + lastUpdateTimestamp: TalerPreciseTimestamp | undefined; + /** * Information about the last error that occurred when trying * to update the exchange info. @@ -1414,6 +1417,8 @@ export const codecForExchangeListItem = (): Codec => .property("exchangeUpdateStatus", codecForAny()) .property("ageRestrictionOptions", codecForList(codecForNumber())) .property("scopeInfo", codecForScopeInfo()) + .property("lastUpdateErrorInfo", codecForAny()) + .property("lastUpdateTimestamp", codecOptional(codecForPreciseTimestamp)) .build("ExchangeListItem"); export const codecForExchangesListResponse = (): Codec => diff --git a/packages/taler-wallet-core/src/exchanges.ts b/packages/taler-wallet-core/src/exchanges.ts index 4792c3c20..d17005705 100644 --- a/packages/taler-wallet-core/src/exchanges.ts +++ b/packages/taler-wallet-core/src/exchanges.ts @@ -309,6 +309,7 @@ async function makeExchangeListItem( ? AgeRestriction.getAgeGroupsFromMask(exchangeDetails.ageMask) : [], paytoUris: exchangeDetails?.wireInfo.accounts.map((x) => x.payto_uri) ?? [], + lastUpdateTimestamp: timestampOptionalPreciseFromDb(r.lastUpdate), lastUpdateErrorInfo, scopeInfo, }; diff --git a/packages/taler-wallet-webextension/src/wallet/AddExchange/test.ts b/packages/taler-wallet-webextension/src/wallet/AddExchange/test.ts index c9c119fd3..60d5b274c 100644 --- a/packages/taler-wallet-webextension/src/wallet/AddExchange/test.ts +++ b/packages/taler-wallet-webextension/src/wallet/AddExchange/test.ts @@ -19,18 +19,18 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { expect } from "chai"; -import { createWalletApiMock } from "../../test-utils.js"; -import * as tests from "@gnu-taler/web-util/testing"; -import { Props } from "./index.js"; -import { useComponentState } from "./state.js"; -import { nullFunction } from "../../mui/handlers.js"; -import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { ExchangeEntryStatus, ExchangeTosStatus, ExchangeUpdateStatus, } from "@gnu-taler/taler-util"; +import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; +import * as tests from "@gnu-taler/web-util/testing"; +import { expect } from "chai"; +import { nullFunction } from "../../mui/handlers.js"; +import { createWalletApiMock } from "../../test-utils.js"; +import { Props } from "./index.js"; +import { useComponentState } from "./state.js"; const props: Props = { onBack: nullFunction, noDebounce: true, @@ -54,6 +54,7 @@ describe("AddExchange states", () => { tosStatus: ExchangeTosStatus.Pending, exchangeUpdateStatus: ExchangeUpdateStatus.UnavailableUpdate, paytoUris: [], + lastUpdateTimestamp: undefined, }, ], }, diff --git a/packages/taler-wallet-webextension/src/wallet/DestinationSelection/test.ts b/packages/taler-wallet-webextension/src/wallet/DestinationSelection/test.ts index d42a3477d..3082ae7a4 100644 --- a/packages/taler-wallet-webextension/src/wallet/DestinationSelection/test.ts +++ b/packages/taler-wallet-webextension/src/wallet/DestinationSelection/test.ts @@ -27,8 +27,8 @@ import { ExchangeUpdateStatus, } from "@gnu-taler/taler-util"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; -import { expect } from "chai"; import * as tests from "@gnu-taler/web-util/testing"; +import { expect } from "chai"; import { nullFunction } from "../../mui/handlers.js"; import { createWalletApiMock } from "../../test-utils.js"; import { useComponentState } from "./state.js"; @@ -42,6 +42,7 @@ const exchangeArs: ExchangeListItem = { exchangeUpdateStatus: ExchangeUpdateStatus.Initial, paytoUris: [], ageRestrictionOptions: [], + lastUpdateTimestamp: undefined, }; describe("Destination selection states", () => { diff --git a/packages/taler-wallet-webextension/src/wallet/Settings.tsx b/packages/taler-wallet-webextension/src/wallet/Settings.tsx index 19b30dd5f..38e576496 100644 --- a/packages/taler-wallet-webextension/src/wallet/Settings.tsx +++ b/packages/taler-wallet-webextension/src/wallet/Settings.tsx @@ -15,6 +15,7 @@ */ import { + AbsoluteTime, ExchangeListItem, ExchangeTosStatus, LibtoolVersion, @@ -152,9 +153,15 @@ export function SettingsView({ URL + + Status + Terms of Service + + Last Update + Actions @@ -162,7 +169,7 @@ export function SettingsView({ {knownExchanges.map((e, idx) => { - function Status(): VNode { + function TosStatus(): VNode { switch (e.tosStatus) { case ExchangeTosStatus.Accepted: return ( @@ -195,7 +202,19 @@ export function SettingsView({ {e.exchangeBaseUrl} - + {e.exchangeEntryStatus} / {e.exchangeUpdateStatus} + + + + + + {e.lastUpdateTimestamp + ? AbsoluteTime.toIsoString( + AbsoluteTime.fromPreciseTimestamp( + e.lastUpdateTimestamp, + ), + ) + : "never"}