/* * This file belongs to Hoist, an application development toolkit * developed by Extremely Heavy Industries (www.xh.io | info@xh.io) * * Copyright © 2026 Extremely Heavy Industries Inc. */ import {LoginPanelModel} from '@xh/hoist/appcontainer/login/LoginPanelModel'; import {div, filler, form, viewport, vspacer} from '@xh/hoist/cmp/layout'; import {creates, hoistCmp, XH} from '@xh/hoist/core'; import {button} from '@xh/hoist/desktop/cmp/button'; import {textInput} from '@xh/hoist/desktop/cmp/input'; import {panel} from '@xh/hoist/desktop/cmp/panel'; import {Icon} from '@xh/hoist/icon'; import './LoginPanel.scss'; /** * A minimal username / password prompt for applications using form-based authentication. * Automatically created and displayed if required by AppContainer. * * @internal */ export const loginPanel = hoistCmp.factory({ displayName: 'LoginPanel', model: creates(LoginPanelModel), render({model}) { const {loginMessage, loginPanelIcon} = XH.appSpec, {loadObserver, warning, isValid, loginInProgress} = model; const onKeyDown = ev => { if (ev.key === 'Enter') model.submitAsync(); }; return viewport({ alignItems: 'center', justifyContent: 'center', flexDirection: 'column', item: panel({ title: `Login to ${XH.clientAppName}`, icon: loginPanelIcon ?? Icon.shieldHalved({prefix: 'fas'}), className: 'xh-login', testId: 'xh-login', width: 300, mask: loadObserver, items: [ vspacer(10), form( textInput({ bind: 'username', leftIcon: Icon.user(), placeholder: 'Username', autoComplete: 'username', autoFocus: true, commitOnChange: true, onKeyDown, width: null, testId: 'xh-login-username' }), textInput({ bind: 'password', leftIcon: Icon.lock(), placeholder: 'Password...', autoComplete: 'current-password', type: 'password', commitOnChange: true, onKeyDown, width: null, testId: 'xh-login-password' }) ), div({ item: loginMessage, omit: !loginMessage, className: 'xh-login__message' }), div({ item: warning, omit: !warning, className: 'xh-login__warning' }) ], bbar: [ filler(), button({ text: loginInProgress ? 'Please wait...' : 'Login', intent: 'primary', icon: Icon.login(), disabled: !isValid || loginInProgress, onClick: () => model.submitAsync(), testId: 'xh-login-btn' }) ] }) }); } });