taler-typescript-core

Wallet core logic and WebUIs for various components
Log | Files | Refs | Submodules | README | LICENSE

commit 3a84bdbfa0957620be6721546dd6cdd902ceaa5b
parent e699cd5c2b5caec7c07d098b19cb7e29bd4e8460
Author: Sebastian <sebasjm@gmail.com>
Date:   Thu,  1 May 2025 12:35:38 -0300

fix #9795

Diffstat:
Mpackages/merchant-backoffice-ui/build.mjs | 1+
Mpackages/merchant-backoffice-ui/src/components/form/InputSecured.stories.tsx | 6+++---
Mpackages/merchant-backoffice-ui/src/components/modal/index.tsx | 32++++++++++++++++----------------
Mpackages/merchant-backoffice-ui/src/context/session.ts | 21++++++++++++++++-----
Mpackages/merchant-backoffice-ui/src/paths/login/index.tsx | 37+++++++++++++++++++++++++++++++++++--
5 files changed, 71 insertions(+), 26 deletions(-)

diff --git a/packages/merchant-backoffice-ui/build.mjs b/packages/merchant-backoffice-ui/build.mjs @@ -19,6 +19,7 @@ import { build } from "@gnu-taler/web-util/build"; await build({ type: "production", + importMeta: import.meta, source: { js: ["src/index.tsx","src/lang.ts"], assets: [{base:"src",files:["src/index.html"]}], diff --git a/packages/merchant-backoffice-ui/src/components/form/InputSecured.stories.tsx b/packages/merchant-backoffice-ui/src/components/form/InputSecured.stories.tsx @@ -36,7 +36,7 @@ export const InitialValueEmpty = (): VNode => { return ( <FormProvider<T> object={state} errors={{}} valueHandler={setState}> Initial value: '' - <InputSecured<T> name="auth_token" label="Access token" /> + <InputSecured<T> name="auth_token" label="Password" /> </FormProvider> ); }; @@ -45,7 +45,7 @@ export const InitialValueToken = (): VNode => { const [state, setState] = useState<Partial<T>>({ auth_token: "token" }); return ( <FormProvider<T> object={state} errors={{}} valueHandler={setState}> - <InputSecured<T> name="auth_token" label="Access token" /> + <InputSecured<T> name="auth_token" label="Password" /> </FormProvider> ); }; @@ -55,7 +55,7 @@ export const InitialValueNull = (): VNode => { return ( <FormProvider<T> object={state} errors={{}} valueHandler={setState}> Initial value: '' - <InputSecured<T> name="auth_token" label="Access token" /> + <InputSecured<T> name="auth_token" label="Password" /> </FormProvider> ); }; diff --git a/packages/merchant-backoffice-ui/src/components/modal/index.tsx b/packages/merchant-backoffice-ui/src/components/modal/index.tsx @@ -792,7 +792,7 @@ export function UpdateTokenModal({ const hasInputTheCorrectOldToken = oldToken && oldToken !== form.old_token; const errors = undefinedIfEmpty({ old_token: hasInputTheCorrectOldToken - ? i18n.str`Is not the same as the current access token` + ? i18n.str`Is not the same as the current password` : undefined, new_token: !form.new_token ? i18n.str`Required` @@ -809,7 +809,7 @@ export function UpdateTokenModal({ const { state } = useSessionContext(); - const text = i18n.str`You are updating the access token for the instance with ID ${state.instance}`; + const text = i18n.str`You are updating the password for the instance with ID ${state.instance}`; return ( <ClearConfirmModal @@ -825,27 +825,27 @@ export function UpdateTokenModal({ {oldToken && ( <Input<State> name="old_token" - label={i18n.str`Old access token`} - tooltip={i18n.str`Access token currently in use`} + label={i18n.str`Old password`} + tooltip={i18n.str`Password currently in use`} inputType="password" /> )} <Input<State> name="new_token" - label={i18n.str`New access token`} - tooltip={i18n.str`Next access token to be used`} + label={i18n.str`New password`} + tooltip={i18n.str`Next password to be used`} inputType="password" /> <Input<State> name="repeat_token" - label={i18n.str`Repeat access token`} - tooltip={i18n.str`Confirm the same access token`} + label={i18n.str`Repeat password`} + tooltip={i18n.str`Confirm the same password`} inputType="password" /> </FormProvider> <p> <i18n.Translate> - Clearing the access token will mean public access to the instance + Clearing the password will mean public access to the instance </i18n.Translate> </p> </div> @@ -871,7 +871,7 @@ export function SetTokenNewInstanceModal({ new_token: !form.new_token ? i18n.str`Required` : form.new_token === form.old_token - ? i18n.str`Can't be the same as the old access token` + ? i18n.str`Can't be the same as the old password` : undefined, repeat_token: form.new_token !== form.repeat_token @@ -886,7 +886,7 @@ export function SetTokenNewInstanceModal({ <div class="modal-background " onClick={onCancel} /> <div class="modal-card"> <header class="modal-card-head"> - <p class="modal-card-title">{i18n.str`You are setting the access token for the new instance`}</p> + <p class="modal-card-title">{i18n.str`You are setting the password for the new instance`}</p> <button class="delete " aria-label="close" onClick={onCancel} /> </header> <section class="modal-card-body is-main-section"> @@ -900,14 +900,14 @@ export function SetTokenNewInstanceModal({ > <Input<State> name="new_token" - label={i18n.str`New access token`} - tooltip={i18n.str`Next access token to be used`} + label={i18n.str`New password`} + tooltip={i18n.str`Next password to be used`} inputType="password" /> <Input<State> name="repeat_token" - label={i18n.str`Repeat access token`} - tooltip={i18n.str`Confirm the same access token`} + label={i18n.str`Repeat password`} + tooltip={i18n.str`Confirm the same password`} inputType="password" /> </FormProvider> @@ -940,7 +940,7 @@ export function SetTokenNewInstanceModal({ onClick={() => onConfirm(form.new_token!)} disabled={hasErrors} > - <i18n.Translate>Set access token</i18n.Translate> + <i18n.Translate>Set password</i18n.Translate> </button> </div> </footer> diff --git a/packages/merchant-backoffice-ui/src/context/session.ts b/packages/merchant-backoffice-ui/src/context/session.ts @@ -89,6 +89,11 @@ function inferInstanceName(url: URL) { return !match || !match[1] ? DEFAULT_ADMIN_USERNAME : match[1]; } +function recalculateUrlForAnotherUser(original: URL, user:string) { + const match = INSTANCE_ID_LOOKUP.exec(original.href); + return !match || !match[1] ? DEFAULT_ADMIN_USERNAME : match[1]; +} + export const defaultState = (url: URL): SavedSession => { return { backendUrl: url, @@ -114,7 +119,7 @@ export interface SessionStateHandler { * from any to loggedIn * @param info */ - logIn(token: AccessToken | undefined): void; + logIn(username: string, token: AccessToken | undefined): void; /** * from loggedIn to impersonate * @param info @@ -200,7 +205,7 @@ export const SessionContextProvider = ({ state: { backendUrl: state.backendUrl, token: state.token, - impersonated: doingImpersonation, + impersonated: false, // doingImpersonation, FIXME: removing impersonation feature for 1.2 instance: currentInstance, isAdmin: currentInstance === DEFAULT_ADMIN_USERNAME, status: status, @@ -237,12 +242,18 @@ export const SessionContextProvider = ({ setStatus("loggedIn"); cleanAllCache(); }, - logIn(token) { + logIn(username, token) { cleanAllCache(); setStatus("loggedIn"); + let backendUrl: URL; + if (currentInstance !== username) { + backendUrl = new URL(rootLib.subInstanceApi(username).instance.baseUrl) + } else { + backendUrl = state.backendUrl + } update({ - backendUrl: state.backendUrl, - token: token, + backendUrl, + token, prevToken: state.prevToken, }); }, diff --git a/packages/merchant-backoffice-ui/src/paths/login/index.tsx b/packages/merchant-backoffice-ui/src/paths/login/index.tsx @@ -47,17 +47,24 @@ export function LoginPage(_p: Props): VNode { const [token, setToken] = useState(""); const [notif, setNotif] = useState<Notification | undefined>(undefined); const { lib, state, logIn } = useSessionContext(); + const [username, setUsername] = useState(state.instance); const { i18n } = useTranslationContext(); async function doLoginImpl() { - const result = await lib.instance.createAuthTokenFromToken( + console.log(state.instance !== username, state.instance, username); + const api = + state.instance !== username + ? lib.subInstanceApi(username).instance + : lib.instance; + + const result = await api.createAuthTokenFromToken( createRFC8959AccessTokenEncoded(token), tokenRequest, ); if (result.type === "ok") { const { token } = result.body; - logIn(token); + logIn(username, token); return; } else { switch (result.case) { @@ -102,6 +109,32 @@ export function LoginPage(_p: Props): VNode { <div class="field is-horizontal"> <div class="field-label is-normal"> <label class="label"> + <i18n.Translate>Username</i18n.Translate> + </label> + </div> + <div class="field-body"> + <div class="field"> + <p class="control is-expanded"> + <input + class="input" + type="text" + placeholder={"instance name"} + name="username" + onKeyPress={(e) => + e.keyCode === 13 ? doLoginImpl() : null + } + value={username} + onInput={(e): void => + setUsername(e?.currentTarget.value) + } + /> + </p> + </div> + </div> + </div> + <div class="field is-horizontal"> + <div class="field-label is-normal"> + <label class="label"> <i18n.Translate>Password</i18n.Translate> </label> </div>