/* This file is part of GNU Taler (C) 2022 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 */ import { AbsoluteTime, NotificationType, ObservabilityEventType, RequestProgressNotification, TalerErrorCode, TalerErrorDetail, TaskProgressNotification, WalletNotification, assertUnreachable } from "@gnu-taler/taler-util"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; 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 { useSettings } from "../hooks/useSettings.js"; import { Button } from "../mui/Button.js"; import { WxApiType } from "../wxApi.js"; import { Modal } from "./Modal.js"; import { Time } from "./Time.js"; interface Props extends JSX.HTMLAttributes { } export function WalletActivity({ }: Props): VNode { const { i18n } = useTranslationContext() const [settings, updateSettings] = useSettings() const api = useBackendContext(); useEffect(() => { document.body.style.marginBottom = "250px" return () => { document.body.style.marginBottom = "0px" } }) const [table, setTable] = useState<"tasks" | "events">("tasks") return (
{ updateSettings("showWalletActivity", false) }}> close
{(function (): VNode { switch (table) { case "events": { return } case "tasks": { return } default: { assertUnreachable(table) } } })()}
); } interface MoreInfoPRops { events: (WalletNotification & { when: AbsoluteTime })[], onClick: (content: VNode) => void } type Notif = { id: string; events: (WalletNotification & { when: AbsoluteTime })[]; description: string; start: AbsoluteTime; end: AbsoluteTime; reference: { eventType: NotificationType, referenceType: "task" | "transaction" | "operation" | "exchange", id: string; } | undefined, MoreInfo: (p: MoreInfoPRops) => VNode; } function ShowBalanceChange({ events }: MoreInfoPRops): VNode { if (!events.length) return ; const not = events[0]; if (not.type !== NotificationType.BalanceChange) return ; return
Transaction
{not.hintTransactionId.substring(0, 10)}
} function ShowBackupOperationError({ events, onClick }: MoreInfoPRops): VNode { if (!events.length) return ; const not = events[0]; if (not.type !== NotificationType.BackupOperationError) return ; return
Error
{ e.preventDefault(); const error = not.error onClick(
Code
{TalerErrorCode[error.code]} ({error.code})
Hint
{error.hint ?? "--"}
Time
            {JSON.stringify(error, undefined, 2)}
          
) }}>{TalerErrorCode[not.error.code]}
} function ShowTransactionStateTransition({ events, onClick }: MoreInfoPRops): VNode { if (!events.length) return ; const not = events[0]; if (not.type !== NotificationType.TransactionStateTransition) return ; return
Old state
{not.oldTxState.major} - {not.oldTxState.minor ?? ""}
New state
{not.newTxState.major} - {not.newTxState.minor ?? ""}
Transaction
{not.transactionId.substring(0, 10)}
{not.errorInfo ?
Error
{ if (!not.errorInfo) return; e.preventDefault(); const error = not.errorInfo; onClick(
Code
{TalerErrorCode[error.code]} ({error.code})
Hint
{error.hint ?? "--"}
Message
{error.message ?? "--"}
) }}>{TalerErrorCode[not.errorInfo.code]}
: undefined}
Experimental
        {JSON.stringify(not.experimentalUserData, undefined, 2)}
      
} function ShowExchangeStateTransition({ events, onClick }: MoreInfoPRops): VNode { if (!events.length) return ; const not = events[0]; if (not.type !== NotificationType.ExchangeStateTransition) return ; return
Exchange
{not.exchangeBaseUrl}
{not.oldExchangeState && not.newExchangeState.exchangeEntryStatus !== not.oldExchangeState?.exchangeEntryStatus &&
Entry status
from {not.oldExchangeState.exchangeEntryStatus} to {not.newExchangeState.exchangeEntryStatus}
} {not.oldExchangeState && not.newExchangeState.exchangeUpdateStatus !== not.oldExchangeState?.exchangeUpdateStatus &&
Update status
from {not.oldExchangeState.exchangeUpdateStatus} to {not.newExchangeState.exchangeUpdateStatus}
} {not.oldExchangeState && not.newExchangeState.tosStatus !== not.oldExchangeState?.tosStatus &&
Tos status
from {not.oldExchangeState.tosStatus} to {not.newExchangeState.tosStatus}
}
} type ObservaNotifWithTime = ((TaskProgressNotification | RequestProgressNotification) & { when: AbsoluteTime; }) function ShowObservabilityEvent({ events, onClick }: MoreInfoPRops): VNode { // let prev: ObservaNotifWithTime; const asd = events.map(not => { if (not.type !== NotificationType.RequestObservabilityEvent && not.type !== NotificationType.TaskObservabilityEvent) return ; const title = (function () { switch (not.event.type) { case ObservabilityEventType.HttpFetchFinishError: case ObservabilityEventType.HttpFetchFinishSuccess: case ObservabilityEventType.HttpFetchStart: return "HTTP Request" case ObservabilityEventType.DbQueryFinishSuccess: case ObservabilityEventType.DbQueryFinishError: case ObservabilityEventType.DbQueryStart: return "Database" case ObservabilityEventType.RequestFinishSuccess: case ObservabilityEventType.RequestFinishError: case ObservabilityEventType.RequestStart: return "Wallet" case ObservabilityEventType.CryptoFinishSuccess: case ObservabilityEventType.CryptoFinishError: case ObservabilityEventType.CryptoStart: return "Crypto" case ObservabilityEventType.TaskStart: return "Task start" case ObservabilityEventType.TaskStop: return "Task stop" case ObservabilityEventType.TaskReset: return "Task reset" case ObservabilityEventType.ShepherdTaskResult: return "Schedule" case ObservabilityEventType.DeclareTaskDependency: return "Task dependency" } })(); return }) return {asd}
Event Info Start End
} function ShowObervavilityDetails({ title, notif, onClick, prev }: { title: string, notif: ObservaNotifWithTime, prev?: ObservaNotifWithTime, onClick: (content: VNode) => void }): VNode { switch (notif.event.type) { case ObservabilityEventType.HttpFetchStart: case ObservabilityEventType.HttpFetchFinishError: case ObservabilityEventType.HttpFetchFinishSuccess: { return { e.preventDefault(); onClick(
              {JSON.stringify({ event: notif, prev }, undefined, 2)}
            
); }}>{title}
{notif.event.url} { prev?.event.type === ObservabilityEventType.HttpFetchFinishSuccess ? `(${prev.event.status})` : prev?.event.type === ObservabilityEventType.HttpFetchFinishError ? { e.preventDefault(); if (prev.event.type !== ObservabilityEventType.HttpFetchFinishError) return; const error = prev.event.error onClick(
Code
{TalerErrorCode[error.code]} ({error.code})
Hint
{error.hint ?? "--"}
Time
                    {JSON.stringify(error, undefined, 2)}
                  
) }}>fail
: undefined }