plugins: new frontend events: loginOk, loginFailed #1126

Massimo Melina committed Nov 26, 2025 at 10:59 UTC b2e7d19c7c85a6b6a19282cdce986ad21e1f952e
3 files changed +12 -4
dev-plugins.md
+8 -2
@@ -617,8 +617,12 @@ This is a list of available frontend-events, with respective object parameter an
617 - `newListEntries`
618 - new entries for the list have being fetched from the server
619 - parameter `{ entries: DirEntry[] }`
620 +- `loginOk`
621 + - parameter `{ username }`
622 +- `loginFailed`
623 + - parameter `{ username, error }`
624 - All of the following have no parameters and you are supposed to output `Html` that will be displayed in the described place:
621 -- `appendMenuBar` inside menu-bar, at the end
625 + - `appendMenuBar` inside menu-bar, at the end
626 - `afterMenuBar` between menu-bar and breadcrumbs
627 - `afterBreadcrumbs` between breadcrumbs and folder-stats
628 - `afterFolderStats` between folder-stats and filter-bar
@@ -1079,4 +1083,6 @@ If you want to override a text regardless of the language, use the special langu
1083 - ctx.disconnect(logMessage)
1084 - 12.94 (v0.57.24)
1085 - HFS.onEvent now supports :after
1082 - - HFS.userBelongsTo now supports array of usernames
\ No newline at end of file
1086 + - HFS.userBelongsTo now supports array of usernames
1087 +- 12.95 (v0.57.27)
1088 + - frontend events: loginOk, loginFailed
\ No newline at end of file
frontend/src/login.ts
+3 -1
@@ -4,7 +4,7 @@ import { apiCall } from '@hfs/shared/api'
4 import { state, useSnapState } from './state'
5 import { alertDialog, newDialog, toast } from './dialog'
6 import {
7 - getHFS, hIcon, makeSessionRefresher, srpClientSequence, working, fallbackToBasicAuth,
7 + getHFS, hIcon, makeSessionRefresher, srpClientSequence, working, fallbackToBasicAuth, hfsEvent,
8 HTTP_CONFLICT, HTTP_UNAUTHORIZED, HTTP_METHOD_NOT_ALLOWED, ALLOW_SESSION_IP_CHANGE,
9 } from './misc'
10 import { createElement as h, Fragment, useEffect, useRef } from 'react'
@@ -22,10 +22,12 @@ async function login(username:string, password:string, extra?: object) {
22 return apiCall('login', { username, password, ...extra })
23 throw err
24 }).then(res => {
25 + hfsEvent('loginOk', { username })
26 refreshSession(res)
27 state.loginRequired = false
28 return res
29 }, err => {
30 + hfsEvent('loginFailed', { username, error: err }) // the name inconsistency with the backend event 'failedLogin' can make it easier to distinguish
31 throw Error(err.data === 'trust' ? t('login_untrusted', "Login aborted: server identity cannot be trusted")
32 : err.code === HTTP_UNAUTHORIZED && !err.data ? t('login_bad_credentials', "Invalid credentials") // err.data is empty on standard errors, but a plugin may want to show differently
33 : err.code === HTTP_CONFLICT ? t('login_bad_cookies', "Cookies not working - login failed")
src/const.ts
+1 -1
@@ -9,7 +9,7 @@ import { formatTimestamp } from './cross'
9 import { argv } from './argv'
10 export * from './cross-const'
11
12 -export const API_VERSION = 12.94
12 +export const API_VERSION = 12.95
13 export const COMPATIBLE_API_VERSION = 1 // while changes in the api are not breaking, this number stays the same, otherwise it is made equal to API_VERSION
14
15 // you can add arguments with this file, currently used for the update process on mac/linux