[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[taler-typescript-core] branch master updated (0c95d00a5 -> 6bada2347)
From: |
Admin |
Subject: |
[taler-typescript-core] branch master updated (0c95d00a5 -> 6bada2347) |
Date: |
Mon, 09 Jun 2025 17:12:52 +0200 |
This is an automated email from the git hooks/post-receive script.
sebasjm pushed a change to branch master
in repository taler-typescript-core.
from 0c95d00a5 Translated using Weblate (German)
new 07d0ae31b fix #9810
new 6bada2347 fix url on stories, it was breaking unit test
The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
.../aml-backoffice-ui/src/ExchangeAmlFrame.tsx | 10 +-
.../src/hooks/decision-request.ts | 2 +-
.../aml-backoffice-ui/src/pages/CaseDetails.tsx | 83 ++++------
.../aml-backoffice-ui/src/pages/MeasuresTable.tsx | 87 +++++++++--
.../aml-backoffice-ui/src/pages/NewMeasure.tsx | 11 +-
packages/aml-backoffice-ui/src/pages/Transfers.tsx | 4 +-
.../src/pages/decision/Measures.tsx | 170 +++++++++++++++++----
.../src/pages/decision/Summary.tsx | 47 ++++--
packages/aml-backoffice-ui/src/utils/QR.tsx | 54 -------
packages/taler-util/src/aml/events.ts | 3 +-
packages/taler-util/src/aml/properties.ts | 5 +-
packages/taler-util/src/types-taler-exchange.ts | 2 +-
packages/taler-util/src/types-taler-kyc-aml.ts | 148 +-----------------
.../src/wallet/History.stories.tsx | 84 ++++++----
packages/web-util/src/components/Attention.tsx | 4 +-
packages/web-util/src/components/Button.tsx | 4 +-
packages/web-util/src/components/Header.tsx | 3 +-
packages/web-util/src/components/Loading.tsx | 2 +-
.../src/components/ShowInputErrorLabel.tsx | 2 +-
19 files changed, 368 insertions(+), 357 deletions(-)
delete mode 100644 packages/aml-backoffice-ui/src/utils/QR.tsx
diff --git a/packages/aml-backoffice-ui/src/ExchangeAmlFrame.tsx
b/packages/aml-backoffice-ui/src/ExchangeAmlFrame.tsx
index 6e2cce6fb..d8d7b8e8f 100644
--- a/packages/aml-backoffice-ui/src/ExchangeAmlFrame.tsx
+++ b/packages/aml-backoffice-ui/src/ExchangeAmlFrame.tsx
@@ -148,10 +148,7 @@ export function ExchangeAmlFrame({
const settings = useUiSettingsContext();
return (
- <div
- class="min-h-full flex flex-col m-0 bg-slate-200"
- style="min-height: 100vh;"
- >
+ <div class="min-h-full flex flex-col m-0 bg-slate-200 min-h-screen">
<div class="bg-indigo-600 pb-32">
<Header
title="Exchange"
@@ -219,10 +216,7 @@ export function ExchangeAmlFrame({
<div class="-mt-32 flex grow ">
{officer?.state !== "ready" ? undefined : <Navigation />}
<div class="flex mx-auto my-4 min-w-80">
- <main
- class="block rounded-lg bg-white px-5 py-6 shadow "
- style={{ minWidth: 600 }}
- >
+ <main class="block rounded-lg bg-white px-5 py-6 shadow min-w-xl">
{children}
</main>
</div>
diff --git a/packages/aml-backoffice-ui/src/hooks/decision-request.ts
b/packages/aml-backoffice-ui/src/hooks/decision-request.ts
index ba07863ef..c3753a1fc 100644
--- a/packages/aml-backoffice-ui/src/hooks/decision-request.ts
+++ b/packages/aml-backoffice-ui/src/hooks/decision-request.ts
@@ -115,7 +115,7 @@ export interface DecisionRequest {
export const codecForMeasure = (): Codec<MeasureInformation> =>
buildCodecForObject<MeasureInformation>()
.property("check_name", codecOptionalDefault(codecForString(), "SKIP"))
- .property("prog_name", codecForString())
+ .property("prog_name", codecOptional(codecForString()))
.property("context", codecOptional(codecForMap(codecForAny())))
.build("MeasureInformation");
diff --git a/packages/aml-backoffice-ui/src/pages/CaseDetails.tsx
b/packages/aml-backoffice-ui/src/pages/CaseDetails.tsx
index 990da4fe0..02b0da523 100644
--- a/packages/aml-backoffice-ui/src/pages/CaseDetails.tsx
+++ b/packages/aml-backoffice-ui/src/pages/CaseDetails.tsx
@@ -1255,10 +1255,7 @@ export function ShowMeasuresToSelect({
return (
<CurrentMeasureTable
- measures={computeAvailableMesaures(
- measures.body,
- // , cm
- )}
+ measures={computeAvailableMesaures(measures.body)}
onSelect={onSelect}
/>
);
@@ -1269,26 +1266,45 @@ export function computeAvailableMesaures(
// customMeasures?: Readonly<CustomMeasures>,
skpiFilter?: (m: MeasureInfo) => boolean,
): Mesaures {
- const init: Mesaures = { forms: [], procedures: [] };
+ const init: Mesaures = { forms: [], procedures: [], info: [] };
if (!serverMeasures) {
return init;
}
const server = Object.entries(serverMeasures.roots).reduce(
(prev, [key, value]) => {
if (value.check_name !== "SKIP") {
- const r: MeasureInfo = {
- type: "form",
- name: key,
- context: value.context,
- programName: value.prog_name,
- program: serverMeasures.programs[value.prog_name],
- checkName: value.check_name,
- check: serverMeasures.checks[value.check_name],
- custom: false,
- };
- if (skpiFilter && skpiFilter(r)) return prev; // skip
- prev.forms.push(r);
+ if (!value.prog_name) {
+ const r: MeasureInfo = {
+ type: "info",
+ name: key,
+ context: value.context,
+ checkName: value.check_name,
+ check: serverMeasures.checks[value.check_name],
+ custom: true,
+ };
+ if (skpiFilter && skpiFilter(r)) return prev; // skip
+ prev.info.push(r);
+ } else {
+ const r: MeasureInfo = {
+ type: "form",
+ name: key,
+ context: value.context,
+ programName: value.prog_name,
+ program: serverMeasures.programs[value.prog_name],
+ checkName: value.check_name,
+ check: serverMeasures.checks[value.check_name],
+ custom: false,
+ };
+ if (skpiFilter && skpiFilter(r)) return prev; // skip
+ prev.forms.push(r);
+ }
} else {
+ if (!value.prog_name) {
+ console.error(
+ `ERROR: program name can't be empty for measure "${key}"`,
+ );
+ return prev;
+ }
const r: MeasureInfo = {
type: "procedure",
name: key,
@@ -1306,37 +1322,4 @@ export function computeAvailableMesaures(
);
return server;
- // if (!customMeasures) {
- // }
-
- // const serverAndCustom = customMeasures.measures.reduce((prev, value) => {
- // if (value.check_name !== "SKIP") {
- // const r: MeasureInfo = {
- // type: "form",
- // name: value.name,
- // context: value.context,
- // programName: value.program,
- // program: serverMeasures.programs[value.program],
- // checkName: value.check_name,
- // check: serverMeasures.checks[value.check_name],
- // custom: true,
- // };
- // if (skpiFilter && skpiFilter(r)) return prev; // skip
- // prev.forms.push(r);
- // } else {
- // const r: MeasureInfo = {
- // type: "procedure",
- // name: value.name,
- // context: value.context,
- // programName: value.program,
- // program: serverMeasures.programs[value.program],
- // custom: true,
- // };
- // if (skpiFilter && skpiFilter(r)) return prev; // skip
- // prev.procedures.push(r);
- // }
- // return prev;
- // }, server);
-
- // return serverAndCustom;
}
diff --git a/packages/aml-backoffice-ui/src/pages/MeasuresTable.tsx
b/packages/aml-backoffice-ui/src/pages/MeasuresTable.tsx
index fcd6ab603..c062a31bb 100644
--- a/packages/aml-backoffice-ui/src/pages/MeasuresTable.tsx
+++ b/packages/aml-backoffice-ui/src/pages/MeasuresTable.tsx
@@ -33,9 +33,9 @@ export type ProcedureMeasure = {
export type FormMeasure = {
type: "form";
name: string;
- programName: string;
+ programName?: string;
+ program?: AmlProgramRequirement;
checkName: string;
- program: AmlProgramRequirement;
check: KycCheckInformation;
context?: object;
custom: boolean;
@@ -43,12 +43,15 @@ export type FormMeasure = {
export type InfoMeasure = {
type: "info";
name: string;
+ checkName: string;
+ check: KycCheckInformation;
context?: object;
custom: boolean;
};
export type Mesaures = {
procedures: ProcedureMeasure[];
forms: FormMeasure[];
+ info: InfoMeasure[];
};
export function CurrentMeasureTable({
measures,
@@ -149,6 +152,79 @@ export function CurrentMeasureTable({
</div>
)}
+ {!measures.info.length ? undefined : (
+ <div class="mt-4 flow-root">
+ <div class="sm:flex sm:items-center">
+ <div class="sm:flex-auto">
+ <h1 class="text-base font-semibold text-gray-900">
+ <i18n.Translate>Info</i18n.Translate>
+ </h1>
+ <p class="mt-2 text-sm text-gray-700">
+ <i18n.Translate>
+ Will show a label or information to the user until a new
state.
+ </i18n.Translate>
+ </p>
+ </div>
+ </div>
+
+ <div class="inline-block min-w-full py-2 align-middle sm:px-6
lg:px-8">
+ <div class="overflow-hidden shadow ring-1 ring-black/5
sm:rounded-lg">
+ <table class="min-w-full divide-y divide-gray-300">
+ <thead class="bg-gray-50">
+ <tr>
+ {onSelect ? (
+ <th scope="col" class="relative p-2 ">
+ <span class="sr-only">Select</span>
+ </th>
+ ) : (
+ <Fragment />
+ )}
+ <th
+ scope="col"
+ class="p-2 text-left text-sm font-semibold text-gray-900
sm:pl-6"
+ >
+ <i18n.Translate>Name</i18n.Translate>
+ </th>
+ <th
+ scope="col"
+ class="p-2 text-left text-sm font-semibold text-gray-900"
+ >
+ <i18n.Translate>Context</i18n.Translate>
+ </th>
+ </tr>
+ </thead>
+ <tbody class="divide-y divide-gray-200 bg-white">
+ {measures.info.map((m) => {
+ return (
+ <tr>
+ {onSelect ? (
+ <td class="relative whitespace-nowrap p-2 text-right
text-sm font-medium ">
+ <button
+ onClick={() => onSelect(m)}
+ class="rounded-md w-fit border-0 p-2 text-center
text-sm bg-indigo-700 text-white shadow-sm hover:bg-indigo-700"
+ >
+ <i18n.Translate>Modify</i18n.Translate>
+ </button>
+ </td>
+ ) : (
+ <Fragment />
+ )}
+ <td class="whitespace-nowrap p-2 text-sm font-medium
text-gray-900 sm:pl-6">
+ {m.name}
+ </td>
+ <td class="whitespace-nowrap p-2 text-sm
text-gray-500">
+ {Object.keys(m.context ?? {}).join(", ")}
+ </td>
+ </tr>
+ );
+ })}
+ </tbody>
+ </table>
+ </div>
+ </div>
+ </div>
+ )}
+
{!measures.procedures.length ? undefined : (
<div class="mt-4 flow-root">
<div class="sm:flex sm:items-center">
@@ -204,13 +280,6 @@ export function CurrentMeasureTable({
</thead>
<tbody class="divide-y divide-gray-200 bg-white">
{measures.procedures.map((m) => {
- // if (
- // m.context &&
- // "internal" in m.context &&
- // m.context.internal
- // ) {
- // return <Fragment />;
- // }
return (
<tr>
{onSelect ? (
diff --git a/packages/aml-backoffice-ui/src/pages/NewMeasure.tsx
b/packages/aml-backoffice-ui/src/pages/NewMeasure.tsx
index 0fe5140eb..edc8688c3 100644
--- a/packages/aml-backoffice-ui/src/pages/NewMeasure.tsx
+++ b/packages/aml-backoffice-ui/src/pages/NewMeasure.tsx
@@ -7,6 +7,7 @@ import {
TranslatedString,
} from "@gnu-taler/taler-util";
import {
+ ErrorsSummary,
FormDesign,
FormUI,
InternationalizationAPI,
@@ -217,7 +218,7 @@ export function MeasureForm({
custom_measures: CURRENT_MEASURES,
});
if (onChanged) {
- onChanged(newMeasure.name)
+ onChanged(newMeasure.name);
}
}}
class="m-4 rounded-md w-fit border-0 px-3 py-2 text-center
text-sm bg-indigo-700 text-white shadow-sm hover:bg-indigo-700
disabled:bg-gray-600"
@@ -232,7 +233,7 @@ export function MeasureForm({
custom_measures: currentMeasures,
});
if (onRemoved) {
- onRemoved(name!)
+ onRemoved(name!);
}
}}
class="m-4 rounded-md w-fit border-0 px-3 py-2 text-center
text-sm bg-indigo-700 text-white shadow-sm hover:bg-indigo-700
disabled:bg-gray-600"
@@ -387,7 +388,6 @@ const formDesign = (
{
type: "selectOne",
id: "program",
- required: true,
label: i18n.str`Program`,
choices: programs.map((m) => {
return {
@@ -395,9 +395,12 @@ const formDesign = (
label: m.key,
};
}),
+ help: i18n.str`Only required when no check is specified`,
validator(value, form) {
return !value
- ? i18n.str`required`
+ ? !form.check
+ ? i18n.str`Missing check or program`
+ : undefined
: programAndCheckMatch(i18n, summary, value, form.check) ??
programAndContextMatch(i18n, summary, value, form.context);
},
diff --git a/packages/aml-backoffice-ui/src/pages/Transfers.tsx
b/packages/aml-backoffice-ui/src/pages/Transfers.tsx
index 7215f9312..a7770e364 100644
--- a/packages/aml-backoffice-ui/src/pages/Transfers.tsx
+++ b/packages/aml-backoffice-ui/src/pages/Transfers.tsx
@@ -260,7 +260,7 @@ export function Transfers({
/>
</span>
) : (
- <span style={{ color: "grey" }}>
+ <span class="text-grey-500">
<{i18n.str`Invalid value`}>
</span>
)}
@@ -299,7 +299,7 @@ export function Transfers({
spec={config.config.currency_specification}
/>
) : (
- <span style={{ color: "grey" }}>
+ <span class="text-grey-500">
<
{i18n.str`Invalid value`}>
</span>
diff --git a/packages/aml-backoffice-ui/src/pages/decision/Measures.tsx
b/packages/aml-backoffice-ui/src/pages/decision/Measures.tsx
index e52f01192..3d503ee55 100644
--- a/packages/aml-backoffice-ui/src/pages/decision/Measures.tsx
+++ b/packages/aml-backoffice-ui/src/pages/decision/Measures.tsx
@@ -1,4 +1,5 @@
import {
+ assertUnreachable,
MeasureInformation,
TalerError,
TalerExchangeApi,
@@ -95,13 +96,51 @@ function ActiveMeasureForm(): VNode {
? undefined
: measures.body;
- const measureList = !measureBody ? [] : Object.keys(measureBody.roots);
- const design = formDesign(i18n, [
+ const measureList = (!measureBody ? [] : Object.keys(measureBody.roots)).map(
+ (m) =>
+ ({
+ type: "normal",
+ name: m,
+ }) satisfies NormalMeasure,
+ );
+
+ const requestCustomMeasures = request?.custom_measures ?? {}
+ const customMeasures = Object.keys(requestCustomMeasures).map(
+ (m) =>
+ ({
+ type: "normal",
+ name: m,
+ }) satisfies NormalMeasure,
+ );
+
+ const checkList = !measureBody ? [] : Object.entries(measureBody.checks);
+ const simpleChecks = checkList
+ .filter(
+ ([, check]) => check.outputs.length > 0 && check.requires.length > 0,
+ )
+ .map(
+ ([key]) =>
+ ({
+ type: "simple-check-form",
+ checkName: key,
+ }) satisfies SimpleCheckMeasure,
+ );
+
+ const allMeasures: MeasureType[] = [
...measureList,
- ...Object.keys(request?.custom_measures ?? {}),
- ]);
+ ...customMeasures,
+ ...simpleChecks,
+ ];
- const nm = !request.new_measures ? [] : request.new_measures;
+ const design = formDesign(i18n, allMeasures);
+
+ const nm = (!request.new_measures ? [] : request.new_measures).map(
+ (m) =>
+ ({
+ type: "normal",
+ name: m,
+ }) satisfies NormalMeasure,
+ );
const initValue = useMemo<FormType>(
() => ({ measures: nm }),
@@ -110,8 +149,30 @@ function ActiveMeasureForm(): VNode {
const form = useForm<FormType>(design, initValue);
onComponentUnload(() => {
+ const newMeasures: string[] = [];
+ const formMeasures = form.status.result.measures ?? [];
+ for (const m of formMeasures) {
+ switch (m.type) {
+ case "normal": {
+ newMeasures.push(m.name)
+ break;
+ }
+ case "simple-check-form": {
+ const generatedId = `check-${m.checkName}`
+ requestCustomMeasures[generatedId] = {
+ check_name: m.checkName,
+ }
+ newMeasures.push(generatedId)
+ break;
+ }
+ default: {
+ assertUnreachable(m);
+ }
+ }
+ }
updateRequest("unload active measure", {
- new_measures: (form.status.result.measures ?? []) as string[],
+ new_measures: newMeasures,
+ custom_measures: requestCustomMeasures,
});
});
@@ -208,13 +269,35 @@ function ShowAllMeasures({
);
}
+type MeasureType = NormalMeasure | SimpleCheckMeasure;
+
+/**
+ * Normal measures are custom measures or server defined measure.
+ * The name reference some measure already defined
+ */
+type NormalMeasure = {
+ type: "normal";
+ name: string;
+};
+
+/**
+ * Simple check form measure are not yet defined but it should be automatically
+ * added on submission.
+ * This checks requires no context and output no information so it doesn't need
+ * any program.
+ */
+type SimpleCheckMeasure = {
+ type: "simple-check-form";
+ checkName: string;
+};
+
type FormType = {
- measures: string[];
+ measures: MeasureType[];
};
function formDesign(
i18n: InternationalizationAPI,
- measureNames: string[],
+ measureNames: MeasureType[],
): FormDesign<FormType> {
return {
type: "single-column",
@@ -222,12 +305,24 @@ function formDesign(
{
type: "selectMultiple",
unique: true,
- choices: measureNames.map((name) => {
- return {
- value: name,
- label: name,
- };
- }),
+ choices: measureNames.map((me) => {
+ switch (me.type) {
+ case "normal": {
+ return {
+ label: me.name,
+ value: me,
+ };
+ }
+ case "simple-check-form": {
+ return {
+ label: `CHECK: ${me.checkName}`,
+ value: me,
+ };
+ }
+ }
+ // FIXME: choises should allow value to be any type
+ // check: why do we require value to be string?
+ }) as any,
id: "measures",
label: i18n.str`Active measures`,
help: i18n.str`Measures that the customer will need to satisfy while
the rules are active.`,
@@ -241,7 +336,7 @@ function computeAvailableMesauresCustom(
serverMeasures: TalerExchangeApi.AvailableMeasureSummary | undefined,
skpiFilter?: (m: MeasureInfo) => boolean,
): Mesaures {
- const init: Mesaures = { forms: [], procedures: [] };
+ const init: Mesaures = { forms: [], procedures: [], info: [] };
if (!customMeasures || !serverMeasures) {
return init;
@@ -249,19 +344,40 @@ function computeAvailableMesauresCustom(
const custom = Object.entries(customMeasures).reduce((prev, [key, value]) =>
{
if (value.check_name !== "SKIP") {
- const r: MeasureInfo = {
- type: "form",
- name: key,
- context: value.context,
- programName: value.prog_name,
- program: serverMeasures.programs[value.prog_name],
- checkName: value.check_name,
- check: serverMeasures.checks[value.check_name],
- custom: true,
- };
- if (skpiFilter && skpiFilter(r)) return prev; // skip
- prev.forms.push(r);
+ if (!value.prog_name) {
+ const r: MeasureInfo = {
+ type: "info",
+ name: key,
+ context: value.context,
+ checkName: value.check_name,
+ check: serverMeasures.checks[value.check_name],
+ custom: true,
+ };
+ if (skpiFilter && skpiFilter(r)) return prev; // skip
+ prev.info.push(r);
+ } else {
+ const r: MeasureInfo = {
+ type: "form",
+ name: key,
+ context: value.context,
+ programName: value.prog_name,
+ program: value.prog_name
+ ? serverMeasures.programs[value.prog_name]
+ : undefined,
+ checkName: value.check_name,
+ check: serverMeasures.checks[value.check_name],
+ custom: true,
+ };
+ if (skpiFilter && skpiFilter(r)) return prev; // skip
+ prev.forms.push(r);
+ }
} else {
+ if (!value.prog_name) {
+ console.error(
+ `ERROR: program name can't be empty for measure "${key}"`,
+ );
+ return prev;
+ }
const r: MeasureInfo = {
type: "procedure",
name: key,
diff --git a/packages/aml-backoffice-ui/src/pages/decision/Summary.tsx
b/packages/aml-backoffice-ui/src/pages/decision/Summary.tsx
index 96a170615..139da5055 100644
--- a/packages/aml-backoffice-ui/src/pages/decision/Summary.tsx
+++ b/packages/aml-backoffice-ui/src/pages/decision/Summary.tsx
@@ -3,12 +3,13 @@ import {
AmlDecisionRequest,
assertUnreachable,
HttpStatusCode,
+ MeasureInformation,
opFixedSuccess,
parsePaytoUri,
PaytoString,
stringifyPaytoUri,
TalerError,
- TOPS_AmlEventsName
+ TOPS_AmlEventsName,
} from "@gnu-taler/taler-util";
import {
Attention,
@@ -20,13 +21,9 @@ import {
} from "@gnu-taler/web-util/browser";
import { Fragment, h, VNode } from "preact";
import { useState } from "preact/hooks";
-import {
- useCurrentDecisionRequest
-} from "../../hooks/decision-request.js";
+import { useCurrentDecisionRequest } from "../../hooks/decision-request.js";
import { useOfficer } from "../../hooks/officer.js";
-import {
- useServerMeasures
-} from "../../hooks/server-info.js";
+import { useServerMeasures } from "../../hooks/server-info.js";
import {
computeAvailableMesaures,
ShowDecisionLimitInfo,
@@ -73,7 +70,9 @@ export function Summary({
const activeMeasureInfo: Mesaures = {
forms: allMeasures.forms.filter((m) => d.indexOf(m.name) !== -1),
procedures: allMeasures.procedures.filter((m) => d.indexOf(m.name) !== -1),
+ info: allMeasures.info.filter((m) => d.indexOf(m.name) !== -1),
};
+ // preserve-investigate
const { lib } = useExchangeApiContext();
@@ -135,7 +134,9 @@ export function Summary({
),
rules: decision.rules!,
successor_measure: decision.onExpire_measure,
- custom_measures: decision.custom_measures ?? {},
+ custom_measures: workaround_defaultProgramName(
+ decision.custom_measures ?? {},
+ ),
},
attributes_expiration: decision.attributes?.expiration
? AbsoluteTime.toProtocolTimestamp(
@@ -192,10 +193,7 @@ export function Summary({
if (submitConfirmation) {
return (
<div class="flex">
- <div
- class="overflow-hidden rounded-lg bg-white shadow-lg"
- style={{ width: 600, marign: "auto" }}
- >
+ <div class="overflow-hidden rounded-lg bg-white shadow-lg w-500 w-64
m-auto">
<div class="px-4 py-5 sm:p-6">
<Attention type="warning" title={i18n.str`Confirmation required`}>
<i18n.Translate>
@@ -230,7 +228,7 @@ export function Summary({
return (
<Fragment>
- <LocalNotificationBanner notification={notification} />
+ {/* <LocalNotificationBanner notification={notification} /> */}
{INVALID_RULES ? (
<Fragment>
@@ -367,3 +365,26 @@ export function Summary({
</Fragment>
);
}
+/**
+ * FIXME: this should be removed when the server allows null programs
+ * or we define a no-operation program
+ *
+ * https://bugs.gnunet.org/view.php?id=9810
+ * https://bugs.gnunet.org/view.php?id=9874
+ *
+ * @param measures
+ * @returns
+ */
+export function workaround_defaultProgramName(
+ measures: Record<string, MeasureInformation>,
+) {
+ const ms = Object.keys(measures);
+ for (const name of ms) {
+ const m = measures[name];
+ if (!m.prog_name) {
+ measures[name].prog_name = "preserve-investigate";
+ }
+ }
+ return measures;
+}
+
diff --git a/packages/aml-backoffice-ui/src/utils/QR.tsx
b/packages/aml-backoffice-ui/src/utils/QR.tsx
deleted file mode 100644
index b382348a3..000000000
--- a/packages/aml-backoffice-ui/src/utils/QR.tsx
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 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 { h, VNode } from "preact";
-import { useEffect, useRef } from "preact/hooks";
-// import qrcode from "qrcode-generator";
-
-export function QR({ text }: { text: string }): VNode {
- const divRef = useRef<HTMLDivElement>(null);
- useEffect(() => {
- // const qr = qrcode(0, "L");
- // qr.addData(text);
- // qr.make();
- // if (divRef.current)
- // divRef.current.innerHTML = qr.createSvgTag({
- // scalable: true,
- // });
- });
-
- return (
- <div
- style={{
- width: "100%",
- display: "flex",
- flexDirection: "column",
- alignItems: "left",
- }}
- >
- <div
- style={{
- width: "50%",
- minWidth: 200,
- maxWidth: 300,
- marginRight: "auto",
- marginLeft: "auto",
- }}
- ref={divRef}
- />
- </div>
- );
-}
diff --git a/packages/taler-util/src/aml/events.ts
b/packages/taler-util/src/aml/events.ts
index 06725556e..67745c521 100644
--- a/packages/taler-util/src/aml/events.ts
+++ b/packages/taler-util/src/aml/events.ts
@@ -1,6 +1,5 @@
import { Amounts } from "../amounts.js";
-import { LimitOperationType } from "../types-taler-exchange.js";
-import { AccountProperties, KycRule } from "../types-taler-kyc-aml.js";
+import { AccountProperties, KycRule, LimitOperationType } from
"../types-taler-exchange.js";
import { TalerAmlProperties } from "../taler-account-properties.js";
import { isOneOf } from "./properties.js";
diff --git a/packages/taler-util/src/aml/properties.ts
b/packages/taler-util/src/aml/properties.ts
index f6de13e6e..53572977d 100644
--- a/packages/taler-util/src/aml/properties.ts
+++ b/packages/taler-util/src/aml/properties.ts
@@ -1,9 +1,6 @@
import { TalerAmlProperties } from "../taler-account-properties.js";
import { TalerFormAttributes } from "../taler-form-attributes.js";
-import {
- AccountProperties,
- LegitimizationRuleSet,
-} from "../types-taler-kyc-aml.js";
+import { AccountProperties, LegitimizationRuleSet } from
"../types-taler-exchange.js";
/**
* List of account properties required by TOPS
diff --git a/packages/taler-util/src/types-taler-exchange.ts
b/packages/taler-util/src/types-taler-exchange.ts
index 03c6d89c5..ef24fac63 100644
--- a/packages/taler-util/src/types-taler-exchange.ts
+++ b/packages/taler-util/src/types-taler-exchange.ts
@@ -1688,7 +1688,7 @@ export interface MeasureInformation {
check_name: string;
// Name of an AML program.
- prog_name: string;
+ prog_name?: string;
// Context for the check. Optional.
context?: Object;
diff --git a/packages/taler-util/src/types-taler-kyc-aml.ts
b/packages/taler-util/src/types-taler-kyc-aml.ts
index 22d024f5e..9ec1ff1c8 100644
--- a/packages/taler-util/src/types-taler-kyc-aml.ts
+++ b/packages/taler-util/src/types-taler-kyc-aml.ts
@@ -15,19 +15,17 @@
*/
import {
+ AccountProperties,
buildCodecForObject,
Codec,
codecForAccountProperties,
codecForAny,
codecForList,
codecOptional,
- LimitOperationType,
+ LegitimizationRuleSet
} from "./index.js";
import {
- AmountString,
- Integer,
- RelativeTime,
- Timestamp,
+ Timestamp
} from "./types-taler-common.js";
//
https://docs.taler.net/taler-kyc-manual.html#implementing-your-own-aml-programs
@@ -215,146 +213,6 @@ export interface AmlOutcome {
new_measures?: string;
}
-// All fields in this object are optional. The actual
-// properties collected depend fully on the discretion
-// of the exchange operator;
-// however, some common fields are standardized
-// and thus described here.
-export interface AccountProperties {
- // True if this is a politically exposed account.
- // Rules for classifying accounts as politically
- // exposed are country-dependent.
- pep?: boolean;
-
- // True if this is a sanctioned account.
- // Rules for classifying accounts as sanctioned
- // are country-dependent.
- sanctioned?: boolean;
-
- // True if this is a high-risk account.
- // Rules for classifying accounts as at-risk
- // are exchange operator-dependent.
- high_risk?: boolean;
-
- // Business domain of the account owner.
- // The list of possible business domains is
- // operator- or country-dependent.
- business_domain?: string;
-
- // Is the client's account currently frozen?
- is_frozen?: boolean;
-
- // Was the client's account reported to the authorities?
- was_reported?: boolean;
-
- [key: string]: string | boolean | number | undefined;
-}
-
-export interface LegitimizationRuleSet {
- // When does this set of rules expire and
- // we automatically transition to the successor
- // measure?
- expiration_time: Timestamp;
-
- // Name of the measure to apply when the expiration time is
- // reached. If not set, we refer to the default
- // set of rules (and the default account state).
- successor_measure?: string;
-
- // Legitimization rules that are to be applied
- // to this account.
- rules: KycRule[];
-
- // Custom measures that KYC rules and the
- // successor_measure may refer to.
- custom_measures: { [measure: string]: MeasureInformation };
-}
-
-export interface KycRule {
- // Type of operation to which the rule applies.
- //
- // Must be one of "WITHDRAW", "DEPOSIT",
- // (p2p) "MERGE", (wallet) "BALANCE",
- // (reserve) "CLOSE", "AGGREGATE",
- // "TRANSACTION" or "REFUND".
- operation_type: LimitOperationType;
-
- // Name of the configuration section this rule
- // originates from. Not available for all rules.
- // Primarily informational, but also useful to
- // explicitly manipulate rules by-name in AML programs.
- rule_name?: string;
-
- // The measures will be taken if the given
- // threshold is crossed over the given timeframe.
- threshold: AmountString;
-
- // Over which duration should the threshold be
- // computed. All amounts of the respective
- // operation_type will be added up for this
- // duration and the sum compared to the threshold.
- timeframe: RelativeTime;
-
- // Array of names of measures to apply.
- // Names listed can be original measures or
- // custom measures from the AmlOutcome.
- // A special measure "verboten" is used if the
- // threshold may never be crossed.
- measures: string[];
-
- // If multiple rules apply to the same account
- // at the same time, the number with the highest
- // rule determines which set of measures will
- // be activated and thus become visible for the
- // user.
- display_priority: Integer;
-
- // True if the rule (specifically, operation_type,
- // threshold, timeframe) and the general nature of
- // the measures (verboten or approval required)
- // should be exposed to the client.
- // Defaults to "false" if not set.
- exposed?: boolean;
-
- // True if all the measures will eventually need to
- // be satisfied, false if any of the measures should
- // do. Primarily used by the SPA to indicate how
- // the measures apply when showing them to the user;
- // in the end, AML programs will decide after each
- // measure what to do next.
- // Default (if missing) is false.
- is_and_combinator?: boolean;
-}
-
-export interface MeasureInformation {
- // Name of a KYC check.
- check_name: string;
-
- // Name of an AML program.
- prog_name: string;
-
- // Context for the check. Optional.
- context?: Object;
-
- // Operation that this measure relates to.
- // NULL if unknown. Useful as a hint to the
- // user if there are many (voluntary) measures
- // and some related to unlocking certain operations.
- // (and due to zero-amount thresholds, no measure
- // was actually specifically triggered).
- //
- // Must be one of "WITHDRAW", "DEPOSIT",
- // (p2p) "MERGE", (wallet) "BALANCE",
- // (reserve) "CLOSE", "AGGREGATE",
- // "TRANSACTION" or "REFUND".
- // New in protocol **v21**.
- operation_type?: LimitOperationType;
-
- // Can this measure be undertaken voluntarily?
- // Optional, default is false.
- // Since protocol **vATTEST**.
- voluntary?: boolean;
-}
export const codecForAmlProgramInput = (): Codec<AmlProgramInput> =>
buildCodecForObject<AmlProgramInput>()
diff --git a/packages/taler-wallet-webextension/src/wallet/History.stories.tsx
b/packages/taler-wallet-webextension/src/wallet/History.stories.tsx
index 059471b9e..511160ff1 100644
--- a/packages/taler-wallet-webextension/src/wallet/History.stories.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/History.stories.tsx
@@ -171,7 +171,7 @@ export const SomeBalanceWithNoTransactions =
tests.createExample(
scope: {
currency: "Ásd",
type: ScopeType.Auditor,
- url: "",
+ url: "http://auditor.taler.ar",
},
balances: [
{
@@ -184,7 +184,7 @@ export const SomeBalanceWithNoTransactions =
tests.createExample(
scopeInfo: {
currency: "Ásd",
type: ScopeType.Auditor,
- url: "",
+ url: "http://auditor.taler.ar",
},
},
],
@@ -198,7 +198,7 @@ export const OneSimpleTransaction =
tests.createExample(TestedComponent, {
scope: {
currency: "Ásd",
type: ScopeType.Auditor,
- url: "",
+ url: "http://auditor.taler.ar",
},
balances: [
{
@@ -211,7 +211,8 @@ export const OneSimpleTransaction =
tests.createExample(TestedComponent, {
scopeInfo: {
currency: "Ásd",
type: ScopeType.Auditor,
- url: "",
+ url: "http://auditor.taler.ar",
+
},
},
],
@@ -226,7 +227,8 @@ export const TwoTransactionsAndZeroBalance =
tests.createExample(
scope: {
currency: "Ásd",
type: ScopeType.Auditor,
- url: "",
+ url: "http://auditor.taler.ar",
+
},
balances: [
{
@@ -239,7 +241,8 @@ export const TwoTransactionsAndZeroBalance =
tests.createExample(
scopeInfo: {
currency: "Ásd",
type: ScopeType.Auditor,
- url: "",
+ url: "http://auditor.taler.ar",
+
},
},
],
@@ -260,7 +263,8 @@ export const OneTransactionPending =
tests.createExample(TestedComponent, {
scope: {
currency: "Ásd",
type: ScopeType.Auditor,
- url: "",
+ url: "http://auditor.taler.ar",
+
},
balances: [
{
@@ -273,7 +277,8 @@ export const OneTransactionPending =
tests.createExample(TestedComponent, {
scopeInfo: {
currency: "Ásd",
type: ScopeType.Auditor,
- url: "",
+ url: "http://auditor.taler.ar",
+
},
},
],
@@ -301,7 +306,8 @@ export const SomeTransactions =
tests.createExample(TestedComponent, {
scope: {
currency: "Ásd",
type: ScopeType.Auditor,
- url: "",
+ url: "http://auditor.taler.ar",
+
},
balances: [
{
@@ -314,7 +320,8 @@ export const SomeTransactions =
tests.createExample(TestedComponent, {
scopeInfo: {
currency: "Ásd",
type: ScopeType.Auditor,
- url: "",
+ url: "http://auditor.taler.ar",
+
},
},
],
@@ -401,7 +408,8 @@ export const SomeTransactionsInDifferentStates =
tests.createExample(
scope: {
currency: "Ásd",
type: ScopeType.Auditor,
- url: "",
+ url: "http://auditor.taler.ar",
+
},
balances: [
{
@@ -414,7 +422,8 @@ export const SomeTransactionsInDifferentStates =
tests.createExample(
scopeInfo: {
currency: "Ásd",
type: ScopeType.Auditor,
- url: "",
+ url: "http://auditor.taler.ar",
+
},
},
],
@@ -438,7 +447,8 @@ export const SomeTransactionsWithTwoCurrencies =
tests.createExample(
scope: {
currency: "Ásd",
type: ScopeType.Auditor,
- url: "",
+ url: "http://auditor.taler.ar",
+
},
balances: [
{
@@ -451,7 +461,8 @@ export const SomeTransactionsWithTwoCurrencies =
tests.createExample(
scopeInfo: {
currency: "Ásd",
type: ScopeType.Auditor,
- url: "",
+ url: "http://auditor.taler.ar",
+
},
},
{
@@ -464,7 +475,8 @@ export const SomeTransactionsWithTwoCurrencies =
tests.createExample(
scopeInfo: {
currency: "Ásd",
type: ScopeType.Auditor,
- url: "",
+ url: "http://auditor.taler.ar",
+
},
},
],
@@ -478,7 +490,8 @@ export const FiveOfficialCurrencies =
tests.createExample(TestedComponent, {
scope: {
currency: "Ásd",
type: ScopeType.Auditor,
- url: "",
+ url: "http://auditor.taler.ar",
+
},
balances: [
{
@@ -491,7 +504,8 @@ export const FiveOfficialCurrencies =
tests.createExample(TestedComponent, {
scopeInfo: {
currency: "Ásd",
type: ScopeType.Auditor,
- url: "",
+ url: "http://auditor.taler.ar",
+
},
},
{
@@ -504,7 +518,8 @@ export const FiveOfficialCurrencies =
tests.createExample(TestedComponent, {
scopeInfo: {
currency: "Ásd",
type: ScopeType.Auditor,
- url: "",
+ url: "http://auditor.taler.ar",
+
},
},
{
@@ -517,7 +532,8 @@ export const FiveOfficialCurrencies =
tests.createExample(TestedComponent, {
scopeInfo: {
currency: "Ásd",
type: ScopeType.Auditor,
- url: "",
+ url: "http://auditor.taler.ar",
+
},
},
{
@@ -530,7 +546,8 @@ export const FiveOfficialCurrencies =
tests.createExample(TestedComponent, {
scopeInfo: {
currency: "Ásd",
type: ScopeType.Auditor,
- url: "",
+ url: "http://auditor.taler.ar",
+
},
},
{
@@ -543,7 +560,8 @@ export const FiveOfficialCurrencies =
tests.createExample(TestedComponent, {
scopeInfo: {
currency: "Ásd",
type: ScopeType.Auditor,
- url: "",
+ url: "http://auditor.taler.ar",
+
},
},
],
@@ -558,7 +576,8 @@ export const FiveOfficialCurrenciesWithHighValue =
tests.createExample(
scope: {
currency: "Ásd",
type: ScopeType.Auditor,
- url: "",
+ url: "http://auditor.taler.ar",
+
},
balances: [
{
@@ -571,7 +590,8 @@ export const FiveOfficialCurrenciesWithHighValue =
tests.createExample(
scopeInfo: {
currency: "Ásd",
type: ScopeType.Auditor,
- url: "",
+ url: "http://auditor.taler.ar",
+
},
},
{
@@ -584,7 +604,8 @@ export const FiveOfficialCurrenciesWithHighValue =
tests.createExample(
scopeInfo: {
currency: "Ásd",
type: ScopeType.Auditor,
- url: "",
+ url: "http://auditor.taler.ar",
+
},
},
{
@@ -596,7 +617,8 @@ export const FiveOfficialCurrenciesWithHighValue =
tests.createExample(
scopeInfo: {
currency: "Ásd",
type: ScopeType.Auditor,
- url: "",
+ url: "http://auditor.taler.ar",
+
},
requiresUserInput: false,
},
@@ -610,7 +632,8 @@ export const FiveOfficialCurrenciesWithHighValue =
tests.createExample(
scopeInfo: {
currency: "Ásd",
type: ScopeType.Auditor,
- url: "",
+ url: "http://auditor.taler.ar",
+
},
},
{
@@ -623,7 +646,8 @@ export const FiveOfficialCurrenciesWithHighValue =
tests.createExample(
scopeInfo: {
currency: "Ásd",
type: ScopeType.Auditor,
- url: "",
+ url: "http://auditor.taler.ar",
+
},
},
],
@@ -642,7 +666,8 @@ export const PeerToPeer =
tests.createExample(TestedComponent, {
scope: {
currency: "Ásd",
type: ScopeType.Auditor,
- url: "",
+ url: "http://auditor.taler.ar",
+
},
balances: [
{
@@ -655,7 +680,8 @@ export const PeerToPeer =
tests.createExample(TestedComponent, {
scopeInfo: {
currency: "Ásd",
type: ScopeType.Auditor,
- url: "",
+ url: "http://auditor.taler.ar",
+
},
},
],
diff --git a/packages/web-util/src/components/Attention.tsx
b/packages/web-util/src/components/Attention.tsx
index 4172c0c9b..7b2310c63 100644
--- a/packages/web-util/src/components/Attention.tsx
+++ b/packages/web-util/src/components/Attention.tsx
@@ -11,7 +11,7 @@ interface Props {
export function Attention({ type = "info", title, children, onClose, timeout =
Duration.getForever() }: Props): VNode {
return <div class={`group attention-${type} mt-2 shadow-lg`}>
- {timeout.d_ms === "forever" ? undefined : <style>{`
+ {/* {timeout.d_ms === "forever" ? undefined : <style>{`
.progress {
animation: notificationTimeoutBar ${Math.round(timeout.d_ms / 1000)}s
ease-in-out;
animation-fill-mode:both;
@@ -22,7 +22,7 @@ export function Attention({ type = "info", title, children,
onClose, timeout = D
100% { width: 100%; }
}
`}</style>
- }
+ } */}
<div data-timed={timeout.d_ms !== "forever"} class="rounded-md
data-[timed=true]:rounded-b-none group-[.attention-info]:bg-blue-50
group-[.attention-low]:bg-gray-100 group-[.attention-warning]:bg-yellow-50
group-[.attention-danger]:bg-red-50 group-[.attention-success]:bg-green-50 p-4
shadow">
<div class="flex">
diff --git a/packages/web-util/src/components/Button.tsx
b/packages/web-util/src/components/Button.tsx
index 18047418e..0d5605699 100644
--- a/packages/web-util/src/components/Button.tsx
+++ b/packages/web-util/src/components/Button.tsx
@@ -88,7 +88,7 @@ export function Button<T extends OperationResult<A, B>, A,
B>({
function Wait(): VNode {
return (
<Fragment>
- <style>
+ {/* <style>
{`
#l1 { width: 120px;
height: 20px;
@@ -99,7 +99,7 @@ function Wait(): VNode {
@keyframes l17 {
100% {background-size:120% 100%}
`}
- </style>
+ </style> */}
<div id="l1" />
</Fragment>
);
diff --git a/packages/web-util/src/components/Header.tsx
b/packages/web-util/src/components/Header.tsx
index 23ac62383..4a0180afc 100644
--- a/packages/web-util/src/components/Header.tsx
+++ b/packages/web-util/src/components/Header.tsx
@@ -38,10 +38,9 @@ export function Header({
<div class="flex-shrink-0 bg-white rounded-lg">
<a href={iconLinkURL ?? "#"} name="logo">
<img
- class="h-8 w-auto"
+ class="h-8 w-auto m-1"
src={logo}
alt="GNU Taler"
- style={{ height: "1.5rem", margin: ".5rem" }}
/>
</a>
</div>
diff --git a/packages/web-util/src/components/Loading.tsx
b/packages/web-util/src/components/Loading.tsx
index c5dcd90c1..e8b9274fa 100644
--- a/packages/web-util/src/components/Loading.tsx
+++ b/packages/web-util/src/components/Loading.tsx
@@ -35,7 +35,7 @@ export function Loading(): VNode {
function Spinner(): VNode {
return (
- <div class="lds-ring" style={{ margin: "auto" }}>
+ <div class="lds-ring m-auto" >
<div />
<div />
<div />
diff --git a/packages/web-util/src/components/ShowInputErrorLabel.tsx
b/packages/web-util/src/components/ShowInputErrorLabel.tsx
index c5840cad9..8ba46af40 100644
--- a/packages/web-util/src/components/ShowInputErrorLabel.tsx
+++ b/packages/web-util/src/components/ShowInputErrorLabel.tsx
@@ -25,5 +25,5 @@ export function ShowInputErrorLabel({
}): VNode {
if (message && isDirty)
return <div class="text-base" style={{ color: "red" }}>{message}</div>;
- return <div class="text-base" style={{ }}> </div>;
+ return <div class="text-base" > </div>;
}
--
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.
- [taler-typescript-core] branch master updated (0c95d00a5 -> 6bada2347),
Admin <=