remove deprecated notifications, implement isOffline
This commit is contained in:
parent
9853f54201
commit
1961f4744c
@ -1,143 +0,0 @@
|
|||||||
#!/usr/bin/env node
|
|
||||||
/*
|
|
||||||
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 <http://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
|
|
||||||
import linaria from "@linaria/esbuild";
|
|
||||||
import esbuild from "esbuild";
|
|
||||||
import path from "path";
|
|
||||||
import fs from "fs";
|
|
||||||
|
|
||||||
function getFilesInDirectory(startPath, regex) {
|
|
||||||
if (!fs.existsSync(startPath)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const files = fs.readdirSync(startPath);
|
|
||||||
const result = files
|
|
||||||
.flatMap((file) => {
|
|
||||||
const filename = path.join(startPath, file);
|
|
||||||
|
|
||||||
const stat = fs.lstatSync(filename);
|
|
||||||
if (stat.isDirectory()) {
|
|
||||||
return getFilesInDirectory(filename, regex);
|
|
||||||
} else if (regex.test(filename)) {
|
|
||||||
return filename;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.filter((x) => !!x);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// eslint-disable-next-line no-undef
|
|
||||||
const BASE = process.cwd();
|
|
||||||
const allTestFiles = getFilesInDirectory(path.join(BASE, "src"), /.test.ts$/);
|
|
||||||
|
|
||||||
const preact = path.join(
|
|
||||||
BASE,
|
|
||||||
"node_modules",
|
|
||||||
"preact",
|
|
||||||
"compat",
|
|
||||||
"dist",
|
|
||||||
"compat.module.js",
|
|
||||||
);
|
|
||||||
const preactCompatPlugin = {
|
|
||||||
name: "preact-compat",
|
|
||||||
setup(build) {
|
|
||||||
build.onResolve({ filter: /^(react-dom|react)$/ }, (args) => ({
|
|
||||||
path: preact,
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const entryPoints = [
|
|
||||||
"src/popupEntryPoint.tsx",
|
|
||||||
"src/popupEntryPoint.dev.tsx",
|
|
||||||
"src/walletEntryPoint.tsx",
|
|
||||||
"src/walletEntryPoint.dev.tsx",
|
|
||||||
"src/background.ts",
|
|
||||||
"src/stories.tsx",
|
|
||||||
"src/background.dev.ts",
|
|
||||||
"src/taler-wallet-interaction-loader.ts",
|
|
||||||
"src/taler-wallet-interaction-support.ts",
|
|
||||||
"src/browserWorkerEntry.ts",
|
|
||||||
];
|
|
||||||
|
|
||||||
let GIT_ROOT = BASE;
|
|
||||||
while (!fs.existsSync(path.join(GIT_ROOT, ".git")) && GIT_ROOT !== "/") {
|
|
||||||
GIT_ROOT = path.join(GIT_ROOT, "../");
|
|
||||||
}
|
|
||||||
if (GIT_ROOT === "/") {
|
|
||||||
// eslint-disable-next-line no-undef
|
|
||||||
console.log("not found");
|
|
||||||
// eslint-disable-next-line no-undef
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
const GIT_HASH = GIT_ROOT === "/" ? undefined : git_hash();
|
|
||||||
|
|
||||||
let _package = JSON.parse(fs.readFileSync(path.join(BASE, "package.json")));
|
|
||||||
|
|
||||||
function git_hash() {
|
|
||||||
const rev = fs
|
|
||||||
.readFileSync(path.join(GIT_ROOT, ".git", "HEAD"))
|
|
||||||
.toString()
|
|
||||||
.trim()
|
|
||||||
.split(/.*[: ]/)
|
|
||||||
.slice(-1)[0];
|
|
||||||
if (rev.indexOf("/") === -1) {
|
|
||||||
return rev;
|
|
||||||
} else {
|
|
||||||
return fs.readFileSync(path.join(GIT_ROOT, ".git", rev)).toString().trim();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const buildConfig = {
|
|
||||||
entryPoints: [...entryPoints, ...allTestFiles],
|
|
||||||
bundle: true,
|
|
||||||
outdir: "dist",
|
|
||||||
minify: false,
|
|
||||||
loader: {
|
|
||||||
".svg": "text",
|
|
||||||
".png": "dataurl",
|
|
||||||
".jpeg": "dataurl",
|
|
||||||
},
|
|
||||||
target: ["es6"],
|
|
||||||
format: "iife",
|
|
||||||
platform: "browser",
|
|
||||||
sourcemap: true,
|
|
||||||
jsxFactory: "h",
|
|
||||||
jsxFragment: "Fragment",
|
|
||||||
define: {
|
|
||||||
__VERSION__: `"${_package.version}"`,
|
|
||||||
__GIT_HASH__: `"${GIT_HASH}"`,
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
preactCompatPlugin,
|
|
||||||
linaria.default({
|
|
||||||
babelOptions: {
|
|
||||||
babelrc: false,
|
|
||||||
configFile: "./babel.config-linaria.json",
|
|
||||||
},
|
|
||||||
sourceMap: true,
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
await esbuild.build(buildConfig).catch((e) => {
|
|
||||||
// eslint-disable-next-line no-undef
|
|
||||||
console.log(e);
|
|
||||||
// eslint-disable-next-line no-undef
|
|
||||||
process.exit(1);
|
|
||||||
});
|
|
@ -19,7 +19,7 @@ import { getFilesInDirectory, initializeDev } from "@gnu-taler/web-util/build";
|
|||||||
import { serve } from "@gnu-taler/web-util/node";
|
import { serve } from "@gnu-taler/web-util/node";
|
||||||
import linaria from "@linaria/esbuild";
|
import linaria from "@linaria/esbuild";
|
||||||
|
|
||||||
const allStaticFiles = getFilesInDirectory("src/spa");
|
const allStaticFiles = getFilesInDirectory("src/pwa");
|
||||||
|
|
||||||
const devEntryPoints = [
|
const devEntryPoints = [
|
||||||
"src/popupEntryPoint.dev.tsx",
|
"src/popupEntryPoint.dev.tsx",
|
||||||
|
@ -799,6 +799,17 @@ export const ErrorBox = styled.div`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const RedBanner = styled.div`
|
||||||
|
width: 80%;
|
||||||
|
padding: 4px;
|
||||||
|
text-align: center;
|
||||||
|
background: red;
|
||||||
|
border: 1px solid #df3a3a;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-weight: bold;
|
||||||
|
margin: 4px;
|
||||||
|
`;
|
||||||
|
|
||||||
export const InfoBox = styled(ErrorBox)`
|
export const InfoBox = styled(ErrorBox)`
|
||||||
color: black;
|
color: black;
|
||||||
background-color: #d1e7dd;
|
background-color: #d1e7dd;
|
||||||
|
@ -49,7 +49,7 @@ export function useComponentState({
|
|||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
api.listener.onUpdateNotification(
|
api.listener.onUpdateNotification(
|
||||||
[NotificationType.CoinWithdrawn],
|
[NotificationType.TransactionStateTransition],
|
||||||
hook?.retry,
|
hook?.retry,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -123,7 +123,9 @@ export function useComponentState({
|
|||||||
raw,
|
raw,
|
||||||
goToWalletManualWithdraw,
|
goToWalletManualWithdraw,
|
||||||
summary,
|
summary,
|
||||||
expiration: expiration ? AbsoluteTime.fromProtocolTimestamp(expiration) : undefined,
|
expiration: expiration
|
||||||
|
? AbsoluteTime.fromProtocolTimestamp(expiration)
|
||||||
|
: undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!foundBalance) {
|
if (!foundBalance) {
|
||||||
|
@ -54,7 +54,7 @@ export function useComponentState({
|
|||||||
useEffect(
|
useEffect(
|
||||||
() =>
|
() =>
|
||||||
api.listener.onUpdateNotification(
|
api.listener.onUpdateNotification(
|
||||||
[NotificationType.CoinWithdrawn],
|
[NotificationType.TransactionStateTransition],
|
||||||
hook?.retry,
|
hook?.retry,
|
||||||
),
|
),
|
||||||
[hook],
|
[hook],
|
||||||
|
@ -541,7 +541,9 @@ describe("Payment CTA states", () => {
|
|||||||
// expect(r.totalFees).deep.equal(Amounts.parseOrThrow("USD:1"));
|
// expect(r.totalFees).deep.equal(Amounts.parseOrThrow("USD:1"));
|
||||||
expect(state.payHandler.onClick).not.undefined;
|
expect(state.payHandler.onClick).not.undefined;
|
||||||
|
|
||||||
handler.notifyEventFromWallet(NotificationType.CoinWithdrawn);
|
handler.notifyEventFromWallet(
|
||||||
|
NotificationType.TransactionStateTransition,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
(state) => {
|
(state) => {
|
||||||
if (state.status !== "ready") expect.fail();
|
if (state.status !== "ready") expect.fail();
|
||||||
|
@ -128,7 +128,7 @@ export function useComponentState({
|
|||||||
}
|
}
|
||||||
const errors = undefinedIfEmpty({
|
const errors = undefinedIfEmpty({
|
||||||
amount: amount && Amounts.isZero(amount) ? i18n.str`required` : undefined,
|
amount: amount && Amounts.isZero(amount) ? i18n.str`required` : undefined,
|
||||||
summary: !summary ? i18n.str`required` : undefined,
|
summary: summary !== undefined && !summary ? i18n.str`required` : undefined,
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
status: "fill-template",
|
status: "fill-template",
|
||||||
|
14
packages/taler-wallet-webextension/src/hooks/useIsOnline.ts
Normal file
14
packages/taler-wallet-webextension/src/hooks/useIsOnline.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { codecForBoolean } from "@gnu-taler/taler-util";
|
||||||
|
import { buildStorageKey, useMemoryStorage } from "@gnu-taler/web-util/browser";
|
||||||
|
import { platform } from "../platform/foreground.js";
|
||||||
|
import { useEffect } from "preact/hooks";
|
||||||
|
|
||||||
|
export function useIsOnline(): boolean {
|
||||||
|
const { value, update } = useMemoryStorage("online", true);
|
||||||
|
useEffect(() => {
|
||||||
|
return platform.listenNetworkConnectionState((state) => {
|
||||||
|
update(state === "on");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return value;
|
||||||
|
}
|
@ -286,4 +286,11 @@ export interface ForegroundPlatformAPI {
|
|||||||
listenToWalletBackground(
|
listenToWalletBackground(
|
||||||
listener: (message: MessageFromBackend) => void,
|
listener: (message: MessageFromBackend) => void,
|
||||||
): () => void;
|
): () => void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notify when platform went offline
|
||||||
|
*/
|
||||||
|
listenNetworkConnectionState(
|
||||||
|
listener: (state: "on" | "off") => void,
|
||||||
|
): () => void;
|
||||||
}
|
}
|
||||||
|
@ -58,6 +58,7 @@ const api: BackgroundPlatformAPI & ForegroundPlatformAPI = {
|
|||||||
sendMessageToBackground,
|
sendMessageToBackground,
|
||||||
useServiceWorkerAsBackgroundProcess,
|
useServiceWorkerAsBackgroundProcess,
|
||||||
keepAlive,
|
keepAlive,
|
||||||
|
listenNetworkConnectionState,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default api;
|
export default api;
|
||||||
@ -762,3 +763,20 @@ async function findTalerUriInActiveTab(): Promise<string | undefined> {
|
|||||||
if (!tab || tab.id === undefined) return;
|
if (!tab || tab.id === undefined) return;
|
||||||
return findTalerUriInTab(tab.id);
|
return findTalerUriInTab(tab.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function listenNetworkConnectionState(
|
||||||
|
notify: (state: "on" | "off") => void,
|
||||||
|
): () => void {
|
||||||
|
function notifyOffline() {
|
||||||
|
notify("off");
|
||||||
|
}
|
||||||
|
function notifyOnline() {
|
||||||
|
notify("on");
|
||||||
|
}
|
||||||
|
window.addEventListener("offline", notifyOffline);
|
||||||
|
window.addEventListener("online", notifyOnline);
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener("offline", notifyOffline);
|
||||||
|
window.removeEventListener("online", notifyOnline);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
@ -34,6 +34,7 @@ const api: BackgroundPlatformAPI & ForegroundPlatformAPI = {
|
|||||||
keepAlive: (cb: VoidFunction) => cb(),
|
keepAlive: (cb: VoidFunction) => cb(),
|
||||||
findTalerUriInActiveTab: async () => undefined,
|
findTalerUriInActiveTab: async () => undefined,
|
||||||
findTalerUriInClipboard: async () => undefined,
|
findTalerUriInClipboard: async () => undefined,
|
||||||
|
listenNetworkConnectionState,
|
||||||
getPermissionsApi: () => ({
|
getPermissionsApi: () => ({
|
||||||
addPermissionsListener: () => undefined,
|
addPermissionsListener: () => undefined,
|
||||||
containsHostPermissions: async () => true,
|
containsHostPermissions: async () => true,
|
||||||
@ -197,3 +198,20 @@ interface IframeMessageCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default api;
|
export default api;
|
||||||
|
|
||||||
|
function listenNetworkConnectionState(
|
||||||
|
notify: (state: "on" | "off") => void,
|
||||||
|
): () => void {
|
||||||
|
function notifyOffline() {
|
||||||
|
notify("off");
|
||||||
|
}
|
||||||
|
function notifyOnline() {
|
||||||
|
notify("on");
|
||||||
|
}
|
||||||
|
window.addEventListener("offline", notifyOffline);
|
||||||
|
window.addEventListener("online", notifyOnline);
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener("offline", notifyOffline);
|
||||||
|
window.removeEventListener("online", notifyOnline);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
@ -44,6 +44,7 @@ import { LogoHeader } from "../components/LogoHeader.js";
|
|||||||
import PendingTransactions from "../components/PendingTransactions.js";
|
import PendingTransactions from "../components/PendingTransactions.js";
|
||||||
import {
|
import {
|
||||||
LinkPrimary,
|
LinkPrimary,
|
||||||
|
RedBanner,
|
||||||
SubTitle,
|
SubTitle,
|
||||||
WalletAction,
|
WalletAction,
|
||||||
WalletBox,
|
WalletBox,
|
||||||
@ -80,6 +81,7 @@ import { QrReaderPage } from "./QrReader.js";
|
|||||||
import { SettingsPage } from "./Settings.js";
|
import { SettingsPage } from "./Settings.js";
|
||||||
import { TransactionPage } from "./Transaction.js";
|
import { TransactionPage } from "./Transaction.js";
|
||||||
import { WelcomePage } from "./Welcome.js";
|
import { WelcomePage } from "./Welcome.js";
|
||||||
|
import { useIsOnline } from "../hooks/useIsOnline.js";
|
||||||
|
|
||||||
export function Application(): VNode {
|
export function Application(): VNode {
|
||||||
const { i18n } = useTranslationContext();
|
const { i18n } = useTranslationContext();
|
||||||
@ -585,8 +587,15 @@ function WalletTemplate({
|
|||||||
children: ComponentChildren;
|
children: ComponentChildren;
|
||||||
goToTransaction?: (id: string) => Promise<void>;
|
goToTransaction?: (id: string) => Promise<void>;
|
||||||
}): VNode {
|
}): VNode {
|
||||||
|
const online = useIsOnline();
|
||||||
|
const { i18n } = useTranslationContext();
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
|
{!online && (
|
||||||
|
<div style={{ display: "flex", justifyContent: "center" }}>
|
||||||
|
<RedBanner>{i18n.str`Network is offline`}</RedBanner>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<LogoHeader />
|
<LogoHeader />
|
||||||
<WalletNavBar path={path} />
|
<WalletNavBar path={path} />
|
||||||
{goToTransaction ? (
|
{goToTransaction ? (
|
||||||
|
@ -47,8 +47,6 @@ export function DeveloperPage(): VNode {
|
|||||||
const [status, timedOut] = useDiagnostics();
|
const [status, timedOut] = useDiagnostics();
|
||||||
|
|
||||||
const listenAllEvents = Array.from<NotificationType>({ length: 1 });
|
const listenAllEvents = Array.from<NotificationType>({ length: 1 });
|
||||||
//FIXME: waiting for retry notification make a always increasing loop of notifications
|
|
||||||
listenAllEvents.includes = (e) => e !== "waiting-for-retry"; // includes every event
|
|
||||||
|
|
||||||
const api = useBackendContext();
|
const api = useBackendContext();
|
||||||
|
|
||||||
@ -405,7 +403,9 @@ export function View({
|
|||||||
<i18n.Translate>
|
<i18n.Translate>
|
||||||
Database exported at
|
Database exported at
|
||||||
<Time
|
<Time
|
||||||
timestamp={AbsoluteTime.fromMilliseconds(downloadedDatabase.time.getTime())}
|
timestamp={AbsoluteTime.fromMilliseconds(
|
||||||
|
downloadedDatabase.time.getTime(),
|
||||||
|
)}
|
||||||
format="yyyy/MM/dd HH:mm:ss"
|
format="yyyy/MM/dd HH:mm:ss"
|
||||||
/>
|
/>
|
||||||
<a
|
<a
|
||||||
|
@ -22,7 +22,7 @@ const allTestFiles = getFilesInDirectory("src", /.test.tsx?$/);
|
|||||||
await build({
|
await build({
|
||||||
type: "test",
|
type: "test",
|
||||||
source: {
|
source: {
|
||||||
js: allTestFiles,
|
js: allTestFiles.files,
|
||||||
assets: [],
|
assets: [],
|
||||||
},
|
},
|
||||||
destination: "./dist/test",
|
destination: "./dist/test",
|
||||||
|
Loading…
Reference in New Issue
Block a user