use latest linaria lib
2
Makefile
@ -97,7 +97,7 @@ anastasis-webui-dev:
|
|||||||
webextension:
|
webextension:
|
||||||
pnpm install --frozen-lockfile --filter @gnu-taler/taler-wallet-webextension...
|
pnpm install --frozen-lockfile --filter @gnu-taler/taler-wallet-webextension...
|
||||||
pnpm run --filter @gnu-taler/taler-wallet-webextension... compile
|
pnpm run --filter @gnu-taler/taler-wallet-webextension... compile
|
||||||
cd ./packages/taler-wallet-webextension/ && ./pack.sh dev
|
cd ./packages/taler-wallet-webextension/ && ./pack.sh prod
|
||||||
|
|
||||||
.PHONY: webextension-dev
|
.PHONY: webextension-dev
|
||||||
webextension-dev:
|
webextension-dev:
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { serve } from "@gnu-taler/web-util/node";
|
import { serve } from "@gnu-taler/web-util/node";
|
||||||
import { initializeDev, getFilesInDirectory } from "@gnu-taler/web-util/build";
|
import { initializeDev } from "@gnu-taler/web-util/build";
|
||||||
|
|
||||||
const devEntryPoints = ["src/stories.tsx", "src/index.tsx"];
|
const devEntryPoints = ["src/stories.tsx", "src/index.tsx"];
|
||||||
|
|
||||||
@ -26,6 +26,7 @@ const build = initializeDev({
|
|||||||
assets: ["src/index.html"],
|
assets: ["src/index.html"],
|
||||||
},
|
},
|
||||||
destination: "./dist/dev",
|
destination: "./dist/dev",
|
||||||
|
public: "/app",
|
||||||
css: "sass",
|
css: "sass",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -13,18 +13,17 @@
|
|||||||
You should have received a copy of the GNU General Public License along with
|
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/>
|
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author Sebastian Javier Marchano (sebasjm)
|
* @author Sebastian Javier Marchano (sebasjm)
|
||||||
*/
|
*/
|
||||||
/*
|
|
||||||
* Linaria need pre-process typscript files into javascript before running.
|
import * as tests from "@gnu-taler/web-util/testing";
|
||||||
* We choose to use the default preact-cli config.
|
import { BankFrame } from "./BankFrame.js";
|
||||||
* This file should be used from @linaria/rollup plugin only
|
|
||||||
*/
|
export default {
|
||||||
{
|
title: "bank frame",
|
||||||
"presets": [
|
};
|
||||||
"preact-cli/babel",
|
|
||||||
],
|
export const Ready = tests.createExample(BankFrame, {});
|
||||||
"plugins": ["./trim-extension.cjs"],
|
|
||||||
}
|
|
@ -17,3 +17,4 @@
|
|||||||
export * as qr from "./QrCodeSection.stories.js";
|
export * as qr from "./QrCodeSection.stories.js";
|
||||||
export * as po from "./PaymentOptions.stories.js";
|
export * as po from "./PaymentOptions.stories.js";
|
||||||
export * as ptf from "./PaytoWireTransferForm.stories.js";
|
export * as ptf from "./PaytoWireTransferForm.stories.js";
|
||||||
|
export * as frame from "./BankFrame.stories.js";
|
||||||
|
@ -15,53 +15,12 @@
|
|||||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
|
||||||
build,
|
|
||||||
computeConfig,
|
|
||||||
getFilesInDirectory,
|
|
||||||
} from "@gnu-taler/web-util/build";
|
|
||||||
import linaria from "@linaria/esbuild";
|
import linaria from "@linaria/esbuild";
|
||||||
import esbuild from "esbuild";
|
import { build, getFilesInDirectory } from "@gnu-taler/web-util/build";
|
||||||
import path from "path";
|
|
||||||
import fs from "fs";
|
|
||||||
|
|
||||||
const BASE = process.cwd();
|
|
||||||
|
|
||||||
const allStaticFiles = getFilesInDirectory("static");
|
const allStaticFiles = getFilesInDirectory("static");
|
||||||
|
|
||||||
// await build({
|
await build({
|
||||||
// source: {
|
|
||||||
// js: [
|
|
||||||
// "src/popupEntryPoint.tsx",
|
|
||||||
// "src/walletEntryPoint.tsx",
|
|
||||||
// "src/background.ts",
|
|
||||||
// "src/taler-wallet-interaction-loader.ts",
|
|
||||||
// "src/taler-wallet-interaction-support.ts",
|
|
||||||
// "src/browserWorkerEntry.ts",
|
|
||||||
// ],
|
|
||||||
// assets: allStaticFiles,
|
|
||||||
// },
|
|
||||||
// destination: "./dist/prod",
|
|
||||||
// css: "linaria",
|
|
||||||
// });
|
|
||||||
function copyFilesPlugin(files) {
|
|
||||||
return {
|
|
||||||
name: "copy-files",
|
|
||||||
setup(build) {
|
|
||||||
const outDir = build.initialOptions.outdir;
|
|
||||||
if (outDir === undefined)
|
|
||||||
throw Error("esbuild build options does not specify outdir");
|
|
||||||
build.onEnd(() => {
|
|
||||||
for (const file of files) {
|
|
||||||
const name = path.parse(file).base;
|
|
||||||
fs.copyFileSync(file, path.join(outDir, name));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const buildConfig2 = computeConfig({
|
|
||||||
source: {
|
source: {
|
||||||
js: [
|
js: [
|
||||||
"src/popupEntryPoint.tsx",
|
"src/popupEntryPoint.tsx",
|
||||||
@ -75,45 +34,17 @@ const buildConfig2 = computeConfig({
|
|||||||
},
|
},
|
||||||
destination: "./dist/prod",
|
destination: "./dist/prod",
|
||||||
css: "linaria",
|
css: "linaria",
|
||||||
});
|
linariaPlugin: () => {
|
||||||
|
// linaria has a bug if this run in web-util library
|
||||||
const preact = path.join(
|
return linaria({
|
||||||
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 asd = linaria.default({
|
|
||||||
babelOptions: {
|
babelOptions: {
|
||||||
babelrc: false,
|
presets: [
|
||||||
configFile: "./babel.config-linaria.json",
|
"@babel/preset-typescript",
|
||||||
|
"@babel/preset-react",
|
||||||
|
"@linaria",
|
||||||
|
],
|
||||||
},
|
},
|
||||||
sourceMap: true,
|
sourceMap: true,
|
||||||
});
|
});
|
||||||
|
},
|
||||||
// buildConfig2.plugins = [
|
|
||||||
// preactCompatPlugin,
|
|
||||||
// copyFilesPlugin(allStaticFiles),
|
|
||||||
// asd,
|
|
||||||
// ];
|
|
||||||
|
|
||||||
// console.log(JSON.stringify(buildConfig, undefined, 2));
|
|
||||||
// console.log(JSON.stringify(buildConfig2, undefined, 2));
|
|
||||||
|
|
||||||
await esbuild.build(buildConfig2).catch((e) => {
|
|
||||||
// eslint-disable-next-line no-undef
|
|
||||||
console.log(e);
|
|
||||||
// eslint-disable-next-line no-undef
|
|
||||||
process.exit(1);
|
|
||||||
});
|
});
|
||||||
|
@ -5,7 +5,7 @@ set -e
|
|||||||
rm -rf dist lib tsconfig.tsbuildinfo .linaria-cache
|
rm -rf dist lib tsconfig.tsbuildinfo .linaria-cache
|
||||||
|
|
||||||
echo typecheck and bundle...
|
echo typecheck and bundle...
|
||||||
node build-fast-with-linaria.mjs &
|
node build.mjs &
|
||||||
pnpm tsc --noEmit &
|
pnpm tsc --noEmit &
|
||||||
wait -n
|
wait -n
|
||||||
wait -n
|
wait -n
|
||||||
|
@ -15,18 +15,52 @@
|
|||||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import linaria from "@linaria/esbuild";
|
||||||
import { serve } from "@gnu-taler/web-util/node";
|
import { serve } from "@gnu-taler/web-util/node";
|
||||||
import esbuild from "esbuild";
|
import { initializeDev, getFilesInDirectory } from "@gnu-taler/web-util/build";
|
||||||
import { buildConfig } from "./build-fast-with-linaria.mjs";
|
|
||||||
|
|
||||||
buildConfig.inject = ["./node_modules/@gnu-taler/web-util/lib/live-reload.mjs"];
|
const allStaticFiles = getFilesInDirectory("static");
|
||||||
|
|
||||||
|
const devEntryPoints = [
|
||||||
|
"src/popupEntryPoint.tsx",
|
||||||
|
"src/walletEntryPoint.tsx",
|
||||||
|
"src/background.ts",
|
||||||
|
"src/taler-wallet-interaction-loader.ts",
|
||||||
|
"src/taler-wallet-interaction-support.ts",
|
||||||
|
"src/browserWorkerEntry.ts",
|
||||||
|
"src/stories.tsx",
|
||||||
|
];
|
||||||
|
|
||||||
|
const build = initializeDev({
|
||||||
|
source: {
|
||||||
|
js: devEntryPoints,
|
||||||
|
assets: allStaticFiles,
|
||||||
|
},
|
||||||
|
destination: "./dist/dev",
|
||||||
|
public: "/app",
|
||||||
|
css: "linaria",
|
||||||
|
linariaPlugin: () => {
|
||||||
|
// linaria has a bug if this run in web-util library
|
||||||
|
return linaria({
|
||||||
|
babelOptions: {
|
||||||
|
presets: [
|
||||||
|
"@babel/preset-typescript",
|
||||||
|
"@babel/preset-react",
|
||||||
|
"@linaria",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
sourceMap: true,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await build();
|
||||||
|
|
||||||
serve({
|
serve({
|
||||||
folder: "./dist",
|
folder: "./dist/dev",
|
||||||
port: 8080,
|
port: 8080,
|
||||||
source: "./src",
|
source: "./src",
|
||||||
development: true,
|
onSourceUpdate: build,
|
||||||
onUpdate: async () => esbuild.build(buildConfig),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// FIXME: create a mocha test in the browser as it was before
|
// FIXME: create a mocha test in the browser as it was before
|
||||||
|
@ -13,11 +13,14 @@ fi
|
|||||||
|
|
||||||
vers_manifest=$(jq -r '.version' manifest-common.json)
|
vers_manifest=$(jq -r '.version' manifest-common.json)
|
||||||
|
|
||||||
|
|
||||||
|
# Create version form Manifest v2
|
||||||
zipfile="taler-wallet-webextension-${vers_manifest}.zip"
|
zipfile="taler-wallet-webextension-${vers_manifest}.zip"
|
||||||
|
|
||||||
TEMP_DIR=$(mktemp -d)
|
TEMP_DIR=$(mktemp -d)
|
||||||
jq -s 'add | .name = "GNU Taler Wallet" ' manifest-common.json manifest-v2.json > $TEMP_DIR/manifest.json
|
jq -s 'add | .name = "GNU Taler Wallet" ' manifest-common.json manifest-v2.json > $TEMP_DIR/manifest.json
|
||||||
cp -r dist static $TEMP_DIR
|
cp -r static $TEMP_DIR
|
||||||
|
cp -r dist/prod $TEMP_DIR/dist
|
||||||
|
|
||||||
find $TEMP_DIR/dist \( -name "test.*" -o -name "*.test.*" -o -name "stories.*" -o -name "*.dev.*" \) -delete
|
find $TEMP_DIR/dist \( -name "test.*" -o -name "*.test.*" -o -name "stories.*" -o -name "*.dev.*" \) -delete
|
||||||
[[ "$ENV" == "prod" ]] && find $TEMP_DIR/dist \( -name "*.map" \) -delete
|
[[ "$ENV" == "prod" ]] && find $TEMP_DIR/dist \( -name "*.map" \) -delete
|
||||||
@ -35,11 +38,14 @@ mkdir -p extension/v2/unpacked
|
|||||||
echo "Packed webextension: extension/v2/$zipfile"
|
echo "Packed webextension: extension/v2/$zipfile"
|
||||||
cp -rf src extension/v2/unpacked
|
cp -rf src extension/v2/unpacked
|
||||||
|
|
||||||
|
# Create version form Manifest v3
|
||||||
zipfile="taler-wallet-webextension-${vers_manifest}.zip"
|
zipfile="taler-wallet-webextension-${vers_manifest}.zip"
|
||||||
|
|
||||||
TEMP_DIR=$(mktemp -d)
|
TEMP_DIR=$(mktemp -d)
|
||||||
jq -s 'add | .name = "GNU Taler Wallet" ' manifest-common.json manifest-v3.json > $TEMP_DIR/manifest.json
|
jq -s 'add | .name = "GNU Taler Wallet" ' manifest-common.json manifest-v3.json > $TEMP_DIR/manifest.json
|
||||||
cp -r dist static service_worker.js $TEMP_DIR
|
cp -r static $TEMP_DIR
|
||||||
|
cp -r dist/prod $TEMP_DIR/dist
|
||||||
|
cp -r service_worker.js $TEMP_DIR
|
||||||
|
|
||||||
find $TEMP_DIR/dist \( -name "test.*" -o -name "*.test.*" -o -name "stories.*" -o -name "*.dev.*" \) -delete
|
find $TEMP_DIR/dist \( -name "test.*" -o -name "*.test.*" -o -name "stories.*" -o -name "*.dev.*" \) -delete
|
||||||
[[ "$ENV" == "prod" ]] && find $TEMP_DIR/dist \( -name "*.map" \) -delete
|
[[ "$ENV" == "prod" ]] && find $TEMP_DIR/dist \( -name "*.map" \) -delete
|
||||||
|
@ -10,9 +10,9 @@
|
|||||||
"private": false,
|
"private": false,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"clean": "rimraf dist lib tsconfig.tsbuildinfo",
|
"clean": "rimraf dist lib tsconfig.tsbuildinfo",
|
||||||
"test": "mocha --require source-map-support/register 'dist/**/*.test.js' 'dist/**/test.js'",
|
"test": "./test.mjs && mocha --require source-map-support/register 'dist/test/**/*.test.js' 'dist/test/**/test.js'",
|
||||||
"test:coverage": "nyc pnpm test",
|
"test:coverage": "nyc pnpm test",
|
||||||
"compile": "tsc && ./build-fast-with-linaria.mjs",
|
"compile": "tsc && ./build.mjs",
|
||||||
"prepare": "tsc",
|
"prepare": "tsc",
|
||||||
"dev": "./dev.mjs",
|
"dev": "./dev.mjs",
|
||||||
"pretty": "prettier --write src",
|
"pretty": "prettier --write src",
|
||||||
@ -44,27 +44,21 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "7.18.9",
|
"@babel/preset-react": "^7.22.3",
|
||||||
"@babel/plugin-transform-modules-commonjs": "7.18.6",
|
|
||||||
"@babel/plugin-transform-react-jsx-source": "7.18.6",
|
|
||||||
"@babel/plugin-transform-typescript": "^7.20.13",
|
|
||||||
"@babel/preset-typescript": "7.18.6",
|
"@babel/preset-typescript": "7.18.6",
|
||||||
"@babel/runtime": "7.18.9",
|
|
||||||
"@gnu-taler/pogen": "workspace:*",
|
"@gnu-taler/pogen": "workspace:*",
|
||||||
"@gnu-taler/web-util": "workspace:*",
|
"@gnu-taler/web-util": "workspace:*",
|
||||||
"@linaria/babel-preset": "3.0.0-beta.22",
|
"@linaria/babel-preset": "^4.4.5",
|
||||||
"@linaria/core": "3.0.0-beta.22",
|
"@linaria/core": "^4.2.10",
|
||||||
"@linaria/react": "3.0.0-beta.22",
|
"@linaria/esbuild": "^4.2.11",
|
||||||
"@linaria/webpack-loader": "3.0.0-beta.22",
|
"@linaria/react": "^4.3.8",
|
||||||
"@types/chai": "^4.3.0",
|
"@types/chai": "^4.3.0",
|
||||||
"@types/chrome": "0.0.197",
|
"@types/chrome": "0.0.197",
|
||||||
"@types/history": "^4.7.8",
|
"@types/history": "^4.7.8",
|
||||||
"@types/mocha": "^9.0.0",
|
"@types/mocha": "^9.0.0",
|
||||||
"@types/node": "^18.11.17",
|
"@types/node": "^18.11.17",
|
||||||
"babel-loader": "^8.2.3",
|
|
||||||
"babel-plugin-transform-react-jsx": "^6.24.1",
|
|
||||||
"chai": "^4.3.6",
|
"chai": "^4.3.6",
|
||||||
"esbuild": "^0.17.7",
|
"esbuild": "^0.17.19",
|
||||||
"mocha": "^9.2.0",
|
"mocha": "^9.2.0",
|
||||||
"nyc": "^15.1.0",
|
"nyc": "^15.1.0",
|
||||||
"polished": "^4.1.4",
|
"polished": "^4.1.4",
|
||||||
|
@ -34,9 +34,9 @@ import {
|
|||||||
} from "./components/styled/index.js";
|
} from "./components/styled/index.js";
|
||||||
import { useBackendContext } from "./context/backend.js";
|
import { useBackendContext } from "./context/backend.js";
|
||||||
import { useAsyncAsHook } from "./hooks/useAsyncAsHook.js";
|
import { useAsyncAsHook } from "./hooks/useAsyncAsHook.js";
|
||||||
import qrIcon from "./svg/qr_code_24px.svg";
|
import qrIcon from "./svg/qr_code_24px.inline.svg";
|
||||||
import settingsIcon from "./svg/settings_black_24dp.svg";
|
import settingsIcon from "./svg/settings_black_24dp.inline.svg";
|
||||||
import warningIcon from "./svg/warning_24px.svg";
|
import warningIcon from "./svg/warning_24px.inline.svg";
|
||||||
import { parseTalerUri, TalerUriAction } from "@gnu-taler/taler-util";
|
import { parseTalerUri, TalerUriAction } from "@gnu-taler/taler-util";
|
||||||
import { useTranslationContext } from "@gnu-taler/web-util/browser";
|
import { useTranslationContext } from "@gnu-taler/web-util/browser";
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ import { Avatar } from "../mui/Avatar.js";
|
|||||||
import { Typography } from "../mui/Typography.js";
|
import { Typography } from "../mui/Typography.js";
|
||||||
import { Banner } from "./Banner.js";
|
import { Banner } from "./Banner.js";
|
||||||
import { SvgIcon } from "./styled/index.js";
|
import { SvgIcon } from "./styled/index.js";
|
||||||
import wifiIcon from "../svg/wifi.svg";
|
import wifiIcon from "../svg/wifi.inline.svg";
|
||||||
export default {
|
export default {
|
||||||
title: "banner",
|
title: "banner",
|
||||||
component: Banner,
|
component: Banner,
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
import { TranslatedString } from "@gnu-taler/taler-util";
|
import { TranslatedString } from "@gnu-taler/taler-util";
|
||||||
import { h, VNode } from "preact";
|
import { h, VNode } from "preact";
|
||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
import arrowDown from "../svg/chevron-down.svg";
|
import arrowDown from "../svg/chevron-down.inline.svg";
|
||||||
import { ErrorBox } from "./styled/index.js";
|
import { ErrorBox } from "./styled/index.js";
|
||||||
|
|
||||||
export function ErrorMessage({
|
export function ErrorMessage({
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
import { TalerErrorDetail, TranslatedString } from "@gnu-taler/taler-util";
|
import { TalerErrorDetail, TranslatedString } from "@gnu-taler/taler-util";
|
||||||
import { Fragment, h, VNode } from "preact";
|
import { Fragment, h, VNode } from "preact";
|
||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
import arrowDown from "../svg/chevron-down.svg";
|
import arrowDown from "../svg/chevron-down.inline.svg";
|
||||||
import { ErrorBox } from "./styled/index.js";
|
import { ErrorBox } from "./styled/index.js";
|
||||||
import { EnabledBySettings } from "./EnabledBySettings.js";
|
import { EnabledBySettings } from "./EnabledBySettings.js";
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ import { css } from "@linaria/core";
|
|||||||
import { Fragment, h, VNode } from "preact";
|
import { Fragment, h, VNode } from "preact";
|
||||||
import { useEffect, useState } from "preact/hooks";
|
import { useEffect, useState } from "preact/hooks";
|
||||||
import { useTranslationContext } from "@gnu-taler/web-util/browser";
|
import { useTranslationContext } from "@gnu-taler/web-util/browser";
|
||||||
import ProgressIcon from "../svg/progress.svg";
|
import ProgressIcon from "../svg/progress.inline.svg";
|
||||||
import { CenteredText } from "./styled/index.js";
|
import { CenteredText } from "./styled/index.js";
|
||||||
|
|
||||||
const fadeIn = css`
|
const fadeIn = css`
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { h, VNode } from "preact";
|
import { h, VNode } from "preact";
|
||||||
import logo from "../svg/logo-2021.svg";
|
import logo from "../svg/logo-2021.inline.svg";
|
||||||
|
|
||||||
export function LogoHeader(): VNode {
|
export function LogoHeader(): VNode {
|
||||||
return (
|
return (
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
import { styled } from "@linaria/react";
|
import { styled } from "@linaria/react";
|
||||||
import { ComponentChildren, h, VNode } from "preact";
|
import { ComponentChildren, h, VNode } from "preact";
|
||||||
import { ButtonHandler } from "../mui/handlers.js";
|
import { ButtonHandler } from "../mui/handlers.js";
|
||||||
import closeIcon from "../svg/close_24px.svg";
|
import closeIcon from "../svg/close_24px.inline.svg";
|
||||||
import { Link, LinkPrimary, LinkWarning } from "./styled/index.js";
|
import { Link, LinkPrimary, LinkWarning } from "./styled/index.js";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
@ -17,7 +17,7 @@ import { TranslatedString } from "@gnu-taler/taler-util";
|
|||||||
import { h, VNode } from "preact";
|
import { h, VNode } from "preact";
|
||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
import { Button } from "../mui/Button.js";
|
import { Button } from "../mui/Button.js";
|
||||||
import arrowDown from "../svg/chevron-down.svg";
|
import arrowDown from "../svg/chevron-down.inline.svg";
|
||||||
import { ParagraphClickable } from "./styled/index.js";
|
import { ParagraphClickable } from "./styled/index.js";
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
|
@ -96,7 +96,7 @@ const CollasibleBox = styled.div`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
import arrowDown from "../svg/chevron-down.svg";
|
import arrowDown from "../svg/chevron-down.inline.svg";
|
||||||
import { useTranslationContext } from "@gnu-taler/web-util/browser";
|
import { useTranslationContext } from "@gnu-taler/web-util/browser";
|
||||||
|
|
||||||
export function PartCollapsible({ text, title, big, showSign }: Props): VNode {
|
export function PartCollapsible({ text, title, big, showSign }: Props): VNode {
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
// need to import linaria types, otherwise compiler will complain
|
// need to import linaria types, otherwise compiler will complain
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
import type * as Linaria from "@linaria/core";
|
// import type * as Linaria from "@linaria/core";
|
||||||
|
|
||||||
import { styled } from "@linaria/react";
|
import { styled } from "@linaria/react";
|
||||||
|
|
||||||
@ -24,7 +24,7 @@ export const PaymentStatus = styled.div<{ color: string }>`
|
|||||||
padding: 5px;
|
padding: 5px;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
color: white;
|
color: white;
|
||||||
background-color: ${(p) => p.color};
|
background-color: ${(p: any) => p.color};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const WalletAction = styled.div`
|
export const WalletAction = styled.div`
|
||||||
@ -100,7 +100,7 @@ export const WalletBox = styled.div<{ noPadding?: boolean }>`
|
|||||||
width: 800px;
|
width: 800px;
|
||||||
}
|
}
|
||||||
& > section {
|
& > section {
|
||||||
padding: ${({ noPadding }) => (noPadding ? "0px" : "8px")};
|
padding: ${({ noPadding }: any) => (noPadding ? "0px" : "8px")};
|
||||||
|
|
||||||
margin-bottom: auto;
|
margin-bottom: auto;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
@ -168,7 +168,7 @@ export const PopupBox = styled.div<{ noPadding?: boolean }>`
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|
||||||
& > section {
|
& > section {
|
||||||
padding: ${({ noPadding }) => (noPadding ? "0px" : "8px")};
|
padding: ${({ noPadding }: any) => (noPadding ? "0px" : "8px")};
|
||||||
// this margin will send the section up when used with a header
|
// this margin will send the section up when used with a header
|
||||||
margin-bottom: auto;
|
margin-bottom: auto;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
@ -411,7 +411,8 @@ export const Button = styled.button<{ upperCased?: boolean }>`
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
text-transform: ${({ upperCased }) => (upperCased ? "uppercase" : "none")};
|
text-transform: ${({ upperCased }: any) =>
|
||||||
|
upperCased ? "uppercase" : "none"};
|
||||||
|
|
||||||
font-family: inherit;
|
font-family: inherit;
|
||||||
font-size: 100%;
|
font-size: 100%;
|
||||||
@ -461,7 +462,8 @@ export const Link = styled.a<{ upperCased?: boolean }>`
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
text-transform: ${({ upperCased }) => (upperCased ? "uppercase" : "none")};
|
text-transform: ${({ upperCased }: any) =>
|
||||||
|
upperCased ? "uppercase" : "none"};
|
||||||
|
|
||||||
font-family: inherit;
|
font-family: inherit;
|
||||||
font-size: 100%;
|
font-size: 100%;
|
||||||
@ -539,7 +541,7 @@ export const LinkPrimary = styled(Link)`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
export const ButtonPrimary = styled(ButtonVariant)<{ small?: boolean }>`
|
export const ButtonPrimary = styled(ButtonVariant)<{ small?: boolean }>`
|
||||||
font-size: ${({ small }) => (small ? "small" : "inherit")};
|
font-size: ${({ small }: any) => (small ? "small" : "inherit")};
|
||||||
background-color: #0042b2;
|
background-color: #0042b2;
|
||||||
border-color: #0042b2;
|
border-color: #0042b2;
|
||||||
`;
|
`;
|
||||||
@ -717,13 +719,13 @@ export const Input = styled.div<{ invalid?: boolean }>`
|
|||||||
& label {
|
& label {
|
||||||
display: block;
|
display: block;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
color: ${({ invalid }) => (!invalid ? "inherit" : "red")};
|
color: ${({ invalid }: any) => (!invalid ? "inherit" : "red")};
|
||||||
}
|
}
|
||||||
& input {
|
& input {
|
||||||
display: block;
|
display: block;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
width: calc(100% - 4px - 10px);
|
width: calc(100% - 4px - 10px);
|
||||||
border-color: ${({ invalid }) => (!invalid ? "inherit" : "red")};
|
border-color: ${({ invalid }: any) => (!invalid ? "inherit" : "red")};
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@ -735,7 +737,7 @@ export const InputWithLabel = styled.div<{ invalid?: boolean }>`
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
margin-left: 0.5em;
|
margin-left: 0.5em;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
color: ${({ invalid }) => (!invalid ? "inherit" : "red")};
|
color: ${({ invalid }: any) => (!invalid ? "inherit" : "red")};
|
||||||
}
|
}
|
||||||
|
|
||||||
& div {
|
& div {
|
||||||
@ -761,7 +763,7 @@ export const InputWithLabel = styled.div<{ invalid?: boolean }>`
|
|||||||
/* border-color: lightgray; */
|
/* border-color: lightgray; */
|
||||||
border-bottom-right-radius: 0.25em;
|
border-bottom-right-radius: 0.25em;
|
||||||
border-top-right-radius: 0.25em;
|
border-top-right-radius: 0.25em;
|
||||||
border-color: ${({ invalid }) => (!invalid ? "lightgray" : "red")};
|
border-color: ${({ invalid }: any) => (!invalid ? "lightgray" : "red")};
|
||||||
}
|
}
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
`;
|
`;
|
||||||
@ -859,8 +861,8 @@ interface SvgIconProps {
|
|||||||
}
|
}
|
||||||
export const SvgIcon = styled.div<SvgIconProps>`
|
export const SvgIcon = styled.div<SvgIconProps>`
|
||||||
& > svg {
|
& > svg {
|
||||||
fill: ${({ color }) => color};
|
fill: ${({ color }: any) => color};
|
||||||
transform: ${({ transform }) => (transform ? transform : "")};
|
transform: ${({ transform }: any) => (transform ? transform : "")};
|
||||||
}
|
}
|
||||||
/* width: 24px;
|
/* width: 24px;
|
||||||
height: 24px; */
|
height: 24px; */
|
||||||
@ -868,7 +870,7 @@ export const SvgIcon = styled.div<SvgIconProps>`
|
|||||||
margin-right: 8px;
|
margin-right: 8px;
|
||||||
display: inline;
|
display: inline;
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
cursor: ${({ onClick }) => (onClick ? "pointer" : "inherit")};
|
cursor: ${({ onClick }: any) => (onClick ? "pointer" : "inherit")};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const Icon = styled.div`
|
export const Icon = styled.div`
|
||||||
|
@ -27,7 +27,7 @@ import {
|
|||||||
import { useTranslationContext } from "@gnu-taler/web-util/browser";
|
import { useTranslationContext } from "@gnu-taler/web-util/browser";
|
||||||
import { Button } from "../../mui/Button.js";
|
import { Button } from "../../mui/Button.js";
|
||||||
import { TextField } from "../../mui/TextField.js";
|
import { TextField } from "../../mui/TextField.js";
|
||||||
import editIcon from "../../svg/edit_24px.svg";
|
import editIcon from "../../svg/edit_24px.inline.svg";
|
||||||
import {
|
import {
|
||||||
ExchangeDetails,
|
ExchangeDetails,
|
||||||
getAmountWithFee,
|
getAmountWithFee,
|
||||||
|
@ -25,7 +25,7 @@ import { Input, LinkSuccess, SvgIcon } from "../../components/styled/index.js";
|
|||||||
import { TermsOfService } from "../../components/TermsOfService/index.js";
|
import { TermsOfService } from "../../components/TermsOfService/index.js";
|
||||||
import { useTranslationContext } from "@gnu-taler/web-util/browser";
|
import { useTranslationContext } from "@gnu-taler/web-util/browser";
|
||||||
import { Button } from "../../mui/Button.js";
|
import { Button } from "../../mui/Button.js";
|
||||||
import editIcon from "../../svg/edit_24px.svg";
|
import editIcon from "../../svg/edit_24px.inline.svg";
|
||||||
import {
|
import {
|
||||||
ExchangeDetails,
|
ExchangeDetails,
|
||||||
getAmountWithFee,
|
getAmountWithFee,
|
||||||
|
@ -17,11 +17,11 @@ import { TranslatedString } from "@gnu-taler/taler-util";
|
|||||||
import { css } from "@linaria/core";
|
import { css } from "@linaria/core";
|
||||||
import { ComponentChildren, h, VNode } from "preact";
|
import { ComponentChildren, h, VNode } from "preact";
|
||||||
// eslint-disable-next-line import/extensions
|
// eslint-disable-next-line import/extensions
|
||||||
import CloseIcon from "../svg/close_24px.svg";
|
import CloseIcon from "../svg/close_24px.inline.svg";
|
||||||
import ErrorOutlineIcon from "../svg/error_outline_outlined_24px.svg";
|
import ErrorOutlineIcon from "../svg/error_outline_outlined_24px.inline.svg";
|
||||||
import InfoOutlinedIcon from "../svg/info_outlined_24px.svg";
|
import InfoOutlinedIcon from "../svg/info_outlined_24px.inline.svg";
|
||||||
import ReportProblemOutlinedIcon from "../svg/report_problem_outlined_24px.svg";
|
import ReportProblemOutlinedIcon from "../svg/report_problem_outlined_24px.inline.svg";
|
||||||
import SuccessOutlinedIcon from "../svg/success_outlined_24px.svg";
|
import SuccessOutlinedIcon from "../svg/success_outlined_24px.inline.svg";
|
||||||
import { IconButton } from "./Button.js";
|
import { IconButton } from "./Button.js";
|
||||||
import { darken, lighten } from "./colors/manipulation.js";
|
import { darken, lighten } from "./colors/manipulation.js";
|
||||||
import { Paper } from "./Paper.js";
|
import { Paper } from "./Paper.js";
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
|
|
||||||
import { Button } from "./Button.js";
|
import { Button } from "./Button.js";
|
||||||
import { Fragment, h, VNode } from "preact";
|
import { Fragment, h, VNode } from "preact";
|
||||||
import DeleteIcon from "../svg/delete_24px.svg";
|
import DeleteIcon from "../svg/delete_24px.inline.svg";
|
||||||
import SendIcon from "../svg/send_24px.svg";
|
import SendIcon from "../svg/send_24px.inline.svg";
|
||||||
import { styled } from "@linaria/react";
|
import { styled } from "@linaria/react";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
import { css } from "@linaria/core";
|
import { css } from "@linaria/core";
|
||||||
import { h, VNode } from "preact";
|
import { h, VNode } from "preact";
|
||||||
// eslint-disable-next-line import/extensions
|
|
||||||
import { Colors, theme } from "../style.js";
|
import { Colors, theme } from "../style.js";
|
||||||
import { useFormControl } from "./FormControl.js";
|
import { useFormControl } from "./FormControl.js";
|
||||||
import { InputBase, InputBaseComponent, InputBaseRoot } from "./InputBase.js";
|
import { InputBase, InputBaseComponent, InputBaseRoot } from "./InputBase.js";
|
||||||
|
@ -56,8 +56,6 @@ export interface Spacing {
|
|||||||
(top: number, right: number, bottom: number, left: number): string;
|
(top: number, right: number, bottom: number, left: number): string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const theme = createTheme();
|
|
||||||
|
|
||||||
const zIndex = {
|
const zIndex = {
|
||||||
mobileStepper: 1000,
|
mobileStepper: 1000,
|
||||||
speedDial: 1050,
|
speedDial: 1050,
|
||||||
@ -68,6 +66,8 @@ const zIndex = {
|
|||||||
tooltip: 1500,
|
tooltip: 1500,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const theme = createTheme();
|
||||||
|
|
||||||
export const ripple = css`
|
export const ripple = css`
|
||||||
background-position: center;
|
background-position: center;
|
||||||
|
|
||||||
|
Before Width: | Height: | Size: 187 B After Width: | Height: | Size: 187 B |
Before Width: | Height: | Size: 556 B After Width: | Height: | Size: 556 B |
Before Width: | Height: | Size: 248 B After Width: | Height: | Size: 248 B |
Before Width: | Height: | Size: 201 B After Width: | Height: | Size: 201 B |
Before Width: | Height: | Size: 235 B After Width: | Height: | Size: 235 B |
Before Width: | Height: | Size: 287 B After Width: | Height: | Size: 287 B |
Before Width: | Height: | Size: 278 B After Width: | Height: | Size: 278 B |
Before Width: | Height: | Size: 297 B After Width: | Height: | Size: 297 B |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 650 B After Width: | Height: | Size: 650 B |
Before Width: | Height: | Size: 229 B After Width: | Height: | Size: 229 B |
Before Width: | Height: | Size: 297 B After Width: | Height: | Size: 297 B |
Before Width: | Height: | Size: 161 B After Width: | Height: | Size: 161 B |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 382 B After Width: | Height: | Size: 382 B |
Before Width: | Height: | Size: 236 B After Width: | Height: | Size: 236 B |
Before Width: | Height: | Size: 188 B After Width: | Height: | Size: 188 B |
Before Width: | Height: | Size: 348 B After Width: | Height: | Size: 348 B |
@ -66,7 +66,7 @@ import {
|
|||||||
} from "../cta/Withdraw/index.js";
|
} from "../cta/Withdraw/index.js";
|
||||||
import { strings } from "../i18n/strings.js";
|
import { strings } from "../i18n/strings.js";
|
||||||
import { platform } from "../platform/foreground.js";
|
import { platform } from "../platform/foreground.js";
|
||||||
import CloseIcon from "../svg/close_24px.svg";
|
import CloseIcon from "../svg/close_24px.inline.svg";
|
||||||
import { AddBackupProviderPage } from "./AddBackupProvider/index.js";
|
import { AddBackupProviderPage } from "./AddBackupProvider/index.js";
|
||||||
import { BackupPage } from "./BackupPage.js";
|
import { BackupPage } from "./BackupPage.js";
|
||||||
import { DepositPage } from "./DepositPage/index.js";
|
import { DepositPage } from "./DepositPage/index.js";
|
||||||
|
@ -30,8 +30,8 @@ import { Button } from "../../mui/Button.js";
|
|||||||
import { Grid } from "../../mui/Grid.js";
|
import { Grid } from "../../mui/Grid.js";
|
||||||
import { Paper } from "../../mui/Paper.js";
|
import { Paper } from "../../mui/Paper.js";
|
||||||
import { Pages } from "../../NavigationBar.js";
|
import { Pages } from "../../NavigationBar.js";
|
||||||
import arrowIcon from "../../svg/chevron-down.svg";
|
import arrowIcon from "../../svg/chevron-down.inline.svg";
|
||||||
import bankIcon from "../../svg/ri-bank-line.svg";
|
import bankIcon from "../../svg/ri-bank-line.inline.svg";
|
||||||
import { assertUnreachable } from "../../utils/index.js";
|
import { assertUnreachable } from "../../utils/index.js";
|
||||||
import { Contact, State } from "./index.js";
|
import { Contact, State } from "./index.js";
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ import { Time } from "../../components/Time.js";
|
|||||||
import { useTranslationContext } from "@gnu-taler/web-util/browser";
|
import { useTranslationContext } from "@gnu-taler/web-util/browser";
|
||||||
import { State as SelectExchangeState } from "../../hooks/useSelectedExchange.js";
|
import { State as SelectExchangeState } from "../../hooks/useSelectedExchange.js";
|
||||||
import { Button } from "../../mui/Button.js";
|
import { Button } from "../../mui/Button.js";
|
||||||
import arrowDown from "../../svg/chevron-down.svg";
|
import arrowDown from "../../svg/chevron-down.inline.svg";
|
||||||
import { State } from "./index.js";
|
import { State } from "./index.js";
|
||||||
|
|
||||||
const ButtonGroup = styled.div`
|
const ButtonGroup = styled.div`
|
||||||
|
@ -40,8 +40,8 @@ import { useTranslationContext } from "@gnu-taler/web-util/browser";
|
|||||||
import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
|
import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
|
||||||
import { Button } from "../mui/Button.js";
|
import { Button } from "../mui/Button.js";
|
||||||
import { NoBalanceHelp } from "../popup/NoBalanceHelp.js";
|
import { NoBalanceHelp } from "../popup/NoBalanceHelp.js";
|
||||||
import DownloadIcon from "../svg/download_24px.svg";
|
import DownloadIcon from "../svg/download_24px.inline.svg";
|
||||||
import UploadIcon from "../svg/upload_24px.svg";
|
import UploadIcon from "../svg/upload_24px.inline.svg";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
currency?: string;
|
currency?: string;
|
||||||
@ -262,7 +262,9 @@ export function HistoryView({
|
|||||||
<Fragment key={i}>
|
<Fragment key={i}>
|
||||||
<DateSeparator>
|
<DateSeparator>
|
||||||
<Time
|
<Time
|
||||||
timestamp={AbsoluteTime.fromMilliseconds(Number.parseInt(d, 10))}
|
timestamp={AbsoluteTime.fromMilliseconds(
|
||||||
|
Number.parseInt(d, 10),
|
||||||
|
)}
|
||||||
format="dd MMMM yyyy"
|
format="dd MMMM yyyy"
|
||||||
/>
|
/>
|
||||||
</DateSeparator>
|
</DateSeparator>
|
||||||
|
@ -33,9 +33,9 @@ import { useTranslationContext } from "@gnu-taler/web-util/browser";
|
|||||||
import { Button } from "../../mui/Button.js";
|
import { Button } from "../../mui/Button.js";
|
||||||
import { TextFieldHandler } from "../../mui/handlers.js";
|
import { TextFieldHandler } from "../../mui/handlers.js";
|
||||||
import { TextField } from "../../mui/TextField.js";
|
import { TextField } from "../../mui/TextField.js";
|
||||||
import checkIcon from "../../svg/check_24px.svg";
|
import checkIcon from "../../svg/check_24px.inline.svg";
|
||||||
import deleteIcon from "../../svg/delete_24px.svg";
|
import deleteIcon from "../../svg/delete_24px.inline.svg";
|
||||||
import warningIcon from "../../svg/warning_24px.svg";
|
import warningIcon from "../../svg/warning_24px.inline.svg";
|
||||||
import { State } from "./index.js";
|
import { State } from "./index.js";
|
||||||
|
|
||||||
type AccountType = "bitcoin" | "x-taler-bank" | "iban";
|
type AccountType = "bitcoin" | "x-taler-bank" | "iban";
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
|
<title>GNU Taler Wallet - WebExtension</title>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<link rel="stylesheet" type="text/css" href="/dist/walletEntryPoint.css" />
|
<link rel="stylesheet" type="text/css" href="/dist/walletEntryPoint.css" />
|
||||||
<link rel="stylesheet" type="text/css" href="/static/font/import.css" />
|
<link rel="stylesheet" type="text/css" href="/static/font/import.css" />
|
||||||
|
44
packages/taler-wallet-webextension/test.mjs
Executable file
@ -0,0 +1,44 @@
|
|||||||
|
#!/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 { build, getFilesInDirectory } from "@gnu-taler/web-util/build";
|
||||||
|
|
||||||
|
const allTestFiles = getFilesInDirectory("src", /.test.tsx?$/);
|
||||||
|
const allStaticFiles = getFilesInDirectory("static");
|
||||||
|
|
||||||
|
await build({
|
||||||
|
source: {
|
||||||
|
js: allTestFiles,
|
||||||
|
assets: allStaticFiles,
|
||||||
|
},
|
||||||
|
destination: "./dist/test",
|
||||||
|
css: "linaria",
|
||||||
|
linariaPlugin: () => {
|
||||||
|
// linaria has a bug if this run in web-util library
|
||||||
|
return linaria({
|
||||||
|
babelOptions: {
|
||||||
|
presets: [
|
||||||
|
"@babel/preset-typescript",
|
||||||
|
"@babel/preset-react",
|
||||||
|
"@linaria",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
sourceMap: true,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|