web-mojo 2.2.102 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/dist/admin.cjs.js +1 -1
- package/dist/admin.es.js +1 -1
- package/dist/auth.cjs.js +1 -1
- package/dist/auth.cjs.js.map +1 -1
- package/dist/auth.es.js +1 -1
- package/dist/auth.es.js.map +1 -1
- package/dist/charts.cjs.js +1 -1
- package/dist/charts.es.js +1 -1
- package/dist/chunks/{AssistantPanelView-CMRTtoqS.js → AssistantPanelView-BG34Qbfj.js} +2 -2
- package/dist/chunks/{AssistantPanelView-CMRTtoqS.js.map → AssistantPanelView-BG34Qbfj.js.map} +1 -1
- package/dist/chunks/{AssistantPanelView-CaVkWhVD.js → AssistantPanelView-DCEV6VeI.js} +2 -2
- package/dist/chunks/{AssistantPanelView-CaVkWhVD.js.map → AssistantPanelView-DCEV6VeI.js.map} +1 -1
- package/dist/chunks/{TokenManager-CFsr1qUV.js → TokenManager-CcQFvaFD.js} +2 -2
- package/dist/chunks/{TokenManager-CFsr1qUV.js.map → TokenManager-CcQFvaFD.js.map} +1 -1
- package/dist/chunks/{TokenManager-CHQxK_e5.js → TokenManager-DEWZqbuo.js} +2 -2
- package/dist/chunks/{TokenManager-CHQxK_e5.js.map → TokenManager-DEWZqbuo.js.map} +1 -1
- package/dist/chunks/admin-B5tf0zOO.js +2 -0
- package/dist/chunks/admin-B5tf0zOO.js.map +1 -0
- package/dist/chunks/admin-CGoTpXfs.js +2 -0
- package/dist/chunks/admin-CGoTpXfs.js.map +1 -0
- package/dist/chunks/{exportChart-DbsHDCxw.js → exportChart-BTJBYkOz.js} +2 -2
- package/dist/chunks/exportChart-BTJBYkOz.js.map +1 -0
- package/dist/chunks/{exportChart-Dk8D_du5.js → exportChart-kQ-we4Cp.js} +2 -2
- package/dist/chunks/exportChart-kQ-we4Cp.js.map +1 -0
- package/dist/chunks/version-BURwX10Q.js +2 -0
- package/dist/chunks/version-BURwX10Q.js.map +1 -0
- package/dist/chunks/version-CYGIXntv.js +2 -0
- package/dist/chunks/version-CYGIXntv.js.map +1 -0
- package/dist/docit.cjs.js +1 -1
- package/dist/docit.es.js +1 -1
- package/dist/index.cjs.js +1 -1
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +1 -1
- package/dist/index.es.js.map +1 -1
- package/dist/lightbox.cjs.js +1 -1
- package/dist/lightbox.es.js +1 -1
- package/dist/mojo-auth.es.js +94 -65
- package/dist/mojo-auth.umd.js +1 -1
- package/package.json +1 -1
- package/dist/chunks/admin-BkxeK68u.js +0 -2
- package/dist/chunks/admin-BkxeK68u.js.map +0 -1
- package/dist/chunks/admin-vjoNbv_1.js +0 -2
- package/dist/chunks/admin-vjoNbv_1.js.map +0 -1
- package/dist/chunks/exportChart-DbsHDCxw.js.map +0 -1
- package/dist/chunks/exportChart-Dk8D_du5.js.map +0 -1
- package/dist/chunks/version-B0cBv8MN.js +0 -2
- package/dist/chunks/version-B0cBv8MN.js.map +0 -1
- package/dist/chunks/version-DtqCY0ZY.js +0 -2
- package/dist/chunks/version-DtqCY0ZY.js.map +0 -1
package/dist/auth.es.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.es.js","sources":["../src/extensions/auth/index.js"],"sourcesContent":["/**\n * Simple Auth Module (KISS)\n * - Standalone, framework-agnostic\n * - Exposes:\n * - createAuthClient({ baseURL }): imperative API for auth endpoints\n * - mountAuth(container, config): renders UI and wires flows; redirects on success\n * - Future extensibility: providers (google/passkey) can be slotted via config without changing core\n */\n\nimport './css/auth.css';\n\n/**\n * Create a minimal, framework-agnostic auth client using fetch.\n *\n * Endpoints (overridable via options.endpoints):\n * - POST /login { username, password }\n * - POST /auth/forgot { email, method: 'code' | 'link' }\n * - POST /auth/password/reset/code { email, code, new_password }\n * - POST /auth/password/reset/token { token, new_password }\n */\nexport function createAuthClient({\n baseURL,\n fetchImpl = (typeof fetch !== 'undefined' ? fetch.bind(window) : null),\n storage = (typeof localStorage !== 'undefined' ? localStorage : null),\n endpoints = {}\n} = {}) {\n if (!baseURL) {\n throw new Error('createAuthClient: baseURL is required');\n }\n if (!fetchImpl) {\n throw new Error('createAuthClient: fetch implementation is not available in this environment');\n }\n if (!storage) {\n throw new Error('createAuthClient: storage (localStorage) is not available in this environment');\n }\n\n const KEYS = {\n access: 'access_token',\n refresh: 'refresh_token',\n user: 'user'\n };\n\n const EP = {\n login: '/login',\n forgot: '/auth/forgot',\n resetCode: '/auth/password/reset/code',\n resetToken: '/auth/password/reset/token',\n ...endpoints\n };\n\n async function post(path, body) {\n const res = await fetchImpl(`${baseURL}${path}`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body || {})\n });\n let json = {};\n try {\n json = await res.json();\n } catch (_) {\n // ignore parse error; json stays {}\n }\n if (!res.ok) {\n // Preserve parsed server error shape\n throw json || { message: `Request failed with status ${res.status}` };\n }\n return json;\n }\n\n function parseResponse(r) {\n // Normalize common API shapes:\n // - { data: { data: {...}} }\n // - { data: {...} }\n // - {...}\n return (r && r.data && r.data.data) || (r && r.data) || r;\n }\n\n function saveAuthData(resp) {\n const d = parseResponse(resp);\n if (!d || !d.access_token) {\n throw new Error('No access_token in response.');\n }\n storage.setItem(KEYS.access, d.access_token);\n if (d.refresh_token) storage.setItem(KEYS.refresh, d.refresh_token);\n if (d.user) storage.setItem(KEYS.user, JSON.stringify(d.user));\n }\n\n function getErrorMessage(err) {\n return err?.message ||\n err?.error ||\n (Array.isArray(err?.errors) && err.errors[0]?.message) ||\n 'An error occurred. Please try again.';\n }\n\n return {\n async login(username, password) {\n const resp = await post(EP.login, { username, password });\n saveAuthData(resp);\n return parseResponse(resp);\n },\n async forgot({ email, method }) {\n return post(EP.forgot, { email, method });\n },\n async resetWithCode({ email, code, newPassword }) {\n const resp = await post(EP.resetCode, { email, code, new_password: newPassword });\n saveAuthData(resp);\n return parseResponse(resp);\n },\n async resetWithToken({ token, newPassword }) {\n const resp = await post(EP.resetToken, { token, new_password: newPassword });\n saveAuthData(resp);\n return parseResponse(resp);\n },\n logout() {\n storage.removeItem(KEYS.access);\n storage.removeItem(KEYS.refresh);\n storage.removeItem(KEYS.user);\n },\n isAuthenticated() {\n return !!storage.getItem(KEYS.access);\n },\n getToken() {\n return storage.getItem(KEYS.access);\n },\n getUser() {\n const raw = storage.getItem(KEYS.user);\n try { return raw ? JSON.parse(raw) : null; } catch { return null; }\n },\n getAuthHeader() {\n const t = storage.getItem(KEYS.access);\n return t ? `Bearer ${t}` : null;\n },\n getErrorMessage,\n parseResponse\n };\n}\n\n/**\n * Mount the full auth UI into a container element with flows:\n * - Sign in\n * - Forgot password (code or link)\n * - Reset with code\n * - Set password via magic link token (login_token from URL)\n *\n * Options:\n * - baseURL: string (required)\n * - onSuccessRedirect: string (final URL after successful login/reset)\n * - allowRedirectOrigins: string[] (optional allowlist of origins to prevent open redirects)\n * - branding: { title?: string, logoUrl?: string, subtitle?: string }\n * - theme: 'light' | 'dark' | string (added as a class on the root container)\n * - endpoints: override endpoints { login, forgot, resetCode, resetToken }\n * - providers: optional object for future extensions (e.g., { google: { onClick } })\n * - texts: replace labels/copy if needed\n */\nexport function mountAuth(container, options = {}) {\n if (!container || !(container instanceof Element)) {\n throw new Error('mountAuth: container must be a DOM Element');\n }\n\n const {\n baseURL,\n onSuccessRedirect,\n allowRedirectOrigins,\n branding = {},\n theme,\n endpoints,\n providers,\n texts = {}\n } = options;\n\n if (!baseURL) {\n throw new Error('mountAuth: baseURL is required');\n }\n\n // Resolve redirect target from:\n // 1) options.onSuccessRedirect\n // 2) ?redirect | ?next | ?returnTo\n // Default to '/'\n const urlParams = new URLSearchParams(window.location.search);\n const redirectParam = urlParams.get('redirect') || urlParams.get('next') || urlParams.get('returnTo');\n const redirectTarget = String(onSuccessRedirect || redirectParam || '/');\n\n function isAllowedRedirect(url) {\n // If no allowlist, allow any same-origin or absolute URLs (caller responsibility).\n if (!allowRedirectOrigins || allowRedirectOrigins.length === 0) {\n return true;\n }\n try {\n const target = new URL(url, window.location.origin);\n return allowRedirectOrigins.includes(target.origin);\n } catch {\n return false;\n }\n }\n\n function performRedirect() {\n if (!isAllowedRedirect(redirectTarget)) {\n window.location.href = '/';\n return;\n }\n window.location.href = redirectTarget.startsWith('http')\n ? redirectTarget\n : new URL(redirectTarget, window.location.origin).href;\n }\n\n const auth = createAuthClient({ baseURL, endpoints });\n\n // Basic UI template (no external framework; styles provided via imported CSS)\n const B = {\n title: branding.title || 'Sign In',\n subtitle: branding.subtitle || 'Sign in to your account',\n logoUrl: branding.logoUrl || ''\n };\n\n const T = {\n emailOrUsername: texts.emailOrUsername || 'Email or Username',\n password: texts.password || 'Password',\n signIn: texts.signIn || 'Sign In',\n forgotPassword: texts.forgotPassword || 'Forgot password?',\n resetYourPassword: texts.resetYourPassword || 'Reset Your Password',\n emailAddress: texts.emailAddress || 'Email Address',\n resetMethod: texts.resetMethod || 'Reset Method',\n emailCode: texts.emailCode || 'Email me a code',\n emailLink: texts.emailLink || 'Email me a magic link',\n sendReset: texts.sendReset || 'Send Reset',\n back: texts.back || 'Back',\n enterResetCode: texts.enterResetCode || 'Enter Reset Code',\n weSentCodeTo: texts.weSentCodeTo || 'We sent a code to',\n resetCode: texts.resetCode || 'Reset Code',\n newPassword: texts.newPassword || 'New Password',\n confirmPassword: texts.confirmPassword || 'Confirm Password',\n resetPassword: texts.resetPassword || 'Reset Password',\n setYourNewPassword: texts.setYourNewPassword || 'Set Your New Password',\n setPassword: texts.setPassword || 'Set Password',\n invalidCredentials: texts.invalidCredentials || 'Invalid credentials.',\n successRedirecting: texts.successRedirecting || 'Success! Redirecting...',\n pleaseFillAllFields: texts.pleaseFillAllFields || 'Please fill in all fields.',\n passwordsDoNotMatch: texts.passwordsDoNotMatch || 'Passwords do not match.',\n };\n\n const HTML = `\n <div class=\"auth-container\">\n <div class=\"auth-card\">\n <div class=\"auth-header\">\n ${B.logoUrl ? `<img src=\"${B.logoUrl}\" alt=\"${B.title}\" style=\"max-height:60px;margin-bottom:10px\" />` : ''}\n <h1 class=\"auth-title\">${B.title}</h1>\n <p class=\"auth-subtitle\">${B.subtitle}</p>\n </div>\n\n <div id=\"status-message\" class=\"alert\" role=\"status\" style=\"display:none;\"></div>\n\n <!-- Sign In View -->\n <div id=\"view-signin\" class=\"auth-view\">\n <form id=\"form-signin\" novalidate>\n <div class=\"mb-3\">\n <label for=\"signin-username\" class=\"form-label\">${T.emailOrUsername}</label>\n <input type=\"text\" class=\"form-control\" id=\"signin-username\" placeholder=\"${T.emailOrUsername}\" autocomplete=\"username\" required />\n </div>\n <div class=\"mb-3\">\n <label for=\"signin-password\" class=\"form-label\">${T.password}</label>\n <input type=\"password\" class=\"form-control\" id=\"signin-password\" placeholder=\"${T.password}\" autocomplete=\"current-password\" required />\n </div>\n <button type=\"submit\" class=\"btn btn-primary w-100 mb-3\" id=\"btn-signin\">\n <span class=\"btn-text\">${T.signIn}</span>\n <span class=\"btn-spinner spinner-border spinner-border-sm\" style=\"display:none;\"></span>\n </button>\n <div class=\"text-center\">\n <a href=\"#\" id=\"link-forgot\" class=\"text-decoration-none\">${T.forgotPassword}</a>\n </div>\n\n ${(providers && (providers.google || providers.passkey)) ? `\n <div class=\"position-relative my-3\">\n <hr class=\"text-muted\" />\n <span class=\"position-absolute top-50 start-50 translate-middle bg-white px-3 text-muted small\">OR</span>\n </div>\n <div class=\"d-grid gap-2\">\n ${providers.google ? `<button type=\"button\" class=\"btn btn-outline-primary\" id=\"btn-google\"><i class=\"bi bi-google me-2\"></i>Continue with Google</button>` : ''}\n ${providers.passkey ? `<button type=\"button\" class=\"btn btn-outline-secondary\" id=\"btn-passkey\"><i class=\"bi bi-fingerprint me-2\"></i>Sign in with Passkey</button>` : ''}\n </div>\n ` : ''}\n </form>\n </div>\n\n <!-- Forgot Password View -->\n <div id=\"view-forgot\" class=\"auth-view\" style=\"display:none;\">\n <button type=\"button\" class=\"btn btn-link p-0 mb-3\" id=\"btn-back-signin\">\n <span aria-hidden=\"true\">←</span> ${T.back}\n </button>\n <h2 class=\"h5 mb-3\">${T.resetYourPassword}</h2>\n <form id=\"form-forgot\" novalidate>\n <div class=\"mb-3\">\n <label for=\"forgot-email\" class=\"form-label\">${T.emailAddress}</label>\n <input type=\"email\" class=\"form-control\" id=\"forgot-email\" placeholder=\"${T.emailAddress}\" autocomplete=\"email\" required />\n </div>\n <div class=\"mb-3\">\n <label class=\"form-label\">${T.resetMethod}</label>\n <div class=\"form-check\">\n <input class=\"form-check-input\" type=\"radio\" name=\"reset-method\" id=\"method-code\" value=\"code\" checked />\n <label class=\"form-check-label\" for=\"method-code\">${T.emailCode}</label>\n </div>\n <div class=\"form-check\">\n <input class=\"form-check-input\" type=\"radio\" name=\"reset-method\" id=\"method-link\" value=\"link\" />\n <label class=\"form-check-label\" for=\"method-link\">${T.emailLink}</label>\n </div>\n </div>\n <button type=\"submit\" class=\"btn btn-primary w-100\" id=\"btn-forgot\">\n <span class=\"btn-text\">${T.sendReset}</span>\n <span class=\"btn-spinner spinner-border spinner-border-sm\" style=\"display:none;\"></span>\n </button>\n </form>\n </div>\n\n <!-- Reset with Code View -->\n <div id=\"view-reset-code\" class=\"auth-view\" style=\"display:none;\">\n <button type=\"button\" class=\"btn btn-link p-0 mb-3\" id=\"btn-back-forgot\">\n <span aria-hidden=\"true\">←</span> ${T.back}\n </button>\n <h2 class=\"h5 mb-3\">${T.enterResetCode}</h2>\n <p class=\"text-muted small mb-3\">${T.weSentCodeTo} <strong id=\"reset-email-display\"></strong></p>\n <form id=\"form-reset-code\" novalidate>\n <div class=\"mb-3\">\n <label for=\"reset-code\" class=\"form-label\">${T.resetCode}</label>\n <input type=\"text\" class=\"form-control\" id=\"reset-code\" placeholder=\"${T.resetCode}\" required />\n </div>\n <div class=\"mb-3\">\n <label for=\"reset-password\" class=\"form-label\">${T.newPassword}</label>\n <input type=\"password\" class=\"form-control\" id=\"reset-password\" placeholder=\"${T.newPassword}\" autocomplete=\"new-password\" required />\n </div>\n <div class=\"mb-3\">\n <label for=\"reset-password-confirm\" class=\"form-label\">${T.confirmPassword}</label>\n <input type=\"password\" class=\"form-control\" id=\"reset-password-confirm\" placeholder=\"${T.confirmPassword}\" autocomplete=\"new-password\" required />\n </div>\n <button type=\"submit\" class=\"btn btn-primary w-100\" id=\"btn-reset-code\">\n <span class=\"btn-text\">${T.resetPassword}</span>\n <span class=\"btn-spinner spinner-border spinner-border-sm\" style=\"display:none;\"></span>\n </button>\n </form>\n </div>\n\n <!-- Set Password via Magic Link View -->\n <div id=\"view-set-password\" class=\"auth-view\" style=\"display:none;\">\n <h2 class=\"h5 mb-3\">${T.setYourNewPassword}</h2>\n <form id=\"form-set-password\" novalidate>\n <div class=\"mb-3\">\n <label for=\"set-password\" class=\"form-label\">${T.newPassword}</label>\n <input type=\"password\" class=\"form-control\" id=\"set-password\" placeholder=\"${T.newPassword}\" autocomplete=\"new-password\" required />\n </div>\n <div class=\"mb-3\">\n <label for=\"set-password-confirm\" class=\"form-label\">${T.confirmPassword}</label>\n <input type=\"password\" class=\"form-control\" id=\"set-password-confirm\" placeholder=\"${T.confirmPassword}\" autocomplete=\"new-password\" required />\n </div>\n <button type=\"submit\" class=\"btn btn-primary w-100\" id=\"btn-set-password\">\n <span class=\"btn-text\">${T.setPassword}</span>\n <span class=\"btn-spinner spinner-border spinner-border-sm\" style=\"display:none;\"></span>\n </button>\n </form>\n </div>\n </div>\n </div>\n `;\n\n // Render\n container.innerHTML = HTML;\n if (theme) {\n container.classList.add(String(theme));\n }\n\n // DOM refs\n const els = {\n views: {\n signin: container.querySelector('#view-signin'),\n forgot: container.querySelector('#view-forgot'),\n resetCode: container.querySelector('#view-reset-code'),\n setPassword: container.querySelector('#view-set-password')\n },\n forms: {\n signin: container.querySelector('#form-signin'),\n forgot: container.querySelector('#form-forgot'),\n resetCode: container.querySelector('#form-reset-code'),\n setPassword: container.querySelector('#form-set-password')\n },\n buttons: {\n signin: container.querySelector('#btn-signin'),\n forgot: container.querySelector('#btn-forgot'),\n resetCode: container.querySelector('#btn-reset-code'),\n setPassword: container.querySelector('#btn-set-password'),\n backSignin: container.querySelector('#btn-back-signin'),\n backForgot: container.querySelector('#btn-back-forgot'),\n google: container.querySelector('#btn-google'),\n passkey: container.querySelector('#btn-passkey')\n },\n inputs: {\n signinUsername: container.querySelector('#signin-username'),\n signinPassword: container.querySelector('#signin-password'),\n forgotEmail: container.querySelector('#forgot-email'),\n resetCode: container.querySelector('#reset-code'),\n resetPassword: container.querySelector('#reset-password'),\n resetPasswordConfirm: container.querySelector('#reset-password-confirm'),\n setPassword: container.querySelector('#set-password'),\n setPasswordConfirm: container.querySelector('#set-password-confirm')\n },\n radios: {\n resetMethodCode: container.querySelector('#method-code'),\n resetMethodLink: container.querySelector('#method-link')\n },\n labels: {\n resetEmailDisplay: container.querySelector('#reset-email-display')\n },\n links: {\n forgot: container.querySelector('#link-forgot')\n },\n message: container.querySelector('#status-message')\n };\n\n // Utility helpers\n function showView(name) {\n Object.entries(els.views).forEach(([key, el]) => {\n if (el) el.style.display = key === name ? 'block' : 'none';\n });\n // Focus management\n setTimeout(() => {\n const view = els.views[name];\n const heading = view?.querySelector('h1, h2, .auth-title, .h5');\n if (heading) {\n heading.setAttribute('tabindex', '-1');\n heading.focus?.();\n } else {\n const firstInput = view?.querySelector('input, button');\n firstInput?.focus?.();\n }\n }, 60);\n }\n\n function showMessage(message, type = 'info') {\n const el = els.message;\n if (!el) return;\n el.textContent = message;\n el.className = `alert alert-${type}`;\n el.style.display = 'block';\n el.setAttribute('role', type === 'danger' ? 'alert' : 'status');\n }\n\n function hideMessage() {\n const el = els.message;\n if (!el) return;\n el.style.display = 'none';\n }\n\n function setButtonLoading(button, loading) {\n if (!button) return;\n const textSpan = button.querySelector('.btn-text');\n const spinner = button.querySelector('.btn-spinner');\n\n button.disabled = !!loading;\n if (textSpan) textSpan.style.display = loading ? 'none' : 'inline';\n if (spinner) spinner.style.display = loading ? 'inline-block' : 'none';\n }\n\n function getResetMethod() {\n if (els.radios.resetMethodCode?.checked) return 'code';\n if (els.radios.resetMethodLink?.checked) return 'link';\n return 'code';\n }\n\n // Handlers\n async function handleSignin(e) {\n e?.preventDefault?.();\n hideMessage();\n\n const username = els.inputs.signinUsername?.value?.trim();\n const password = els.inputs.signinPassword?.value;\n\n if (!username || !password) {\n showMessage('Please enter both username and password.', 'danger');\n return;\n }\n\n setButtonLoading(els.buttons.signin, true);\n try {\n await auth.login(username, password);\n showMessage(`${T.successRedirecting}`, 'success');\n setTimeout(performRedirect, 350);\n } catch (err) {\n showMessage(auth.getErrorMessage(err) || T.invalidCredentials, 'danger');\n setButtonLoading(els.buttons.signin, false);\n }\n }\n\n async function handleForgot(e) {\n e?.preventDefault?.();\n hideMessage();\n\n const email = els.inputs.forgotEmail?.value?.trim();\n const method = getResetMethod();\n\n if (!email) {\n showMessage('Please enter your email address.', 'danger');\n return;\n }\n\n setButtonLoading(els.buttons.forgot, true);\n try {\n await auth.forgot({ email, method });\n\n if (method === 'code') {\n sessionStorage.setItem('reset_email', email);\n sessionStorage.setItem('reset_method', method);\n if (els.labels.resetEmailDisplay) els.labels.resetEmailDisplay.textContent = email;\n showView('resetCode');\n showMessage('Reset code sent! Check your email.', 'success');\n } else {\n showMessage('Magic link sent! Check your email and click the link.', 'success');\n }\n } catch (err) {\n showMessage(auth.getErrorMessage(err) || 'Something went wrong. Please try again.', 'danger');\n } finally {\n setButtonLoading(els.buttons.forgot, false);\n }\n }\n\n async function handleResetCode(e) {\n e?.preventDefault?.();\n hideMessage();\n\n const code = els.inputs.resetCode?.value?.trim();\n const newPassword = els.inputs.resetPassword?.value;\n const confirmPassword = els.inputs.resetPasswordConfirm?.value;\n const email = sessionStorage.getItem('reset_email');\n\n if (!email) {\n showMessage('Session expired. Please restart the password reset process.', 'danger');\n showView('forgot');\n return;\n }\n\n if (!code || !newPassword) {\n showMessage(T.pleaseFillAllFields, 'danger');\n return;\n }\n if (newPassword !== confirmPassword) {\n showMessage(T.passwordsDoNotMatch, 'danger');\n return;\n }\n\n setButtonLoading(els.buttons.resetCode, true);\n try {\n await auth.resetWithCode({ email, code, newPassword });\n sessionStorage.removeItem('reset_email');\n sessionStorage.removeItem('reset_method');\n showMessage(T.successRedirecting, 'success');\n setTimeout(performRedirect, 350);\n } catch (err) {\n showMessage(auth.getErrorMessage(err) || 'Invalid code or code expired.', 'danger');\n setButtonLoading(els.buttons.resetCode, false);\n }\n }\n\n async function handleSetPassword(e) {\n e?.preventDefault?.();\n hideMessage();\n\n const newPassword = els.inputs.setPassword?.value;\n const confirmPassword = els.inputs.setPasswordConfirm?.value;\n const token = sessionStorage.getItem('login_token');\n\n if (!token) {\n showMessage('Invalid or expired link. Please request a new one.', 'danger');\n showView('forgot');\n return;\n }\n if (!newPassword) {\n showMessage('Please enter a new password.', 'danger');\n return;\n }\n if (newPassword !== confirmPassword) {\n showMessage(T.passwordsDoNotMatch, 'danger');\n return;\n }\n\n setButtonLoading(els.buttons.setPassword, true);\n try {\n await auth.resetWithToken({ token, newPassword });\n sessionStorage.removeItem('login_token');\n showMessage(T.successRedirecting, 'success');\n setTimeout(performRedirect, 350);\n } catch (err) {\n showMessage(auth.getErrorMessage(err) || 'Invalid or expired link.', 'danger');\n setButtonLoading(els.buttons.setPassword, false);\n }\n }\n\n // Navigation\n function goToForgot(e) {\n e?.preventDefault?.();\n hideMessage();\n showView('forgot');\n }\n function backToSignin() {\n hideMessage();\n showView('signin');\n }\n function backToForgot() {\n hideMessage();\n showView('forgot');\n }\n\n // Provider buttons (future extensibility)\n function bindProviders() {\n if (providers?.google && els.buttons.google) {\n els.buttons.google.addEventListener('click', (e) => {\n e?.preventDefault?.();\n providers.google.onClick?.({ container, auth, redirect: performRedirect, showMessage });\n });\n }\n if (providers?.passkey && els.buttons.passkey) {\n els.buttons.passkey.addEventListener('click', (e) => {\n e?.preventDefault?.();\n providers.passkey.onClick?.({ container, auth, redirect: performRedirect, showMessage });\n });\n }\n }\n\n // Wire events\n els.forms.signin?.addEventListener('submit', handleSignin);\n els.forms.forgot?.addEventListener('submit', handleForgot);\n els.forms.resetCode?.addEventListener('submit', handleResetCode);\n els.forms.setPassword?.addEventListener('submit', handleSetPassword);\n els.links.forgot?.addEventListener('click', goToForgot);\n els.buttons.backSignin?.addEventListener('click', backToSignin);\n els.buttons.backForgot?.addEventListener('click', backToForgot);\n\n bindProviders();\n\n // Initialize view based on URL token (magic link flow)\n (function init() {\n // Check magic link token\n const params = new URLSearchParams(window.location.search);\n const loginToken = params.get('login_token');\n\n if (loginToken) {\n sessionStorage.setItem('login_token', loginToken);\n\n // Clean URL (remove login_token)\n params.delete('login_token');\n const newUrl = params.toString()\n ? `${window.location.pathname}?${params.toString()}`\n : window.location.pathname;\n window.history.replaceState({}, '', newUrl);\n\n showView('setPassword');\n showMessage('Please set your new password.', 'info');\n return;\n }\n\n // If forgot flow was started (code method)\n const resetEmail = sessionStorage.getItem('reset_email');\n if (resetEmail) {\n if (els.labels.resetEmailDisplay) els.labels.resetEmailDisplay.textContent = resetEmail;\n showView('resetCode');\n return;\n }\n\n // Default view\n showView('signin');\n })();\n\n // Return unmount/destroy function for cleanup\n return {\n destroy() {\n els.forms.signin?.removeEventListener('submit', handleSignin);\n els.forms.forgot?.removeEventListener('submit', handleForgot);\n els.forms.resetCode?.removeEventListener('submit', handleResetCode);\n els.forms.setPassword?.removeEventListener('submit', handleSetPassword);\n els.links.forgot?.removeEventListener('click', goToForgot);\n els.buttons.backSignin?.removeEventListener('click', backToSignin);\n els.buttons.backForgot?.removeEventListener('click', backToForgot);\n if (providers?.google && els.buttons.google) {\n els.buttons.google.replaceWith(els.buttons.google.cloneNode(true));\n }\n if (providers?.passkey && els.buttons.passkey) {\n els.buttons.passkey.replaceWith(els.buttons.passkey.cloneNode(true));\n }\n container.innerHTML = '';\n }\n };\n}\n\nexport default {\n mountAuth,\n createAuthClient\n};"],"names":["createAuthClient","baseURL","fetchImpl","fetch","bind","window","storage","localStorage","endpoints","Error","KEYS","EP","login","forgot","resetCode","resetToken","async","post","path","body","res","method","headers","JSON","stringify","json","_","ok","message","status","parseResponse","r","data","saveAuthData","resp","d","access_token","setItem","refresh_token","user","username","password","email","resetWithCode","code","newPassword","new_password","resetWithToken","token","logout","removeItem","isAuthenticated","getItem","getToken","getUser","raw","parse","getAuthHeader","t","getErrorMessage","err","error","Array","isArray","errors","mountAuth","container","options","Element","onSuccessRedirect","allowRedirectOrigins","branding","theme","providers","texts","urlParams","URLSearchParams","location","search","redirectParam","get","redirectTarget","String","performRedirect","url","length","target","URL","origin","includes","isAllowedRedirect","href","startsWith","auth","B","title","subtitle","logoUrl","T","emailOrUsername","signIn","forgotPassword","resetYourPassword","emailAddress","resetMethod","emailCode","emailLink","sendReset","back","enterResetCode","weSentCodeTo","confirmPassword","resetPassword","setYourNewPassword","setPassword","invalidCredentials","successRedirecting","pleaseFillAllFields","passwordsDoNotMatch","HTML","google","passkey","innerHTML","classList","add","els","views","signin","querySelector","forms","buttons","backSignin","backForgot","inputs","signinUsername","signinPassword","forgotEmail","resetPasswordConfirm","setPasswordConfirm","radios","resetMethodCode","resetMethodLink","labels","resetEmailDisplay","links","showView","name","Object","entries","forEach","key","el","style","display","setTimeout","view","heading","setAttribute","focus","firstInput","showMessage","type","textContent","className","hideMessage","setButtonLoading","button","loading","textSpan","spinner","disabled","handleSignin","e","preventDefault","value","trim","handleForgot","checked","sessionStorage","handleResetCode","handleSetPassword","goToForgot","backToSignin","backToForgot","addEventListener","onClick","redirect","params","loginToken","delete","newUrl","toString","pathname","history","replaceState","resetEmail","destroy","removeEventListener","replaceWith","cloneNode","index"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"auth.es.js","sources":["../src/extensions/auth/index.js"],"sourcesContent":["/**\n * Simple Auth Module (KISS)\n * - Standalone, framework-agnostic\n * - Exposes:\n * - createAuthClient({ baseURL }): imperative API for auth endpoints\n * - mountAuth(container, config): renders UI and wires flows; redirects on success\n * - Future extensibility: providers (google/passkey) can be slotted via config without changing core\n */\n\nimport './css/auth.css';\n\n/**\n * Create a minimal, framework-agnostic auth client using fetch.\n *\n * Endpoints (overridable via options.endpoints):\n * - POST /login { username, password }\n * - POST /auth/forgot { email, method: 'code' | 'link' }\n * - POST /auth/password/reset/code { email, code, new_password }\n * - POST /auth/password/reset/token { token, new_password }\n */\nexport function createAuthClient({\n baseURL,\n fetchImpl = (typeof fetch !== 'undefined' ? fetch.bind(window) : null),\n storage = (typeof localStorage !== 'undefined' ? localStorage : null),\n endpoints = {}\n} = {}) {\n if (!baseURL) {\n throw new Error('createAuthClient: baseURL is required');\n }\n if (!fetchImpl) {\n throw new Error('createAuthClient: fetch implementation is not available in this environment');\n }\n if (!storage) {\n throw new Error('createAuthClient: storage (localStorage) is not available in this environment');\n }\n\n const KEYS = {\n access: 'access_token',\n refresh: 'refresh_token',\n user: 'user'\n };\n\n const EP = {\n login: '/login',\n forgot: '/auth/forgot',\n resetCode: '/auth/password/reset/code',\n resetToken: '/auth/password/reset/token',\n exchange: '/auth/exchange',\n ...endpoints\n };\n\n // Single-flight guard for exchangeAuthCode / handleAuthCodeFromURL —\n // a single-use auth_code must not be POSTed twice if two boot paths race.\n let _exchangePromise = null;\n\n async function post(path, body) {\n const res = await fetchImpl(`${baseURL}${path}`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body || {})\n });\n let json = {};\n try {\n json = await res.json();\n } catch (_) {\n // ignore parse error; json stays {}\n }\n if (!res.ok) {\n // Preserve parsed server error shape\n throw json || { message: `Request failed with status ${res.status}` };\n }\n return json;\n }\n\n function parseResponse(r) {\n // Normalize common API shapes:\n // - { data: { data: {...}} }\n // - { data: {...} }\n // - {...}\n return (r && r.data && r.data.data) || (r && r.data) || r;\n }\n\n function saveAuthData(resp) {\n const d = parseResponse(resp);\n if (!d || !d.access_token) {\n throw new Error('No access_token in response.');\n }\n storage.setItem(KEYS.access, d.access_token);\n if (d.refresh_token) storage.setItem(KEYS.refresh, d.refresh_token);\n if (d.user) storage.setItem(KEYS.user, JSON.stringify(d.user));\n }\n\n function getErrorMessage(err) {\n return err?.message ||\n err?.error ||\n (Array.isArray(err?.errors) && err.errors[0]?.message) ||\n 'An error occurred. Please try again.';\n }\n\n return {\n async login(username, password) {\n const resp = await post(EP.login, { username, password });\n saveAuthData(resp);\n return parseResponse(resp);\n },\n async forgot({ email, method }) {\n return post(EP.forgot, { email, method });\n },\n async resetWithCode({ email, code, newPassword }) {\n const resp = await post(EP.resetCode, { email, code, new_password: newPassword });\n saveAuthData(resp);\n return parseResponse(resp);\n },\n async resetWithToken({ token, newPassword }) {\n const resp = await post(EP.resetToken, { token, new_password: newPassword });\n saveAuthData(resp);\n return parseResponse(resp);\n },\n async exchangeAuthCode(code) {\n if (_exchangePromise) return _exchangePromise;\n _exchangePromise = (async () => {\n try {\n const resp = await post(EP.exchange, { code });\n saveAuthData(resp);\n return parseResponse(resp);\n } finally {\n _exchangePromise = null;\n }\n })();\n return _exchangePromise;\n },\n async handleAuthCodeFromURL() {\n if (typeof window === 'undefined' || !window.location) return null;\n const params = new URLSearchParams(window.location.search);\n const code = params.get('auth_code');\n if (!code) return null;\n\n // Scrub before any network call.\n params.delete('auth_code');\n const newUrl = window.location.pathname\n + (params.toString() ? `?${params.toString()}` : '')\n + (window.location.hash || '');\n window.history.replaceState({}, '', newUrl);\n\n return this.exchangeAuthCode(code);\n },\n logout() {\n storage.removeItem(KEYS.access);\n storage.removeItem(KEYS.refresh);\n storage.removeItem(KEYS.user);\n },\n isAuthenticated() {\n return !!storage.getItem(KEYS.access);\n },\n getToken() {\n return storage.getItem(KEYS.access);\n },\n getUser() {\n const raw = storage.getItem(KEYS.user);\n try { return raw ? JSON.parse(raw) : null; } catch { return null; }\n },\n getAuthHeader() {\n const t = storage.getItem(KEYS.access);\n return t ? `Bearer ${t}` : null;\n },\n getErrorMessage,\n parseResponse\n };\n}\n\n/**\n * Mount the full auth UI into a container element with flows:\n * - Sign in\n * - Forgot password (code or link)\n * - Reset with code\n * - Set password via magic link token (login_token from URL)\n *\n * Options:\n * - baseURL: string (required)\n * - onSuccessRedirect: string (final URL after successful login/reset)\n * - allowRedirectOrigins: string[] (optional allowlist of origins to prevent open redirects)\n * - branding: { title?: string, logoUrl?: string, subtitle?: string }\n * - theme: 'light' | 'dark' | string (added as a class on the root container)\n * - endpoints: override endpoints { login, forgot, resetCode, resetToken }\n * - providers: optional object for future extensions (e.g., { google: { onClick } })\n * - texts: replace labels/copy if needed\n */\nexport function mountAuth(container, options = {}) {\n if (!container || !(container instanceof Element)) {\n throw new Error('mountAuth: container must be a DOM Element');\n }\n\n const {\n baseURL,\n onSuccessRedirect,\n allowRedirectOrigins,\n branding = {},\n theme,\n endpoints,\n providers,\n texts = {}\n } = options;\n\n if (!baseURL) {\n throw new Error('mountAuth: baseURL is required');\n }\n\n // Resolve redirect target from:\n // 1) options.onSuccessRedirect\n // 2) ?redirect | ?next | ?returnTo\n // Default to '/'\n const urlParams = new URLSearchParams(window.location.search);\n const redirectParam = urlParams.get('redirect') || urlParams.get('next') || urlParams.get('returnTo');\n const redirectTarget = String(onSuccessRedirect || redirectParam || '/');\n\n function isAllowedRedirect(url) {\n // If no allowlist, allow any same-origin or absolute URLs (caller responsibility).\n if (!allowRedirectOrigins || allowRedirectOrigins.length === 0) {\n return true;\n }\n try {\n const target = new URL(url, window.location.origin);\n return allowRedirectOrigins.includes(target.origin);\n } catch {\n return false;\n }\n }\n\n function performRedirect() {\n if (!isAllowedRedirect(redirectTarget)) {\n window.location.href = '/';\n return;\n }\n window.location.href = redirectTarget.startsWith('http')\n ? redirectTarget\n : new URL(redirectTarget, window.location.origin).href;\n }\n\n const auth = createAuthClient({ baseURL, endpoints });\n\n // Basic UI template (no external framework; styles provided via imported CSS)\n const B = {\n title: branding.title || 'Sign In',\n subtitle: branding.subtitle || 'Sign in to your account',\n logoUrl: branding.logoUrl || ''\n };\n\n const T = {\n emailOrUsername: texts.emailOrUsername || 'Email or Username',\n password: texts.password || 'Password',\n signIn: texts.signIn || 'Sign In',\n forgotPassword: texts.forgotPassword || 'Forgot password?',\n resetYourPassword: texts.resetYourPassword || 'Reset Your Password',\n emailAddress: texts.emailAddress || 'Email Address',\n resetMethod: texts.resetMethod || 'Reset Method',\n emailCode: texts.emailCode || 'Email me a code',\n emailLink: texts.emailLink || 'Email me a magic link',\n sendReset: texts.sendReset || 'Send Reset',\n back: texts.back || 'Back',\n enterResetCode: texts.enterResetCode || 'Enter Reset Code',\n weSentCodeTo: texts.weSentCodeTo || 'We sent a code to',\n resetCode: texts.resetCode || 'Reset Code',\n newPassword: texts.newPassword || 'New Password',\n confirmPassword: texts.confirmPassword || 'Confirm Password',\n resetPassword: texts.resetPassword || 'Reset Password',\n setYourNewPassword: texts.setYourNewPassword || 'Set Your New Password',\n setPassword: texts.setPassword || 'Set Password',\n invalidCredentials: texts.invalidCredentials || 'Invalid credentials.',\n successRedirecting: texts.successRedirecting || 'Success! Redirecting...',\n pleaseFillAllFields: texts.pleaseFillAllFields || 'Please fill in all fields.',\n passwordsDoNotMatch: texts.passwordsDoNotMatch || 'Passwords do not match.',\n };\n\n const HTML = `\n <div class=\"auth-container\">\n <div class=\"auth-card\">\n <div class=\"auth-header\">\n ${B.logoUrl ? `<img src=\"${B.logoUrl}\" alt=\"${B.title}\" style=\"max-height:60px;margin-bottom:10px\" />` : ''}\n <h1 class=\"auth-title\">${B.title}</h1>\n <p class=\"auth-subtitle\">${B.subtitle}</p>\n </div>\n\n <div id=\"status-message\" class=\"alert\" role=\"status\" style=\"display:none;\"></div>\n\n <!-- Sign In View -->\n <div id=\"view-signin\" class=\"auth-view\">\n <form id=\"form-signin\" novalidate>\n <div class=\"mb-3\">\n <label for=\"signin-username\" class=\"form-label\">${T.emailOrUsername}</label>\n <input type=\"text\" class=\"form-control\" id=\"signin-username\" placeholder=\"${T.emailOrUsername}\" autocomplete=\"username\" required />\n </div>\n <div class=\"mb-3\">\n <label for=\"signin-password\" class=\"form-label\">${T.password}</label>\n <input type=\"password\" class=\"form-control\" id=\"signin-password\" placeholder=\"${T.password}\" autocomplete=\"current-password\" required />\n </div>\n <button type=\"submit\" class=\"btn btn-primary w-100 mb-3\" id=\"btn-signin\">\n <span class=\"btn-text\">${T.signIn}</span>\n <span class=\"btn-spinner spinner-border spinner-border-sm\" style=\"display:none;\"></span>\n </button>\n <div class=\"text-center\">\n <a href=\"#\" id=\"link-forgot\" class=\"text-decoration-none\">${T.forgotPassword}</a>\n </div>\n\n ${(providers && (providers.google || providers.passkey)) ? `\n <div class=\"position-relative my-3\">\n <hr class=\"text-muted\" />\n <span class=\"position-absolute top-50 start-50 translate-middle bg-white px-3 text-muted small\">OR</span>\n </div>\n <div class=\"d-grid gap-2\">\n ${providers.google ? `<button type=\"button\" class=\"btn btn-outline-primary\" id=\"btn-google\"><i class=\"bi bi-google me-2\"></i>Continue with Google</button>` : ''}\n ${providers.passkey ? `<button type=\"button\" class=\"btn btn-outline-secondary\" id=\"btn-passkey\"><i class=\"bi bi-fingerprint me-2\"></i>Sign in with Passkey</button>` : ''}\n </div>\n ` : ''}\n </form>\n </div>\n\n <!-- Forgot Password View -->\n <div id=\"view-forgot\" class=\"auth-view\" style=\"display:none;\">\n <button type=\"button\" class=\"btn btn-link p-0 mb-3\" id=\"btn-back-signin\">\n <span aria-hidden=\"true\">←</span> ${T.back}\n </button>\n <h2 class=\"h5 mb-3\">${T.resetYourPassword}</h2>\n <form id=\"form-forgot\" novalidate>\n <div class=\"mb-3\">\n <label for=\"forgot-email\" class=\"form-label\">${T.emailAddress}</label>\n <input type=\"email\" class=\"form-control\" id=\"forgot-email\" placeholder=\"${T.emailAddress}\" autocomplete=\"email\" required />\n </div>\n <div class=\"mb-3\">\n <label class=\"form-label\">${T.resetMethod}</label>\n <div class=\"form-check\">\n <input class=\"form-check-input\" type=\"radio\" name=\"reset-method\" id=\"method-code\" value=\"code\" checked />\n <label class=\"form-check-label\" for=\"method-code\">${T.emailCode}</label>\n </div>\n <div class=\"form-check\">\n <input class=\"form-check-input\" type=\"radio\" name=\"reset-method\" id=\"method-link\" value=\"link\" />\n <label class=\"form-check-label\" for=\"method-link\">${T.emailLink}</label>\n </div>\n </div>\n <button type=\"submit\" class=\"btn btn-primary w-100\" id=\"btn-forgot\">\n <span class=\"btn-text\">${T.sendReset}</span>\n <span class=\"btn-spinner spinner-border spinner-border-sm\" style=\"display:none;\"></span>\n </button>\n </form>\n </div>\n\n <!-- Reset with Code View -->\n <div id=\"view-reset-code\" class=\"auth-view\" style=\"display:none;\">\n <button type=\"button\" class=\"btn btn-link p-0 mb-3\" id=\"btn-back-forgot\">\n <span aria-hidden=\"true\">←</span> ${T.back}\n </button>\n <h2 class=\"h5 mb-3\">${T.enterResetCode}</h2>\n <p class=\"text-muted small mb-3\">${T.weSentCodeTo} <strong id=\"reset-email-display\"></strong></p>\n <form id=\"form-reset-code\" novalidate>\n <div class=\"mb-3\">\n <label for=\"reset-code\" class=\"form-label\">${T.resetCode}</label>\n <input type=\"text\" class=\"form-control\" id=\"reset-code\" placeholder=\"${T.resetCode}\" required />\n </div>\n <div class=\"mb-3\">\n <label for=\"reset-password\" class=\"form-label\">${T.newPassword}</label>\n <input type=\"password\" class=\"form-control\" id=\"reset-password\" placeholder=\"${T.newPassword}\" autocomplete=\"new-password\" required />\n </div>\n <div class=\"mb-3\">\n <label for=\"reset-password-confirm\" class=\"form-label\">${T.confirmPassword}</label>\n <input type=\"password\" class=\"form-control\" id=\"reset-password-confirm\" placeholder=\"${T.confirmPassword}\" autocomplete=\"new-password\" required />\n </div>\n <button type=\"submit\" class=\"btn btn-primary w-100\" id=\"btn-reset-code\">\n <span class=\"btn-text\">${T.resetPassword}</span>\n <span class=\"btn-spinner spinner-border spinner-border-sm\" style=\"display:none;\"></span>\n </button>\n </form>\n </div>\n\n <!-- Set Password via Magic Link View -->\n <div id=\"view-set-password\" class=\"auth-view\" style=\"display:none;\">\n <h2 class=\"h5 mb-3\">${T.setYourNewPassword}</h2>\n <form id=\"form-set-password\" novalidate>\n <div class=\"mb-3\">\n <label for=\"set-password\" class=\"form-label\">${T.newPassword}</label>\n <input type=\"password\" class=\"form-control\" id=\"set-password\" placeholder=\"${T.newPassword}\" autocomplete=\"new-password\" required />\n </div>\n <div class=\"mb-3\">\n <label for=\"set-password-confirm\" class=\"form-label\">${T.confirmPassword}</label>\n <input type=\"password\" class=\"form-control\" id=\"set-password-confirm\" placeholder=\"${T.confirmPassword}\" autocomplete=\"new-password\" required />\n </div>\n <button type=\"submit\" class=\"btn btn-primary w-100\" id=\"btn-set-password\">\n <span class=\"btn-text\">${T.setPassword}</span>\n <span class=\"btn-spinner spinner-border spinner-border-sm\" style=\"display:none;\"></span>\n </button>\n </form>\n </div>\n </div>\n </div>\n `;\n\n // Render\n container.innerHTML = HTML;\n if (theme) {\n container.classList.add(String(theme));\n }\n\n // DOM refs\n const els = {\n views: {\n signin: container.querySelector('#view-signin'),\n forgot: container.querySelector('#view-forgot'),\n resetCode: container.querySelector('#view-reset-code'),\n setPassword: container.querySelector('#view-set-password')\n },\n forms: {\n signin: container.querySelector('#form-signin'),\n forgot: container.querySelector('#form-forgot'),\n resetCode: container.querySelector('#form-reset-code'),\n setPassword: container.querySelector('#form-set-password')\n },\n buttons: {\n signin: container.querySelector('#btn-signin'),\n forgot: container.querySelector('#btn-forgot'),\n resetCode: container.querySelector('#btn-reset-code'),\n setPassword: container.querySelector('#btn-set-password'),\n backSignin: container.querySelector('#btn-back-signin'),\n backForgot: container.querySelector('#btn-back-forgot'),\n google: container.querySelector('#btn-google'),\n passkey: container.querySelector('#btn-passkey')\n },\n inputs: {\n signinUsername: container.querySelector('#signin-username'),\n signinPassword: container.querySelector('#signin-password'),\n forgotEmail: container.querySelector('#forgot-email'),\n resetCode: container.querySelector('#reset-code'),\n resetPassword: container.querySelector('#reset-password'),\n resetPasswordConfirm: container.querySelector('#reset-password-confirm'),\n setPassword: container.querySelector('#set-password'),\n setPasswordConfirm: container.querySelector('#set-password-confirm')\n },\n radios: {\n resetMethodCode: container.querySelector('#method-code'),\n resetMethodLink: container.querySelector('#method-link')\n },\n labels: {\n resetEmailDisplay: container.querySelector('#reset-email-display')\n },\n links: {\n forgot: container.querySelector('#link-forgot')\n },\n message: container.querySelector('#status-message')\n };\n\n // Utility helpers\n function showView(name) {\n Object.entries(els.views).forEach(([key, el]) => {\n if (el) el.style.display = key === name ? 'block' : 'none';\n });\n // Focus management\n setTimeout(() => {\n const view = els.views[name];\n const heading = view?.querySelector('h1, h2, .auth-title, .h5');\n if (heading) {\n heading.setAttribute('tabindex', '-1');\n heading.focus?.();\n } else {\n const firstInput = view?.querySelector('input, button');\n firstInput?.focus?.();\n }\n }, 60);\n }\n\n function showMessage(message, type = 'info') {\n const el = els.message;\n if (!el) return;\n el.textContent = message;\n el.className = `alert alert-${type}`;\n el.style.display = 'block';\n el.setAttribute('role', type === 'danger' ? 'alert' : 'status');\n }\n\n function hideMessage() {\n const el = els.message;\n if (!el) return;\n el.style.display = 'none';\n }\n\n function setButtonLoading(button, loading) {\n if (!button) return;\n const textSpan = button.querySelector('.btn-text');\n const spinner = button.querySelector('.btn-spinner');\n\n button.disabled = !!loading;\n if (textSpan) textSpan.style.display = loading ? 'none' : 'inline';\n if (spinner) spinner.style.display = loading ? 'inline-block' : 'none';\n }\n\n function getResetMethod() {\n if (els.radios.resetMethodCode?.checked) return 'code';\n if (els.radios.resetMethodLink?.checked) return 'link';\n return 'code';\n }\n\n // Handlers\n async function handleSignin(e) {\n e?.preventDefault?.();\n hideMessage();\n\n const username = els.inputs.signinUsername?.value?.trim();\n const password = els.inputs.signinPassword?.value;\n\n if (!username || !password) {\n showMessage('Please enter both username and password.', 'danger');\n return;\n }\n\n setButtonLoading(els.buttons.signin, true);\n try {\n await auth.login(username, password);\n showMessage(`${T.successRedirecting}`, 'success');\n setTimeout(performRedirect, 350);\n } catch (err) {\n showMessage(auth.getErrorMessage(err) || T.invalidCredentials, 'danger');\n setButtonLoading(els.buttons.signin, false);\n }\n }\n\n async function handleForgot(e) {\n e?.preventDefault?.();\n hideMessage();\n\n const email = els.inputs.forgotEmail?.value?.trim();\n const method = getResetMethod();\n\n if (!email) {\n showMessage('Please enter your email address.', 'danger');\n return;\n }\n\n setButtonLoading(els.buttons.forgot, true);\n try {\n await auth.forgot({ email, method });\n\n if (method === 'code') {\n sessionStorage.setItem('reset_email', email);\n sessionStorage.setItem('reset_method', method);\n if (els.labels.resetEmailDisplay) els.labels.resetEmailDisplay.textContent = email;\n showView('resetCode');\n showMessage('Reset code sent! Check your email.', 'success');\n } else {\n showMessage('Magic link sent! Check your email and click the link.', 'success');\n }\n } catch (err) {\n showMessage(auth.getErrorMessage(err) || 'Something went wrong. Please try again.', 'danger');\n } finally {\n setButtonLoading(els.buttons.forgot, false);\n }\n }\n\n async function handleResetCode(e) {\n e?.preventDefault?.();\n hideMessage();\n\n const code = els.inputs.resetCode?.value?.trim();\n const newPassword = els.inputs.resetPassword?.value;\n const confirmPassword = els.inputs.resetPasswordConfirm?.value;\n const email = sessionStorage.getItem('reset_email');\n\n if (!email) {\n showMessage('Session expired. Please restart the password reset process.', 'danger');\n showView('forgot');\n return;\n }\n\n if (!code || !newPassword) {\n showMessage(T.pleaseFillAllFields, 'danger');\n return;\n }\n if (newPassword !== confirmPassword) {\n showMessage(T.passwordsDoNotMatch, 'danger');\n return;\n }\n\n setButtonLoading(els.buttons.resetCode, true);\n try {\n await auth.resetWithCode({ email, code, newPassword });\n sessionStorage.removeItem('reset_email');\n sessionStorage.removeItem('reset_method');\n showMessage(T.successRedirecting, 'success');\n setTimeout(performRedirect, 350);\n } catch (err) {\n showMessage(auth.getErrorMessage(err) || 'Invalid code or code expired.', 'danger');\n setButtonLoading(els.buttons.resetCode, false);\n }\n }\n\n async function handleSetPassword(e) {\n e?.preventDefault?.();\n hideMessage();\n\n const newPassword = els.inputs.setPassword?.value;\n const confirmPassword = els.inputs.setPasswordConfirm?.value;\n const token = sessionStorage.getItem('login_token');\n\n if (!token) {\n showMessage('Invalid or expired link. Please request a new one.', 'danger');\n showView('forgot');\n return;\n }\n if (!newPassword) {\n showMessage('Please enter a new password.', 'danger');\n return;\n }\n if (newPassword !== confirmPassword) {\n showMessage(T.passwordsDoNotMatch, 'danger');\n return;\n }\n\n setButtonLoading(els.buttons.setPassword, true);\n try {\n await auth.resetWithToken({ token, newPassword });\n sessionStorage.removeItem('login_token');\n showMessage(T.successRedirecting, 'success');\n setTimeout(performRedirect, 350);\n } catch (err) {\n showMessage(auth.getErrorMessage(err) || 'Invalid or expired link.', 'danger');\n setButtonLoading(els.buttons.setPassword, false);\n }\n }\n\n // Navigation\n function goToForgot(e) {\n e?.preventDefault?.();\n hideMessage();\n showView('forgot');\n }\n function backToSignin() {\n hideMessage();\n showView('signin');\n }\n function backToForgot() {\n hideMessage();\n showView('forgot');\n }\n\n // Provider buttons (future extensibility)\n function bindProviders() {\n if (providers?.google && els.buttons.google) {\n els.buttons.google.addEventListener('click', (e) => {\n e?.preventDefault?.();\n providers.google.onClick?.({ container, auth, redirect: performRedirect, showMessage });\n });\n }\n if (providers?.passkey && els.buttons.passkey) {\n els.buttons.passkey.addEventListener('click', (e) => {\n e?.preventDefault?.();\n providers.passkey.onClick?.({ container, auth, redirect: performRedirect, showMessage });\n });\n }\n }\n\n // Wire events\n els.forms.signin?.addEventListener('submit', handleSignin);\n els.forms.forgot?.addEventListener('submit', handleForgot);\n els.forms.resetCode?.addEventListener('submit', handleResetCode);\n els.forms.setPassword?.addEventListener('submit', handleSetPassword);\n els.links.forgot?.addEventListener('click', goToForgot);\n els.buttons.backSignin?.addEventListener('click', backToSignin);\n els.buttons.backForgot?.addEventListener('click', backToForgot);\n\n bindProviders();\n\n // Initialize view based on URL token (magic link flow)\n (function init() {\n // Check magic link token\n const params = new URLSearchParams(window.location.search);\n const loginToken = params.get('login_token');\n\n if (loginToken) {\n sessionStorage.setItem('login_token', loginToken);\n\n // Clean URL (remove login_token)\n params.delete('login_token');\n const newUrl = params.toString()\n ? `${window.location.pathname}?${params.toString()}`\n : window.location.pathname;\n window.history.replaceState({}, '', newUrl);\n\n showView('setPassword');\n showMessage('Please set your new password.', 'info');\n return;\n }\n\n // If forgot flow was started (code method)\n const resetEmail = sessionStorage.getItem('reset_email');\n if (resetEmail) {\n if (els.labels.resetEmailDisplay) els.labels.resetEmailDisplay.textContent = resetEmail;\n showView('resetCode');\n return;\n }\n\n // Default view\n showView('signin');\n })();\n\n // Return unmount/destroy function for cleanup\n return {\n destroy() {\n els.forms.signin?.removeEventListener('submit', handleSignin);\n els.forms.forgot?.removeEventListener('submit', handleForgot);\n els.forms.resetCode?.removeEventListener('submit', handleResetCode);\n els.forms.setPassword?.removeEventListener('submit', handleSetPassword);\n els.links.forgot?.removeEventListener('click', goToForgot);\n els.buttons.backSignin?.removeEventListener('click', backToSignin);\n els.buttons.backForgot?.removeEventListener('click', backToForgot);\n if (providers?.google && els.buttons.google) {\n els.buttons.google.replaceWith(els.buttons.google.cloneNode(true));\n }\n if (providers?.passkey && els.buttons.passkey) {\n els.buttons.passkey.replaceWith(els.buttons.passkey.cloneNode(true));\n }\n container.innerHTML = '';\n }\n };\n}\n\nexport default {\n mountAuth,\n createAuthClient\n};"],"names":["createAuthClient","baseURL","fetchImpl","fetch","bind","window","storage","localStorage","endpoints","Error","KEYS","EP","login","forgot","resetCode","resetToken","exchange","_exchangePromise","async","post","path","body","res","method","headers","JSON","stringify","json","_","ok","message","status","parseResponse","r","data","saveAuthData","resp","d","access_token","setItem","refresh_token","user","username","password","email","resetWithCode","code","newPassword","new_password","resetWithToken","token","handleAuthCodeFromURL","location","params","URLSearchParams","search","get","delete","newUrl","pathname","toString","hash","history","replaceState","this","exchangeAuthCode","logout","removeItem","isAuthenticated","getItem","getToken","getUser","raw","parse","getAuthHeader","t","getErrorMessage","err","error","Array","isArray","errors","mountAuth","container","options","Element","onSuccessRedirect","allowRedirectOrigins","branding","theme","providers","texts","urlParams","redirectParam","redirectTarget","String","performRedirect","url","length","target","URL","origin","includes","isAllowedRedirect","href","startsWith","auth","B","title","subtitle","logoUrl","T","emailOrUsername","signIn","forgotPassword","resetYourPassword","emailAddress","resetMethod","emailCode","emailLink","sendReset","back","enterResetCode","weSentCodeTo","confirmPassword","resetPassword","setYourNewPassword","setPassword","invalidCredentials","successRedirecting","pleaseFillAllFields","passwordsDoNotMatch","HTML","google","passkey","innerHTML","classList","add","els","views","signin","querySelector","forms","buttons","backSignin","backForgot","inputs","signinUsername","signinPassword","forgotEmail","resetPasswordConfirm","setPasswordConfirm","radios","resetMethodCode","resetMethodLink","labels","resetEmailDisplay","links","showView","name","Object","entries","forEach","key","el","style","display","setTimeout","view","heading","setAttribute","focus","firstInput","showMessage","type","textContent","className","hideMessage","setButtonLoading","button","loading","textSpan","spinner","disabled","handleSignin","e","preventDefault","value","trim","handleForgot","checked","sessionStorage","handleResetCode","handleSetPassword","goToForgot","backToSignin","backToForgot","addEventListener","onClick","redirect","loginToken","resetEmail","destroy","removeEventListener","replaceWith","cloneNode","index"],"mappings":"oFAoBO,SAASA,GAAiBC,QAC/BA,EAAAC,UACAA,GAA8B,oBAAVC,MAAwBA,MAAMC,KAAKC,QAAU,MAAAC,QACjEA,GAAmC,oBAAjBC,aAA+BA,aAAe,MAAAC,UAChEA,EAAY,CAAA,GACV,IACF,IAAKP,EACH,MAAM,IAAIQ,MAAM,yCAElB,IAAKP,EACH,MAAM,IAAIO,MAAM,+EAElB,IAAKH,EACH,MAAM,IAAIG,MAAM,iFAGlB,MAAMC,EACI,eADJA,EAEK,gBAFLA,EAGE,OAGFC,EAAK,CACTC,MAAO,SACPC,OAAQ,eACRC,UAAW,4BACXC,WAAY,6BACZC,SAAU,oBACPR,GAKL,IAAIS,EAAmB,KAEvBC,eAAeC,EAAKC,EAAMC,GACxB,MAAMC,QAAYpB,EAAU,GAAGD,IAAUmB,IAAQ,CAC/CG,OAAQ,OACRC,QAAS,CAAE,eAAgB,oBAC3BH,KAAMI,KAAKC,UAAUL,GAAQ,CAAA,KAE/B,IAAIM,EAAO,CAAA,EACX,IACEA,QAAaL,EAAIK,MACnB,OAASC,GAET,CACA,IAAKN,EAAIO,GAEP,MAAMF,GAAQ,CAAEG,QAAS,8BAA8BR,EAAIS,UAE7D,OAAOJ,CACT,CAEA,SAASK,EAAcC,GAKrB,OAAQA,GAAKA,EAAEC,MAAQD,EAAEC,KAAKA,MAAUD,GAAKA,EAAEC,MAASD,CAC1D,CAEA,SAASE,EAAaC,GACpB,MAAMC,EAAIL,EAAcI,GACxB,IAAKC,IAAMA,EAAEC,aACX,MAAM,IAAI7B,MAAM,gCAElBH,EAAQiC,QAAQ7B,EAAa2B,EAAEC,cAC3BD,EAAEG,eAAelC,EAAQiC,QAAQ7B,EAAc2B,EAAEG,eACjDH,EAAEI,MAAMnC,EAAQiC,QAAQ7B,EAAWe,KAAKC,UAAUW,EAAEI,MAC1D,CASA,MAAO,CACL,WAAM7B,CAAM8B,EAAUC,GACpB,MAAMP,QAAajB,EAAKR,EAAGC,MAAO,CAAE8B,WAAUC,aAE9C,OADAR,EAAaC,GACNJ,EAAcI,EACvB,EACAlB,OAAM,OAAO0B,MAAEA,EAAArB,OAAOA,KACbJ,EAAKR,EAAGE,OAAQ,CAAE+B,QAAOrB,WAElC,mBAAMsB,EAAcD,MAAEA,EAAAE,KAAOA,EAAAC,YAAMA,IACjC,MAAMX,QAAajB,EAAKR,EAAGG,UAAW,CAAE8B,QAAOE,OAAME,aAAcD,IAEnE,OADAZ,EAAaC,GACNJ,EAAcI,EACvB,EACA,oBAAMa,EAAeC,MAAEA,EAAAH,YAAOA,IAC5B,MAAMX,QAAajB,EAAKR,EAAGI,WAAY,CAAEmC,QAAOF,aAAcD,IAE9D,OADAZ,EAAaC,GACNJ,EAAcI,EACvB,EACAlB,uBAAuB4B,GACjB7B,IACJA,EAAA,WACE,IACE,MAAMmB,QAAajB,EAAKR,EAAGK,SAAU,CAAE8B,SAEvC,OADAX,EAAaC,GACNJ,EAAcI,EACvB,CAAA,QACEnB,EAAmB,IACrB,CACF,EARA,GASOA,GAET,2BAAMkC,GACJ,GAAsB,oBAAX9C,SAA2BA,OAAO+C,SAAU,OAAO,KAC9D,MAAMC,EAAS,IAAIC,gBAAgBjD,OAAO+C,SAASG,QAC7CT,EAAOO,EAAOG,IAAI,aACxB,IAAKV,EAAM,OAAO,KAGlBO,EAAOI,OAAO,aACd,MAAMC,EAASrD,OAAO+C,SAASO,UAC1BN,EAAOO,WAAa,IAAIP,EAAOO,aAAe,KAC9CvD,OAAO+C,SAASS,MAAQ,IAG7B,OAFAxD,OAAOyD,QAAQC,aAAa,CAAA,EAAI,GAAIL,GAE7BM,KAAKC,iBAAiBnB,EAC/B,EACA,MAAAoB,GACE5D,EAAQ6D,WAAWzD,GACnBJ,EAAQ6D,WAAWzD,GACnBJ,EAAQ6D,WAAWzD,EACrB,EACA0D,gBAAA,MACW9D,EAAQ+D,QAAQ3D,GAE3B4D,SAAA,IACShE,EAAQ+D,QAAQ3D,GAEzB,OAAA6D,GACE,MAAMC,EAAMlE,EAAQ+D,QAAQ3D,GAC5B,IAAM,OAAO8D,EAAM/C,KAAKgD,MAAMD,GAAO,IAAM,CAAA,MAAU,OAAO,IAAM,CACpE,EACA,aAAAE,GACE,MAAMC,EAAIrE,EAAQ+D,QAAQ3D,GAC1B,OAAOiE,EAAI,UAAUA,IAAM,IAC7B,EACAC,gBAzEF,SAAyBC,GACvB,OAAOA,GAAK/C,SACL+C,GAAKC,OACJC,MAAMC,QAAQH,GAAKI,SAAWJ,EAAII,OAAO,IAAInD,SAC9C,sCACT,EAqEEE,gBAEJ,CAmBO,SAASkD,EAAUC,EAAWC,EAAU,IAC7C,KAAKD,GAAeA,aAAqBE,SACvC,MAAM,IAAI5E,MAAM,8CAGlB,MAAMR,QACJA,EAAAqF,kBACAA,EAAAC,qBACAA,EAAAC,SACAA,EAAW,CAAA,EAAAC,MACXA,EAAAjF,UACAA,EAAAkF,UACAA,EAAAC,MACAA,EAAQ,CAAA,GACNP,EAEJ,IAAKnF,EACH,MAAM,IAAIQ,MAAM,kCAOlB,MAAMmF,EAAY,IAAItC,gBAAgBjD,OAAO+C,SAASG,QAChDsC,EAAgBD,EAAUpC,IAAI,aAAeoC,EAAUpC,IAAI,SAAWoC,EAAUpC,IAAI,YACpFsC,EAAiBC,OAAOT,GAAqBO,GAAiB,KAepE,SAASG,KAbT,SAA2BC,GAEzB,IAAKV,GAAwD,IAAhCA,EAAqBW,OAChD,OAAO,EAET,IACE,MAAMC,EAAS,IAAIC,IAAIH,EAAK5F,OAAO+C,SAASiD,QAC5C,OAAOd,EAAqBe,SAASH,EAAOE,OAC9C,CAAA,MACE,OAAO,CACT,CACF,CAGOE,CAAkBT,GACrBzF,OAAO+C,SAASoD,KAAO,IAGzBnG,OAAO+C,SAASoD,KAAOV,EAAeW,WAAW,QAC7CX,EACA,IAAIM,IAAIN,EAAgBzF,OAAO+C,SAASiD,QAAQG,IACtD,CAEA,MAAME,EAAO1G,EAAiB,CAAEC,UAASO,cAGnCmG,EACGnB,EAASoB,OAAS,UADrBD,EAEMnB,EAASqB,UAAY,0BAF3BF,EAGKnB,EAASsB,SAAW,GAGzBC,EAAI,CACRC,gBAAiBrB,EAAMqB,iBAAmB,oBAC1CrE,SAAUgD,EAAMhD,UAAY,WAC5BsE,OAAQtB,EAAMsB,QAAU,UACxBC,eAAgBvB,EAAMuB,gBAAkB,mBACxCC,kBAAmBxB,EAAMwB,mBAAqB,sBAC9CC,aAAczB,EAAMyB,cAAgB,gBACpCC,YAAa1B,EAAM0B,aAAe,eAClCC,UAAW3B,EAAM2B,WAAa,kBAC9BC,UAAW5B,EAAM4B,WAAa,wBAC9BC,UAAW7B,EAAM6B,WAAa,aAC9BC,KAAM9B,EAAM8B,MAAQ,OACpBC,eAAgB/B,EAAM+B,gBAAkB,mBACxCC,aAAchC,EAAMgC,cAAgB,oBACpC7G,UAAW6E,EAAM7E,WAAa,aAC9BiC,YAAa4C,EAAM5C,aAAe,eAClC6E,gBAAiBjC,EAAMiC,iBAAmB,mBAC1CC,cAAelC,EAAMkC,eAAiB,iBACtCC,mBAAoBnC,EAAMmC,oBAAsB,wBAChDC,YAAapC,EAAMoC,aAAe,eAClCC,mBAAoBrC,EAAMqC,oBAAsB,uBAChDC,mBAAoBtC,EAAMsC,oBAAsB,0BAChDC,oBAAqBvC,EAAMuC,qBAAuB,6BAClDC,oBAAqBxC,EAAMwC,qBAAuB,2BAG9CC,EAAO,mHAIHzB,EAAY,aAAaA,WAAmBA,mDAA2D,wCAChFA,8CACEA,4VAS2BI,EAAEC,oHACwBD,EAAEC,2KAG5BD,EAAEpE,iHAC4BoE,EAAEpE,0MAGzDoE,EAAEE,gQAIiCF,EAAEG,yDAG7DxB,IAAcA,EAAU2C,QAAU3C,EAAU4C,SAAY,+SAMrD5C,EAAU2C,OAAS,uIAAyI,uBAC5J3C,EAAU4C,QAAU,+IAAiJ,yCAEvK,oSAOgCvB,EAAEU,4DAElBV,EAAEI,oKAG2BJ,EAAEK,+GACyBL,EAAEK,+IAGhDL,EAAEM,6PAGwBN,EAAEO,yQAIFP,EAAEQ,uLAI/BR,EAAES,qbASOT,EAAEU,4DAElBV,EAAEW,mEACWX,EAAEY,2MAGYZ,EAAEjG,yGACwBiG,EAAEjG,4IAGxBiG,EAAEhE,mHAC4BgE,EAAEhE,kLAGxBgE,EAAEa,+HAC4Bb,EAAEa,4MAGhEb,EAAEc,kWAQTd,EAAEe,2KAG2Bf,EAAEhE,iHAC4BgE,EAAEhE,gLAGxBgE,EAAEa,6HAC4Bb,EAAEa,8MAG9Db,EAAEgB,qNAUvC5C,EAAUoD,UAAYH,EAClB3C,GACFN,EAAUqD,UAAUC,IAAI1C,OAAON,IAIjC,MAAMiD,EAAM,CACVC,MAAO,CACLC,OAAQzD,EAAU0D,cAAc,gBAChChI,OAAQsE,EAAU0D,cAAc,gBAChC/H,UAAWqE,EAAU0D,cAAc,oBACnCd,YAAa5C,EAAU0D,cAAc,uBAEvCC,MAAO,CACLF,OAAQzD,EAAU0D,cAAc,gBAChChI,OAAQsE,EAAU0D,cAAc,gBAChC/H,UAAWqE,EAAU0D,cAAc,oBACnCd,YAAa5C,EAAU0D,cAAc,uBAEvCE,QAAS,CACPH,OAAQzD,EAAU0D,cAAc,eAChChI,OAAQsE,EAAU0D,cAAc,eAChC/H,UAAWqE,EAAU0D,cAAc,mBACnCd,YAAa5C,EAAU0D,cAAc,qBACrCG,WAAY7D,EAAU0D,cAAc,oBACpCI,WAAY9D,EAAU0D,cAAc,oBACpCR,OAAQlD,EAAU0D,cAAc,eAChCP,QAASnD,EAAU0D,cAAc,iBAEnCK,OAAQ,CACNC,eAAgBhE,EAAU0D,cAAc,oBACxCO,eAAgBjE,EAAU0D,cAAc,oBACxCQ,YAAalE,EAAU0D,cAAc,iBACrC/H,UAAWqE,EAAU0D,cAAc,eACnChB,cAAe1C,EAAU0D,cAAc,mBACvCS,qBAAsBnE,EAAU0D,cAAc,2BAC9Cd,YAAa5C,EAAU0D,cAAc,iBACrCU,mBAAoBpE,EAAU0D,cAAc,0BAE9CW,OAAQ,CACNC,gBAAiBtE,EAAU0D,cAAc,gBACzCa,gBAAiBvE,EAAU0D,cAAc,iBAE3Cc,OAAQ,CACNC,kBAAmBzE,EAAU0D,cAAc,yBAE7CgB,MAAO,CACLhJ,OAAQsE,EAAU0D,cAAc,iBAElC/G,QAASqD,EAAU0D,cAAc,oBAInC,SAASiB,EAASC,GAChBC,OAAOC,QAAQvB,EAAIC,OAAOuB,QAAQ,EAAEC,EAAKC,MACnCA,IAAIA,EAAGC,MAAMC,QAAUH,IAAQJ,EAAO,QAAU,UAGtDQ,WAAW,KACT,MAAMC,EAAO9B,EAAIC,MAAMoB,GACjBU,EAAUD,GAAM3B,cAAc,4BACpC,GAAI4B,EACFA,EAAQC,aAAa,WAAY,MACjCD,EAAQE,cACH,CACL,MAAMC,EAAaJ,GAAM3B,cAAc,iBACvC+B,GAAYD,SACd,GACC,GACL,CAEA,SAASE,EAAY/I,EAASgJ,EAAO,QACnC,MAAMV,EAAK1B,EAAI5G,QACVsI,IACLA,EAAGW,YAAcjJ,EACjBsI,EAAGY,UAAY,eAAeF,IAC9BV,EAAGC,MAAMC,QAAU,QACnBF,EAAGM,aAAa,OAAiB,WAATI,EAAoB,QAAU,UACxD,CAEA,SAASG,IACP,MAAMb,EAAK1B,EAAI5G,QACVsI,IACLA,EAAGC,MAAMC,QAAU,OACrB,CAEA,SAASY,EAAiBC,EAAQC,GAChC,IAAKD,EAAQ,OACb,MAAME,EAAWF,EAAOtC,cAAc,aAChCyC,EAAUH,EAAOtC,cAAc,gBAErCsC,EAAOI,WAAaH,EAChBC,IAAUA,EAAShB,MAAMC,QAAUc,EAAU,OAAS,UACtDE,IAASA,EAAQjB,MAAMC,QAAUc,EAAU,eAAiB,OAClE,CASAlK,eAAesK,EAAaC,GAC1BA,GAAGC,mBACHT,IAEA,MAAMvI,EAAWgG,EAAIQ,OAAOC,gBAAgBwC,OAAOC,OAC7CjJ,EAAW+F,EAAIQ,OAAOE,gBAAgBuC,MAE5C,GAAKjJ,GAAaC,EAAlB,CAKAuI,EAAiBxC,EAAIK,QAAQH,QAAQ,GACrC,UACQlC,EAAK9F,MAAM8B,EAAUC,GAC3BkI,EAAY,GAAG9D,EAAEkB,qBAAsB,WACvCsC,WAAWvE,EAAiB,IAC9B,OAASnB,GACPgG,EAAYnE,EAAK9B,gBAAgBC,IAAQkC,EAAEiB,mBAAoB,UAC/DkD,EAAiBxC,EAAIK,QAAQH,QAAQ,EACvC,CAVA,MAFEiC,EAAY,2CAA4C,SAa5D,CAEA3J,eAAe2K,EAAaJ,GAC1BA,GAAGC,mBACHT,IAEA,MAAMrI,EAAQ8F,EAAIQ,OAAOG,aAAasC,OAAOC,OACvCrK,EAlCFmH,EAAIc,OAAOC,iBAAiBqC,QAAgB,OAC5CpD,EAAIc,OAAOE,iBAAiBoC,QAAgB,OACzC,OAkCP,GAAKlJ,EAAL,CAKAsI,EAAiBxC,EAAIK,QAAQlI,QAAQ,GACrC,UACQ6F,EAAK7F,OAAO,CAAE+B,QAAOrB,WAEZ,SAAXA,GACFwK,eAAexJ,QAAQ,cAAeK,GACtCmJ,eAAexJ,QAAQ,eAAgBhB,GACnCmH,EAAIiB,OAAOC,oBAAmBlB,EAAIiB,OAAOC,kBAAkBmB,YAAcnI,GAC7EkH,EAAS,aACTe,EAAY,qCAAsC,YAElDA,EAAY,wDAAyD,UAEzE,OAAShG,GACPgG,EAAYnE,EAAK9B,gBAAgBC,IAAQ,0CAA2C,SACtF,CAAA,QACEqG,EAAiBxC,EAAIK,QAAQlI,QAAQ,EACvC,CAnBA,MAFEgK,EAAY,mCAAoC,SAsBpD,CAEA3J,eAAe8K,EAAgBP,GAC7BA,GAAGC,mBACHT,IAEA,MAAMnI,EAAO4F,EAAIQ,OAAOpI,WAAW6K,OAAOC,OACpC7I,EAAc2F,EAAIQ,OAAOrB,eAAe8D,MACxC/D,EAAkBc,EAAIQ,OAAOI,sBAAsBqC,MACnD/I,EAAQmJ,eAAe1H,QAAQ,eAErC,IAAKzB,EAGH,OAFAiI,EAAY,8DAA+D,eAC3Ef,EAAS,UAIX,GAAKhH,GAASC,EAId,GAAIA,IAAgB6E,EAApB,CAKAsD,EAAiBxC,EAAIK,QAAQjI,WAAW,GACxC,UACQ4F,EAAK7D,cAAc,CAAED,QAAOE,OAAMC,gBACxCgJ,eAAe5H,WAAW,eAC1B4H,eAAe5H,WAAW,gBAC1B0G,EAAY9D,EAAEkB,mBAAoB,WAClCsC,WAAWvE,EAAiB,IAC9B,OAASnB,GACPgG,EAAYnE,EAAK9B,gBAAgBC,IAAQ,gCAAiC,UAC1EqG,EAAiBxC,EAAIK,QAAQjI,WAAW,EAC1C,CAZA,MAFE+J,EAAY9D,EAAEoB,oBAAqB,eAJnC0C,EAAY9D,EAAEmB,oBAAqB,SAmBvC,CAEAhH,eAAe+K,EAAkBR,GAC/BA,GAAGC,mBACHT,IAEA,MAAMlI,EAAc2F,EAAIQ,OAAOnB,aAAa4D,MACtC/D,EAAkBc,EAAIQ,OAAOK,oBAAoBoC,MACjDzI,EAAQ6I,eAAe1H,QAAQ,eAErC,IAAKnB,EAGH,OAFA2H,EAAY,qDAAsD,eAClEf,EAAS,UAGX,GAAK/G,EAIL,GAAIA,IAAgB6E,EAApB,CAKAsD,EAAiBxC,EAAIK,QAAQhB,aAAa,GAC1C,UACQrB,EAAKzD,eAAe,CAAEC,QAAOH,gBACnCgJ,eAAe5H,WAAW,eAC1B0G,EAAY9D,EAAEkB,mBAAoB,WAClCsC,WAAWvE,EAAiB,IAC9B,OAASnB,GACPgG,EAAYnE,EAAK9B,gBAAgBC,IAAQ,2BAA4B,UACrEqG,EAAiBxC,EAAIK,QAAQhB,aAAa,EAC5C,CAXA,MAFE8C,EAAY9D,EAAEoB,oBAAqB,eAJnC0C,EAAY,+BAAgC,SAkBhD,CAGA,SAASqB,EAAWT,GAClBA,GAAGC,mBACHT,IACAnB,EAAS,SACX,CACA,SAASqC,IACPlB,IACAnB,EAAS,SACX,CACA,SAASsC,IACPnB,IACAnB,EAAS,SACX,CA+DA,OA5CApB,EAAII,MAAMF,QAAQyD,iBAAiB,SAAUb,GAC7C9C,EAAII,MAAMjI,QAAQwL,iBAAiB,SAAUR,GAC7CnD,EAAII,MAAMhI,WAAWuL,iBAAiB,SAAUL,GAChDtD,EAAII,MAAMf,aAAasE,iBAAiB,SAAUJ,GAClDvD,EAAImB,MAAMhJ,QAAQwL,iBAAiB,QAASH,GAC5CxD,EAAIK,QAAQC,YAAYqD,iBAAiB,QAASF,GAClDzD,EAAIK,QAAQE,YAAYoD,iBAAiB,QAASD,GArB5C1G,GAAW2C,QAAUK,EAAIK,QAAQV,QACnCK,EAAIK,QAAQV,OAAOgE,iBAAiB,QAAUZ,IAC5CA,GAAGC,mBACHhG,EAAU2C,OAAOiE,UAAU,CAAEnH,YAAWuB,OAAM6F,SAAUvG,EAAiB6E,kBAGzEnF,GAAW4C,SAAWI,EAAIK,QAAQT,SACpCI,EAAIK,QAAQT,QAAQ+D,iBAAiB,QAAUZ,IAC7CA,GAAGC,mBACHhG,EAAU4C,QAAQgE,UAAU,CAAEnH,YAAWuB,OAAM6F,SAAUvG,EAAiB6E,kBAiBhF,WAEE,MAAMxH,EAAS,IAAIC,gBAAgBjD,OAAO+C,SAASG,QAC7CiJ,EAAanJ,EAAOG,IAAI,eAE9B,GAAIgJ,EAAY,CACdT,eAAexJ,QAAQ,cAAeiK,GAGtCnJ,EAAOI,OAAO,eACd,MAAMC,EAASL,EAAOO,WAClB,GAAGvD,OAAO+C,SAASO,YAAYN,EAAOO,aACtCvD,OAAO+C,SAASO,SAKpB,OAJAtD,OAAOyD,QAAQC,aAAa,CAAA,EAAI,GAAIL,GAEpCoG,EAAS,oBACTe,EAAY,gCAAiC,OAE/C,CAGA,MAAM4B,EAAaV,eAAe1H,QAAQ,eAC1C,GAAIoI,EAGF,OAFI/D,EAAIiB,OAAOC,oBAAmBlB,EAAIiB,OAAOC,kBAAkBmB,YAAc0B,QAC7E3C,EAAS,aAKXA,EAAS,SACX,CA9BA,GAiCO,CACL,OAAA4C,GACEhE,EAAII,MAAMF,QAAQ+D,oBAAoB,SAAUnB,GAChD9C,EAAII,MAAMjI,QAAQ8L,oBAAoB,SAAUd,GAChDnD,EAAII,MAAMhI,WAAW6L,oBAAoB,SAAUX,GACnDtD,EAAII,MAAMf,aAAa4E,oBAAoB,SAAUV,GACrDvD,EAAImB,MAAMhJ,QAAQ8L,oBAAoB,QAAST,GAC/CxD,EAAIK,QAAQC,YAAY2D,oBAAoB,QAASR,GACrDzD,EAAIK,QAAQE,YAAY0D,oBAAoB,QAASP,GACjD1G,GAAW2C,QAAUK,EAAIK,QAAQV,QACnCK,EAAIK,QAAQV,OAAOuE,YAAYlE,EAAIK,QAAQV,OAAOwE,WAAU,IAE1DnH,GAAW4C,SAAWI,EAAIK,QAAQT,SACpCI,EAAIK,QAAQT,QAAQsE,YAAYlE,EAAIK,QAAQT,QAAQuE,WAAU,IAEhE1H,EAAUoD,UAAY,EACxB,EAEJ,CAEA,MAAAuE,EAAe,CACb5H,YACAlF"}
|
package/dist/charts.cjs.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("./chunks/exportChart-Dk8D_du5.js"),e=require("./chunks/View-Yazho7OL.js"),s=require("./chunks/Collection-BZlmtcuL.js"),i=require("./chunks/WebApp-irKlhuFX.js"),r=require("./chunks/version-DtqCY0ZY.js");class CircularProgress extends e.View{constructor(t={}){super({className:`circular-progress ${t.className||""}`,...t}),this.SIZE_PRESETS={xs:40,sm:60,md:80,lg:120,xl:180},this.STROKE_PRESETS={xs:4,sm:6,md:8,lg:12,xl:16},this.value=void 0!==t.value?t.value:0,this.min=void 0!==t.min?t.min:0,this.max=void 0!==t.max?t.max:100,this.sizePreset="string"==typeof t.size&&this.SIZE_PRESETS[t.size]?t.size:null,this.size=this.resolveSize(void 0!==t.size?t.size:"md"),this.strokeWidth="auto"===t.strokeWidth||void 0===t.strokeWidth?this.getAutoStrokeWidth(t.size):t.strokeWidth,this.theme=t.theme||"basic",this.variant=t.variant||"default",this.color=t.color,this.trackColor=t.trackColor,this.textColor=t.textColor,this.gradientColors=t.gradientColors||null,this.applyTheme(),this.applyVariant(),this.rotation=void 0!==t.rotation?t.rotation:-90,this.gap=t.gap||0,this.showValue=!1!==t.showValue,this.valueFormat=t.valueFormat||"percentage",this.valueFormatter=t.valueFormatter||null,this.label=t.label||null,this.labelHtml=t.labelHtml||null,this.icon=t.icon||null,this.animate=!1!==t.animate,this.animationDuration=t.animationDuration||600,this.animationEasing=t.animationEasing||"ease-out",this.rounded=!1!==t.rounded,this.shadow=t.shadow||!1,this.clickable=t.clickable||!1,this.tooltip=t.tooltip||null,this.tooltipPlacement=t.tooltipPlacement||"top",this.segments=t.segments||null,this.segmentGap=t.segmentGap||2,this.dataFormatter=s.dataFormatter,this.svg=null,this.centerElement=null,this.popover=null,this.gradientId=`gradient-${Math.random().toString(36).substr(2,9)}`}resolveSize(t){return"string"==typeof t&&this.SIZE_PRESETS[t]?this.SIZE_PRESETS[t]:"number"==typeof t?t:this.SIZE_PRESETS.md}getAutoStrokeWidth(t){if("string"==typeof t&&this.STROKE_PRESETS[t])return this.STROKE_PRESETS[t];const e=this.resolveSize(t);return e<=40?4:e<=60?6:e<=80?8:e<=120?12:16}applyTheme(){const t={basic:{trackColor:"#e9ecef",textColor:null,backgroundColor:null},shadowed:{trackColor:"#d1d5db",textColor:null,backgroundColor:null,shadow:!0},dark:{trackColor:"#374151",textColor:"#e5e7eb",backgroundColor:"#1f2937"},light:{trackColor:"#f3f4f6",textColor:"#111827",backgroundColor:"#ffffff"}},e=t[this.theme]||t.basic;this.trackColor||(this.trackColor=e.trackColor),!this.textColor&&e.textColor&&(this.textColor=e.textColor),e.shadow&&!1===this.shadow&&(this.shadow=e.shadow)}applyVariant(){const t={success:{color:"#198754",trackColor:"rgba(25, 135, 84, 0.1)"},danger:{color:"#dc3545",trackColor:"rgba(220, 53, 69, 0.1)"},warning:{color:"#ffc107",trackColor:"rgba(255, 193, 7, 0.1)"},info:{color:"#0dcaf0",trackColor:"rgba(13, 202, 240, 0.1)"},default:{color:"#0d6efd"}};if(t[this.variant]){const e=t[this.variant];this.color||(this.color=e.color),e.trackColor&&this.trackColor===this.applyTheme.trackColor&&(this.trackColor=e.trackColor)}this.color||(this.color="#0d6efd")}getTemplate(){const t=this.sizePreset?`circular-progress-${this.sizePreset}`:"",e="default"!==this.variant?`circular-progress-${this.variant}`:"",s="basic"!==this.theme?`circular-progress-theme-${this.theme}`:"",i=this.clickable?"circular-progress-clickable":"",r=this.shadow?"circular-progress-shadow":"",o=this.textColor?`color: ${this.textColor};`:"";return`\n <div class="circular-progress-container ${t} ${e} ${s} ${i} ${r}"\n style="width: ${this.size}px; height: ${this.size}px;">\n <svg class="circular-progress-svg" \n width="${this.size}" \n height="${this.size}"\n viewBox="0 0 ${this.size} ${this.size}">\n </svg>\n <div class="circular-progress-center" style="${o}">\n <div class="circular-progress-content"></div>\n </div>\n </div>\n `}async onAfterRender(){this.svg=this.element.querySelector(".circular-progress-svg"),this.centerElement=this.element.querySelector(".circular-progress-content"),this.containerElement=this.element.querySelector(".circular-progress-container"),this.renderProgress(),this.renderCenterContent(),this.clickable&&this.setupClickHandler(),this.tooltip&&this.clickable&&this.setupTooltip()}renderProgress(){if(!this.svg)return;this.svg.innerHTML="";const t=this.size/2,e=(this.size-this.strokeWidth)/2,s=2*Math.PI*e;this.gradientColors&&this.gradientColors.length>1&&this.createGradient(),this.segments&&Array.isArray(this.segments)&&this.segments.length>0?this.renderSegments(t,e,s):this.renderSingleProgress(t,e,s)}renderSingleProgress(t,e,s){const i=(this.gap>0?360-this.gap:360)/360*s,r=this.createCircle(t,e,{stroke:this.trackColor,strokeWidth:this.strokeWidth,fill:"none",strokeLinecap:this.rounded?"round":"butt",strokeDasharray:this.gap>0?`${i} ${s}`:"none",transform:`rotate(${this.rotation} ${t} ${t})`});this.svg.appendChild(r);const o=i-this.getPercentage()/100*i,a=this.gradientColors?`url(#${this.gradientId})`:this.color,n=this.createCircle(t,e,{stroke:a,strokeWidth:this.strokeWidth,fill:"none",strokeLinecap:this.rounded?"round":"butt",strokeDasharray:`${i} ${s}`,strokeDashoffset:this.animate?i:o,transform:`rotate(${this.rotation} ${t} ${t})`,class:"circular-progress-bar"});this.svg.appendChild(n),this.animate&&this.animateProgress(n,o)}renderSegments(t,e,s){const i=(this.gap>0?360-this.gap:360)/360*s,r=this.createCircle(t,e,{stroke:this.trackColor,strokeWidth:this.strokeWidth,fill:"none",strokeLinecap:this.rounded?"round":"butt",strokeDasharray:this.gap>0?`${i} ${s}`:"none",transform:`rotate(${this.rotation} ${t} ${t})`});this.svg.appendChild(r),this.segments.reduce((t,e)=>t+(e.value||0),0)>this.max&&console.warn("CircularProgress: Segment total exceeds max value. Clamping to max.");let o=0;this.segments.forEach((r,a)=>{const n=(r.value||0)/(this.max-this.min)*100/100*i,h=this.segmentGap/360*s;if(n>0){const l=this.createCircle(t,e,{stroke:r.color||this.color,strokeWidth:this.strokeWidth,fill:"none",strokeLinecap:this.rounded?"round":"butt",strokeDasharray:`${n} ${s}`,strokeDashoffset:this.animate?i:-o,transform:`rotate(${this.rotation} ${t} ${t})`,class:`circular-progress-segment circular-progress-segment-${a}`,"data-segment-index":a});this.svg.appendChild(l),this.animate&&this.animateProgress(l,-o,100*a),o+=n+h}})}createCircle(t,e,s={}){const i=document.createElementNS("http://www.w3.org/2000/svg","circle");return i.setAttribute("cx",t),i.setAttribute("cy",t),i.setAttribute("r",e),Object.entries(s).forEach(([t,e])=>{"strokeWidth"===t?i.setAttribute("stroke-width",e):"strokeLinecap"===t?i.setAttribute("stroke-linecap",e):"strokeDasharray"===t?i.setAttribute("stroke-dasharray",e):"strokeDashoffset"===t?i.setAttribute("stroke-dashoffset",e):i.setAttribute(t,e)}),i}createGradient(){const t=document.createElementNS("http://www.w3.org/2000/svg","defs"),e=document.createElementNS("http://www.w3.org/2000/svg","linearGradient");e.setAttribute("id",this.gradientId),e.setAttribute("x1","0%"),e.setAttribute("y1","0%"),e.setAttribute("x2","100%"),e.setAttribute("y2","100%"),this.gradientColors.forEach((t,s)=>{const i=document.createElementNS("http://www.w3.org/2000/svg","stop"),r=s/(this.gradientColors.length-1)*100;i.setAttribute("offset",`${r}%`),i.setAttribute("stop-color",t),e.appendChild(i)}),t.appendChild(e),this.svg.appendChild(t)}animateProgress(t,e,s=0){setTimeout(()=>{t.style.transition=`stroke-dashoffset ${this.animationDuration}ms ${this.animationEasing}`,t.style.strokeDashoffset=e},s)}renderCenterContent(){if(this.centerElement)if(this.labelHtml)this.centerElement.innerHTML=this.labelHtml;else if(this.icon)this.centerElement.innerHTML=`<i class="${this.icon}"></i>`;else if(this.showValue){let t=`<div class="circular-progress-value">${this.getFormattedValue()}</div>`;this.label&&(t+=`<div class="circular-progress-label">${this.label}</div>`),this.centerElement.innerHTML=t}}getFormattedValue(){const t=this.value,e=this.min,s=this.max;if(this.valueFormatter&&"function"==typeof this.valueFormatter)return this.valueFormatter(t,e,s);switch(this.valueFormat){case"percentage":return`${Math.round(this.getPercentage())}%`;case"fraction":return`${t}/${s}`;case"value":return t.toString();default:if(this.dataFormatter)try{return this.dataFormatter.pipe(t,this.valueFormat)}catch(i){return console.warn("CircularProgress: DataFormatter error, falling back to percentage",i),`${Math.round(this.getPercentage())}%`}return`${Math.round(this.getPercentage())}%`}}getPercentage(){const t=this.max-this.min;return 0===t?0:(this.value-this.min)/t*100}setupClickHandler(){this.containerElement&&(this.containerElement.style.cursor="pointer",this.containerElement.addEventListener("click",t=>{t.preventDefault(),t.stopPropagation();const e=this.getPercentage();this.emit("progress:clicked",{value:this.value,percentage:e,min:this.min,max:this.max}),this.tooltip&&this.togglePopover()}))}setupTooltip(){}togglePopover(){if(this.containerElement&&void 0!==window.bootstrap){if(!this.popover){const t=this.getTooltipContent(),e="object"==typeof this.tooltip&&this.tooltip.title?this.tooltip.title:void 0,s={content:t,html:!0,placement:this.tooltipPlacement,trigger:"manual",container:"body"};e&&(s.title=e),this.popover=new window.bootstrap.Popover(this.containerElement,s)}window.bootstrap.Popover.getInstance(this.containerElement)&&this.containerElement.getAttribute("aria-describedby")?this.popover.hide():(this.popover.setContent({".popover-body":this.getTooltipContent()}),this.popover.show())}else console.warn("CircularProgress: Bootstrap is required for tooltip support")}getTooltipContent(){return"function"==typeof this.tooltip?this.tooltip(this.value,{min:this.min,max:this.max,percentage:this.getPercentage()}):"object"==typeof this.tooltip?this.tooltip.html||this.tooltip.content||"":this.tooltip||""}setValue(t,e=!0){if(this.value,this.value=Math.max(this.min,Math.min(this.max,t)),this.renderCenterContent(),this.svg&&!this.segments){const t=this.svg.querySelector(".circular-progress-bar");if(t){const s=this.size/2-this.strokeWidth/2,i=2*Math.PI*s,r=(this.gap>0?360-this.gap:360)/360*i,o=r-this.getPercentage()/100*r;e?(t.style.transition=`stroke-dashoffset ${this.animationDuration}ms ${this.animationEasing}`,t.style.strokeDashoffset=o):(t.style.transition="none",t.style.strokeDashoffset=o)}}else{const t=this.animate;this.animate=e,this.renderProgress(),this.animate=t}}setRange(t,e){this.min=t,this.max=e,this.renderProgress(),this.renderCenterContent()}increment(t=1){this.setValue(this.value+t)}decrement(t=1){this.setValue(this.value-t)}setColor(t){if(this.color=t,this.gradientColors=null,this.svg&&!this.segments){const e=this.svg.querySelector(".circular-progress-bar");e&&e.setAttribute("stroke",t)}else this.renderProgress()}setGradient(t){Array.isArray(t)&&t.length>1&&(this.gradientColors=t,this.gradientId=`gradient-${Math.random().toString(36).substr(2,9)}`,this.renderProgress())}setSize(t){this.containerElement&&this.sizePreset&&this.containerElement.classList.remove(`circular-progress-${this.sizePreset}`),this.sizePreset="string"==typeof t&&this.SIZE_PRESETS[t]?t:null,this.size=this.resolveSize(t),this.strokeWidth=this.getAutoStrokeWidth(t),this.containerElement&&(this.containerElement.style.width=`${this.size}px`,this.containerElement.style.height=`${this.size}px`,this.sizePreset&&this.containerElement.classList.add(`circular-progress-${this.sizePreset}`)),this.svg&&(this.svg.setAttribute("width",this.size),this.svg.setAttribute("height",this.size),this.svg.setAttribute("viewBox",`0 0 ${this.size} ${this.size}`)),this.renderProgress()}animateTo(t,e=1e3){const s=this.value,i=t-s,r=performance.now(),o=a=>{const n=a-r,h=Math.min(n/e,1),l=1-Math.pow(1-h,3),c=s+i*l;this.setValue(c,!1),h<1?requestAnimationFrame(o):this.setValue(t,!1)};requestAnimationFrame(o)}pulse(){this.containerElement&&(this.containerElement.style.animation="none",setTimeout(()=>{this.containerElement.style.animation="circular-progress-pulse 0.5s ease-out"},10),setTimeout(()=>{this.containerElement.style.animation=""},500))}complete(){this.variant="success",this.applyVariant(),this.setValue(this.max),this.pulse()}reset(){this.setValue(this.min)}hide(){this.element&&(this.element.style.display="none")}show(){this.element&&(this.element.style.display="")}getValue(){return this.value}getPercentageValue(){return this.getPercentage()}async onBeforeDestroy(){this.popover&&(this.popover.dispose(),this.popover=null),await super.onBeforeDestroy()}}exports.MetricsChart=t.MetricsChart,exports.MetricsMiniChart=t.MetricsMiniChart,exports.MetricsMiniChartWidget=t.MetricsMiniChartWidget,exports.MiniChart=t.MiniChart,exports.PieChart=t.PieChart,exports.SeriesChart=t.SeriesChart,exports.exportChartPng=t.exportChartPng,exports.WebApp=i.WebApp,exports.BUILD_TIME=r.BUILD_TIME,exports.VERSION=r.VERSION,exports.VERSION_INFO=r.VERSION_INFO,exports.VERSION_MAJOR=r.VERSION_MAJOR,exports.VERSION_MINOR=r.VERSION_MINOR,exports.VERSION_REVISION=r.VERSION_REVISION,exports.CircularProgress=CircularProgress;
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("./chunks/exportChart-kQ-we4Cp.js"),e=require("./chunks/View-Yazho7OL.js"),s=require("./chunks/Collection-BZlmtcuL.js"),i=require("./chunks/WebApp-irKlhuFX.js"),r=require("./chunks/version-BURwX10Q.js");class CircularProgress extends e.View{constructor(t={}){super({className:`circular-progress ${t.className||""}`,...t}),this.SIZE_PRESETS={xs:40,sm:60,md:80,lg:120,xl:180},this.STROKE_PRESETS={xs:4,sm:6,md:8,lg:12,xl:16},this.value=void 0!==t.value?t.value:0,this.min=void 0!==t.min?t.min:0,this.max=void 0!==t.max?t.max:100,this.sizePreset="string"==typeof t.size&&this.SIZE_PRESETS[t.size]?t.size:null,this.size=this.resolveSize(void 0!==t.size?t.size:"md"),this.strokeWidth="auto"===t.strokeWidth||void 0===t.strokeWidth?this.getAutoStrokeWidth(t.size):t.strokeWidth,this.theme=t.theme||"basic",this.variant=t.variant||"default",this.color=t.color,this.trackColor=t.trackColor,this.textColor=t.textColor,this.gradientColors=t.gradientColors||null,this.applyTheme(),this.applyVariant(),this.rotation=void 0!==t.rotation?t.rotation:-90,this.gap=t.gap||0,this.showValue=!1!==t.showValue,this.valueFormat=t.valueFormat||"percentage",this.valueFormatter=t.valueFormatter||null,this.label=t.label||null,this.labelHtml=t.labelHtml||null,this.icon=t.icon||null,this.animate=!1!==t.animate,this.animationDuration=t.animationDuration||600,this.animationEasing=t.animationEasing||"ease-out",this.rounded=!1!==t.rounded,this.shadow=t.shadow||!1,this.clickable=t.clickable||!1,this.tooltip=t.tooltip||null,this.tooltipPlacement=t.tooltipPlacement||"top",this.segments=t.segments||null,this.segmentGap=t.segmentGap||2,this.dataFormatter=s.dataFormatter,this.svg=null,this.centerElement=null,this.popover=null,this.gradientId=`gradient-${Math.random().toString(36).substr(2,9)}`}resolveSize(t){return"string"==typeof t&&this.SIZE_PRESETS[t]?this.SIZE_PRESETS[t]:"number"==typeof t?t:this.SIZE_PRESETS.md}getAutoStrokeWidth(t){if("string"==typeof t&&this.STROKE_PRESETS[t])return this.STROKE_PRESETS[t];const e=this.resolveSize(t);return e<=40?4:e<=60?6:e<=80?8:e<=120?12:16}applyTheme(){const t={basic:{trackColor:"#e9ecef",textColor:null,backgroundColor:null},shadowed:{trackColor:"#d1d5db",textColor:null,backgroundColor:null,shadow:!0},dark:{trackColor:"#374151",textColor:"#e5e7eb",backgroundColor:"#1f2937"},light:{trackColor:"#f3f4f6",textColor:"#111827",backgroundColor:"#ffffff"}},e=t[this.theme]||t.basic;this.trackColor||(this.trackColor=e.trackColor),!this.textColor&&e.textColor&&(this.textColor=e.textColor),e.shadow&&!1===this.shadow&&(this.shadow=e.shadow)}applyVariant(){const t={success:{color:"#198754",trackColor:"rgba(25, 135, 84, 0.1)"},danger:{color:"#dc3545",trackColor:"rgba(220, 53, 69, 0.1)"},warning:{color:"#ffc107",trackColor:"rgba(255, 193, 7, 0.1)"},info:{color:"#0dcaf0",trackColor:"rgba(13, 202, 240, 0.1)"},default:{color:"#0d6efd"}};if(t[this.variant]){const e=t[this.variant];this.color||(this.color=e.color),e.trackColor&&this.trackColor===this.applyTheme.trackColor&&(this.trackColor=e.trackColor)}this.color||(this.color="#0d6efd")}getTemplate(){const t=this.sizePreset?`circular-progress-${this.sizePreset}`:"",e="default"!==this.variant?`circular-progress-${this.variant}`:"",s="basic"!==this.theme?`circular-progress-theme-${this.theme}`:"",i=this.clickable?"circular-progress-clickable":"",r=this.shadow?"circular-progress-shadow":"",o=this.textColor?`color: ${this.textColor};`:"";return`\n <div class="circular-progress-container ${t} ${e} ${s} ${i} ${r}"\n style="width: ${this.size}px; height: ${this.size}px;">\n <svg class="circular-progress-svg" \n width="${this.size}" \n height="${this.size}"\n viewBox="0 0 ${this.size} ${this.size}">\n </svg>\n <div class="circular-progress-center" style="${o}">\n <div class="circular-progress-content"></div>\n </div>\n </div>\n `}async onAfterRender(){this.svg=this.element.querySelector(".circular-progress-svg"),this.centerElement=this.element.querySelector(".circular-progress-content"),this.containerElement=this.element.querySelector(".circular-progress-container"),this.renderProgress(),this.renderCenterContent(),this.clickable&&this.setupClickHandler(),this.tooltip&&this.clickable&&this.setupTooltip()}renderProgress(){if(!this.svg)return;this.svg.innerHTML="";const t=this.size/2,e=(this.size-this.strokeWidth)/2,s=2*Math.PI*e;this.gradientColors&&this.gradientColors.length>1&&this.createGradient(),this.segments&&Array.isArray(this.segments)&&this.segments.length>0?this.renderSegments(t,e,s):this.renderSingleProgress(t,e,s)}renderSingleProgress(t,e,s){const i=(this.gap>0?360-this.gap:360)/360*s,r=this.createCircle(t,e,{stroke:this.trackColor,strokeWidth:this.strokeWidth,fill:"none",strokeLinecap:this.rounded?"round":"butt",strokeDasharray:this.gap>0?`${i} ${s}`:"none",transform:`rotate(${this.rotation} ${t} ${t})`});this.svg.appendChild(r);const o=i-this.getPercentage()/100*i,a=this.gradientColors?`url(#${this.gradientId})`:this.color,n=this.createCircle(t,e,{stroke:a,strokeWidth:this.strokeWidth,fill:"none",strokeLinecap:this.rounded?"round":"butt",strokeDasharray:`${i} ${s}`,strokeDashoffset:this.animate?i:o,transform:`rotate(${this.rotation} ${t} ${t})`,class:"circular-progress-bar"});this.svg.appendChild(n),this.animate&&this.animateProgress(n,o)}renderSegments(t,e,s){const i=(this.gap>0?360-this.gap:360)/360*s,r=this.createCircle(t,e,{stroke:this.trackColor,strokeWidth:this.strokeWidth,fill:"none",strokeLinecap:this.rounded?"round":"butt",strokeDasharray:this.gap>0?`${i} ${s}`:"none",transform:`rotate(${this.rotation} ${t} ${t})`});this.svg.appendChild(r),this.segments.reduce((t,e)=>t+(e.value||0),0)>this.max&&console.warn("CircularProgress: Segment total exceeds max value. Clamping to max.");let o=0;this.segments.forEach((r,a)=>{const n=(r.value||0)/(this.max-this.min)*100/100*i,h=this.segmentGap/360*s;if(n>0){const l=this.createCircle(t,e,{stroke:r.color||this.color,strokeWidth:this.strokeWidth,fill:"none",strokeLinecap:this.rounded?"round":"butt",strokeDasharray:`${n} ${s}`,strokeDashoffset:this.animate?i:-o,transform:`rotate(${this.rotation} ${t} ${t})`,class:`circular-progress-segment circular-progress-segment-${a}`,"data-segment-index":a});this.svg.appendChild(l),this.animate&&this.animateProgress(l,-o,100*a),o+=n+h}})}createCircle(t,e,s={}){const i=document.createElementNS("http://www.w3.org/2000/svg","circle");return i.setAttribute("cx",t),i.setAttribute("cy",t),i.setAttribute("r",e),Object.entries(s).forEach(([t,e])=>{"strokeWidth"===t?i.setAttribute("stroke-width",e):"strokeLinecap"===t?i.setAttribute("stroke-linecap",e):"strokeDasharray"===t?i.setAttribute("stroke-dasharray",e):"strokeDashoffset"===t?i.setAttribute("stroke-dashoffset",e):i.setAttribute(t,e)}),i}createGradient(){const t=document.createElementNS("http://www.w3.org/2000/svg","defs"),e=document.createElementNS("http://www.w3.org/2000/svg","linearGradient");e.setAttribute("id",this.gradientId),e.setAttribute("x1","0%"),e.setAttribute("y1","0%"),e.setAttribute("x2","100%"),e.setAttribute("y2","100%"),this.gradientColors.forEach((t,s)=>{const i=document.createElementNS("http://www.w3.org/2000/svg","stop"),r=s/(this.gradientColors.length-1)*100;i.setAttribute("offset",`${r}%`),i.setAttribute("stop-color",t),e.appendChild(i)}),t.appendChild(e),this.svg.appendChild(t)}animateProgress(t,e,s=0){setTimeout(()=>{t.style.transition=`stroke-dashoffset ${this.animationDuration}ms ${this.animationEasing}`,t.style.strokeDashoffset=e},s)}renderCenterContent(){if(this.centerElement)if(this.labelHtml)this.centerElement.innerHTML=this.labelHtml;else if(this.icon)this.centerElement.innerHTML=`<i class="${this.icon}"></i>`;else if(this.showValue){let t=`<div class="circular-progress-value">${this.getFormattedValue()}</div>`;this.label&&(t+=`<div class="circular-progress-label">${this.label}</div>`),this.centerElement.innerHTML=t}}getFormattedValue(){const t=this.value,e=this.min,s=this.max;if(this.valueFormatter&&"function"==typeof this.valueFormatter)return this.valueFormatter(t,e,s);switch(this.valueFormat){case"percentage":return`${Math.round(this.getPercentage())}%`;case"fraction":return`${t}/${s}`;case"value":return t.toString();default:if(this.dataFormatter)try{return this.dataFormatter.pipe(t,this.valueFormat)}catch(i){return console.warn("CircularProgress: DataFormatter error, falling back to percentage",i),`${Math.round(this.getPercentage())}%`}return`${Math.round(this.getPercentage())}%`}}getPercentage(){const t=this.max-this.min;return 0===t?0:(this.value-this.min)/t*100}setupClickHandler(){this.containerElement&&(this.containerElement.style.cursor="pointer",this.containerElement.addEventListener("click",t=>{t.preventDefault(),t.stopPropagation();const e=this.getPercentage();this.emit("progress:clicked",{value:this.value,percentage:e,min:this.min,max:this.max}),this.tooltip&&this.togglePopover()}))}setupTooltip(){}togglePopover(){if(this.containerElement&&void 0!==window.bootstrap){if(!this.popover){const t=this.getTooltipContent(),e="object"==typeof this.tooltip&&this.tooltip.title?this.tooltip.title:void 0,s={content:t,html:!0,placement:this.tooltipPlacement,trigger:"manual",container:"body"};e&&(s.title=e),this.popover=new window.bootstrap.Popover(this.containerElement,s)}window.bootstrap.Popover.getInstance(this.containerElement)&&this.containerElement.getAttribute("aria-describedby")?this.popover.hide():(this.popover.setContent({".popover-body":this.getTooltipContent()}),this.popover.show())}else console.warn("CircularProgress: Bootstrap is required for tooltip support")}getTooltipContent(){return"function"==typeof this.tooltip?this.tooltip(this.value,{min:this.min,max:this.max,percentage:this.getPercentage()}):"object"==typeof this.tooltip?this.tooltip.html||this.tooltip.content||"":this.tooltip||""}setValue(t,e=!0){if(this.value,this.value=Math.max(this.min,Math.min(this.max,t)),this.renderCenterContent(),this.svg&&!this.segments){const t=this.svg.querySelector(".circular-progress-bar");if(t){const s=this.size/2-this.strokeWidth/2,i=2*Math.PI*s,r=(this.gap>0?360-this.gap:360)/360*i,o=r-this.getPercentage()/100*r;e?(t.style.transition=`stroke-dashoffset ${this.animationDuration}ms ${this.animationEasing}`,t.style.strokeDashoffset=o):(t.style.transition="none",t.style.strokeDashoffset=o)}}else{const t=this.animate;this.animate=e,this.renderProgress(),this.animate=t}}setRange(t,e){this.min=t,this.max=e,this.renderProgress(),this.renderCenterContent()}increment(t=1){this.setValue(this.value+t)}decrement(t=1){this.setValue(this.value-t)}setColor(t){if(this.color=t,this.gradientColors=null,this.svg&&!this.segments){const e=this.svg.querySelector(".circular-progress-bar");e&&e.setAttribute("stroke",t)}else this.renderProgress()}setGradient(t){Array.isArray(t)&&t.length>1&&(this.gradientColors=t,this.gradientId=`gradient-${Math.random().toString(36).substr(2,9)}`,this.renderProgress())}setSize(t){this.containerElement&&this.sizePreset&&this.containerElement.classList.remove(`circular-progress-${this.sizePreset}`),this.sizePreset="string"==typeof t&&this.SIZE_PRESETS[t]?t:null,this.size=this.resolveSize(t),this.strokeWidth=this.getAutoStrokeWidth(t),this.containerElement&&(this.containerElement.style.width=`${this.size}px`,this.containerElement.style.height=`${this.size}px`,this.sizePreset&&this.containerElement.classList.add(`circular-progress-${this.sizePreset}`)),this.svg&&(this.svg.setAttribute("width",this.size),this.svg.setAttribute("height",this.size),this.svg.setAttribute("viewBox",`0 0 ${this.size} ${this.size}`)),this.renderProgress()}animateTo(t,e=1e3){const s=this.value,i=t-s,r=performance.now(),o=a=>{const n=a-r,h=Math.min(n/e,1),l=1-Math.pow(1-h,3),c=s+i*l;this.setValue(c,!1),h<1?requestAnimationFrame(o):this.setValue(t,!1)};requestAnimationFrame(o)}pulse(){this.containerElement&&(this.containerElement.style.animation="none",setTimeout(()=>{this.containerElement.style.animation="circular-progress-pulse 0.5s ease-out"},10),setTimeout(()=>{this.containerElement.style.animation=""},500))}complete(){this.variant="success",this.applyVariant(),this.setValue(this.max),this.pulse()}reset(){this.setValue(this.min)}hide(){this.element&&(this.element.style.display="none")}show(){this.element&&(this.element.style.display="")}getValue(){return this.value}getPercentageValue(){return this.getPercentage()}async onBeforeDestroy(){this.popover&&(this.popover.dispose(),this.popover=null),await super.onBeforeDestroy()}}exports.MetricsChart=t.MetricsChart,exports.MetricsMiniChart=t.MetricsMiniChart,exports.MetricsMiniChartWidget=t.MetricsMiniChartWidget,exports.MiniChart=t.MiniChart,exports.PieChart=t.PieChart,exports.SeriesChart=t.SeriesChart,exports.exportChartPng=t.exportChartPng,exports.WebApp=i.WebApp,exports.BUILD_TIME=r.BUILD_TIME,exports.VERSION=r.VERSION,exports.VERSION_INFO=r.VERSION_INFO,exports.VERSION_MAJOR=r.VERSION_MAJOR,exports.VERSION_MINOR=r.VERSION_MINOR,exports.VERSION_REVISION=r.VERSION_REVISION,exports.CircularProgress=CircularProgress;
|
|
2
2
|
//# sourceMappingURL=charts.cjs.js.map
|
package/dist/charts.es.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{M as t,a as e,b as s,c as i,P as r,S as o,e as a}from"./chunks/exportChart-DbsHDCxw.js";import{V as n}from"./chunks/View-C5n3sIFi.js";import{d as h}from"./chunks/Collection-Bwoq6muu.js";import{W as l}from"./chunks/WebApp-CeiDNV6L.js";import{B as c,V as u,a as g,b as d,c as m,d as p}from"./chunks/version-B0cBv8MN.js";class CircularProgress extends n{constructor(t={}){super({className:`circular-progress ${t.className||""}`,...t}),this.SIZE_PRESETS={xs:40,sm:60,md:80,lg:120,xl:180},this.STROKE_PRESETS={xs:4,sm:6,md:8,lg:12,xl:16},this.value=void 0!==t.value?t.value:0,this.min=void 0!==t.min?t.min:0,this.max=void 0!==t.max?t.max:100,this.sizePreset="string"==typeof t.size&&this.SIZE_PRESETS[t.size]?t.size:null,this.size=this.resolveSize(void 0!==t.size?t.size:"md"),this.strokeWidth="auto"===t.strokeWidth||void 0===t.strokeWidth?this.getAutoStrokeWidth(t.size):t.strokeWidth,this.theme=t.theme||"basic",this.variant=t.variant||"default",this.color=t.color,this.trackColor=t.trackColor,this.textColor=t.textColor,this.gradientColors=t.gradientColors||null,this.applyTheme(),this.applyVariant(),this.rotation=void 0!==t.rotation?t.rotation:-90,this.gap=t.gap||0,this.showValue=!1!==t.showValue,this.valueFormat=t.valueFormat||"percentage",this.valueFormatter=t.valueFormatter||null,this.label=t.label||null,this.labelHtml=t.labelHtml||null,this.icon=t.icon||null,this.animate=!1!==t.animate,this.animationDuration=t.animationDuration||600,this.animationEasing=t.animationEasing||"ease-out",this.rounded=!1!==t.rounded,this.shadow=t.shadow||!1,this.clickable=t.clickable||!1,this.tooltip=t.tooltip||null,this.tooltipPlacement=t.tooltipPlacement||"top",this.segments=t.segments||null,this.segmentGap=t.segmentGap||2,this.dataFormatter=h,this.svg=null,this.centerElement=null,this.popover=null,this.gradientId=`gradient-${Math.random().toString(36).substr(2,9)}`}resolveSize(t){return"string"==typeof t&&this.SIZE_PRESETS[t]?this.SIZE_PRESETS[t]:"number"==typeof t?t:this.SIZE_PRESETS.md}getAutoStrokeWidth(t){if("string"==typeof t&&this.STROKE_PRESETS[t])return this.STROKE_PRESETS[t];const e=this.resolveSize(t);return e<=40?4:e<=60?6:e<=80?8:e<=120?12:16}applyTheme(){const t={basic:{trackColor:"#e9ecef",textColor:null,backgroundColor:null},shadowed:{trackColor:"#d1d5db",textColor:null,backgroundColor:null,shadow:!0},dark:{trackColor:"#374151",textColor:"#e5e7eb",backgroundColor:"#1f2937"},light:{trackColor:"#f3f4f6",textColor:"#111827",backgroundColor:"#ffffff"}},e=t[this.theme]||t.basic;this.trackColor||(this.trackColor=e.trackColor),!this.textColor&&e.textColor&&(this.textColor=e.textColor),e.shadow&&!1===this.shadow&&(this.shadow=e.shadow)}applyVariant(){const t={success:{color:"#198754",trackColor:"rgba(25, 135, 84, 0.1)"},danger:{color:"#dc3545",trackColor:"rgba(220, 53, 69, 0.1)"},warning:{color:"#ffc107",trackColor:"rgba(255, 193, 7, 0.1)"},info:{color:"#0dcaf0",trackColor:"rgba(13, 202, 240, 0.1)"},default:{color:"#0d6efd"}};if(t[this.variant]){const e=t[this.variant];this.color||(this.color=e.color),e.trackColor&&this.trackColor===this.applyTheme.trackColor&&(this.trackColor=e.trackColor)}this.color||(this.color="#0d6efd")}getTemplate(){const t=this.sizePreset?`circular-progress-${this.sizePreset}`:"",e="default"!==this.variant?`circular-progress-${this.variant}`:"",s="basic"!==this.theme?`circular-progress-theme-${this.theme}`:"",i=this.clickable?"circular-progress-clickable":"",r=this.shadow?"circular-progress-shadow":"",o=this.textColor?`color: ${this.textColor};`:"";return`\n <div class="circular-progress-container ${t} ${e} ${s} ${i} ${r}"\n style="width: ${this.size}px; height: ${this.size}px;">\n <svg class="circular-progress-svg" \n width="${this.size}" \n height="${this.size}"\n viewBox="0 0 ${this.size} ${this.size}">\n </svg>\n <div class="circular-progress-center" style="${o}">\n <div class="circular-progress-content"></div>\n </div>\n </div>\n `}async onAfterRender(){this.svg=this.element.querySelector(".circular-progress-svg"),this.centerElement=this.element.querySelector(".circular-progress-content"),this.containerElement=this.element.querySelector(".circular-progress-container"),this.renderProgress(),this.renderCenterContent(),this.clickable&&this.setupClickHandler(),this.tooltip&&this.clickable&&this.setupTooltip()}renderProgress(){if(!this.svg)return;this.svg.innerHTML="";const t=this.size/2,e=(this.size-this.strokeWidth)/2,s=2*Math.PI*e;this.gradientColors&&this.gradientColors.length>1&&this.createGradient(),this.segments&&Array.isArray(this.segments)&&this.segments.length>0?this.renderSegments(t,e,s):this.renderSingleProgress(t,e,s)}renderSingleProgress(t,e,s){const i=(this.gap>0?360-this.gap:360)/360*s,r=this.createCircle(t,e,{stroke:this.trackColor,strokeWidth:this.strokeWidth,fill:"none",strokeLinecap:this.rounded?"round":"butt",strokeDasharray:this.gap>0?`${i} ${s}`:"none",transform:`rotate(${this.rotation} ${t} ${t})`});this.svg.appendChild(r);const o=i-this.getPercentage()/100*i,a=this.gradientColors?`url(#${this.gradientId})`:this.color,n=this.createCircle(t,e,{stroke:a,strokeWidth:this.strokeWidth,fill:"none",strokeLinecap:this.rounded?"round":"butt",strokeDasharray:`${i} ${s}`,strokeDashoffset:this.animate?i:o,transform:`rotate(${this.rotation} ${t} ${t})`,class:"circular-progress-bar"});this.svg.appendChild(n),this.animate&&this.animateProgress(n,o)}renderSegments(t,e,s){const i=(this.gap>0?360-this.gap:360)/360*s,r=this.createCircle(t,e,{stroke:this.trackColor,strokeWidth:this.strokeWidth,fill:"none",strokeLinecap:this.rounded?"round":"butt",strokeDasharray:this.gap>0?`${i} ${s}`:"none",transform:`rotate(${this.rotation} ${t} ${t})`});this.svg.appendChild(r),this.segments.reduce((t,e)=>t+(e.value||0),0)>this.max&&console.warn("CircularProgress: Segment total exceeds max value. Clamping to max.");let o=0;this.segments.forEach((r,a)=>{const n=(r.value||0)/(this.max-this.min)*100/100*i,h=this.segmentGap/360*s;if(n>0){const l=this.createCircle(t,e,{stroke:r.color||this.color,strokeWidth:this.strokeWidth,fill:"none",strokeLinecap:this.rounded?"round":"butt",strokeDasharray:`${n} ${s}`,strokeDashoffset:this.animate?i:-o,transform:`rotate(${this.rotation} ${t} ${t})`,class:`circular-progress-segment circular-progress-segment-${a}`,"data-segment-index":a});this.svg.appendChild(l),this.animate&&this.animateProgress(l,-o,100*a),o+=n+h}})}createCircle(t,e,s={}){const i=document.createElementNS("http://www.w3.org/2000/svg","circle");return i.setAttribute("cx",t),i.setAttribute("cy",t),i.setAttribute("r",e),Object.entries(s).forEach(([t,e])=>{"strokeWidth"===t?i.setAttribute("stroke-width",e):"strokeLinecap"===t?i.setAttribute("stroke-linecap",e):"strokeDasharray"===t?i.setAttribute("stroke-dasharray",e):"strokeDashoffset"===t?i.setAttribute("stroke-dashoffset",e):i.setAttribute(t,e)}),i}createGradient(){const t=document.createElementNS("http://www.w3.org/2000/svg","defs"),e=document.createElementNS("http://www.w3.org/2000/svg","linearGradient");e.setAttribute("id",this.gradientId),e.setAttribute("x1","0%"),e.setAttribute("y1","0%"),e.setAttribute("x2","100%"),e.setAttribute("y2","100%"),this.gradientColors.forEach((t,s)=>{const i=document.createElementNS("http://www.w3.org/2000/svg","stop"),r=s/(this.gradientColors.length-1)*100;i.setAttribute("offset",`${r}%`),i.setAttribute("stop-color",t),e.appendChild(i)}),t.appendChild(e),this.svg.appendChild(t)}animateProgress(t,e,s=0){setTimeout(()=>{t.style.transition=`stroke-dashoffset ${this.animationDuration}ms ${this.animationEasing}`,t.style.strokeDashoffset=e},s)}renderCenterContent(){if(this.centerElement)if(this.labelHtml)this.centerElement.innerHTML=this.labelHtml;else if(this.icon)this.centerElement.innerHTML=`<i class="${this.icon}"></i>`;else if(this.showValue){let t=`<div class="circular-progress-value">${this.getFormattedValue()}</div>`;this.label&&(t+=`<div class="circular-progress-label">${this.label}</div>`),this.centerElement.innerHTML=t}}getFormattedValue(){const t=this.value,e=this.min,s=this.max;if(this.valueFormatter&&"function"==typeof this.valueFormatter)return this.valueFormatter(t,e,s);switch(this.valueFormat){case"percentage":return`${Math.round(this.getPercentage())}%`;case"fraction":return`${t}/${s}`;case"value":return t.toString();default:if(this.dataFormatter)try{return this.dataFormatter.pipe(t,this.valueFormat)}catch(i){return console.warn("CircularProgress: DataFormatter error, falling back to percentage",i),`${Math.round(this.getPercentage())}%`}return`${Math.round(this.getPercentage())}%`}}getPercentage(){const t=this.max-this.min;return 0===t?0:(this.value-this.min)/t*100}setupClickHandler(){this.containerElement&&(this.containerElement.style.cursor="pointer",this.containerElement.addEventListener("click",t=>{t.preventDefault(),t.stopPropagation();const e=this.getPercentage();this.emit("progress:clicked",{value:this.value,percentage:e,min:this.min,max:this.max}),this.tooltip&&this.togglePopover()}))}setupTooltip(){}togglePopover(){if(this.containerElement&&void 0!==window.bootstrap){if(!this.popover){const t=this.getTooltipContent(),e="object"==typeof this.tooltip&&this.tooltip.title?this.tooltip.title:void 0,s={content:t,html:!0,placement:this.tooltipPlacement,trigger:"manual",container:"body"};e&&(s.title=e),this.popover=new window.bootstrap.Popover(this.containerElement,s)}window.bootstrap.Popover.getInstance(this.containerElement)&&this.containerElement.getAttribute("aria-describedby")?this.popover.hide():(this.popover.setContent({".popover-body":this.getTooltipContent()}),this.popover.show())}else console.warn("CircularProgress: Bootstrap is required for tooltip support")}getTooltipContent(){return"function"==typeof this.tooltip?this.tooltip(this.value,{min:this.min,max:this.max,percentage:this.getPercentage()}):"object"==typeof this.tooltip?this.tooltip.html||this.tooltip.content||"":this.tooltip||""}setValue(t,e=!0){if(this.value,this.value=Math.max(this.min,Math.min(this.max,t)),this.renderCenterContent(),this.svg&&!this.segments){const t=this.svg.querySelector(".circular-progress-bar");if(t){const s=this.size/2-this.strokeWidth/2,i=2*Math.PI*s,r=(this.gap>0?360-this.gap:360)/360*i,o=r-this.getPercentage()/100*r;e?(t.style.transition=`stroke-dashoffset ${this.animationDuration}ms ${this.animationEasing}`,t.style.strokeDashoffset=o):(t.style.transition="none",t.style.strokeDashoffset=o)}}else{const t=this.animate;this.animate=e,this.renderProgress(),this.animate=t}}setRange(t,e){this.min=t,this.max=e,this.renderProgress(),this.renderCenterContent()}increment(t=1){this.setValue(this.value+t)}decrement(t=1){this.setValue(this.value-t)}setColor(t){if(this.color=t,this.gradientColors=null,this.svg&&!this.segments){const e=this.svg.querySelector(".circular-progress-bar");e&&e.setAttribute("stroke",t)}else this.renderProgress()}setGradient(t){Array.isArray(t)&&t.length>1&&(this.gradientColors=t,this.gradientId=`gradient-${Math.random().toString(36).substr(2,9)}`,this.renderProgress())}setSize(t){this.containerElement&&this.sizePreset&&this.containerElement.classList.remove(`circular-progress-${this.sizePreset}`),this.sizePreset="string"==typeof t&&this.SIZE_PRESETS[t]?t:null,this.size=this.resolveSize(t),this.strokeWidth=this.getAutoStrokeWidth(t),this.containerElement&&(this.containerElement.style.width=`${this.size}px`,this.containerElement.style.height=`${this.size}px`,this.sizePreset&&this.containerElement.classList.add(`circular-progress-${this.sizePreset}`)),this.svg&&(this.svg.setAttribute("width",this.size),this.svg.setAttribute("height",this.size),this.svg.setAttribute("viewBox",`0 0 ${this.size} ${this.size}`)),this.renderProgress()}animateTo(t,e=1e3){const s=this.value,i=t-s,r=performance.now(),o=a=>{const n=a-r,h=Math.min(n/e,1),l=1-Math.pow(1-h,3),c=s+i*l;this.setValue(c,!1),h<1?requestAnimationFrame(o):this.setValue(t,!1)};requestAnimationFrame(o)}pulse(){this.containerElement&&(this.containerElement.style.animation="none",setTimeout(()=>{this.containerElement.style.animation="circular-progress-pulse 0.5s ease-out"},10),setTimeout(()=>{this.containerElement.style.animation=""},500))}complete(){this.variant="success",this.applyVariant(),this.setValue(this.max),this.pulse()}reset(){this.setValue(this.min)}hide(){this.element&&(this.element.style.display="none")}show(){this.element&&(this.element.style.display="")}getValue(){return this.value}getPercentageValue(){return this.getPercentage()}async onBeforeDestroy(){this.popover&&(this.popover.dispose(),this.popover=null),await super.onBeforeDestroy()}}export{c as BUILD_TIME,CircularProgress,t as MetricsChart,e as MetricsMiniChart,s as MetricsMiniChartWidget,i as MiniChart,r as PieChart,o as SeriesChart,u as VERSION,g as VERSION_INFO,d as VERSION_MAJOR,m as VERSION_MINOR,p as VERSION_REVISION,l as WebApp,a as exportChartPng};
|
|
1
|
+
import{M as t,a as e,b as s,c as i,P as r,S as o,e as a}from"./chunks/exportChart-BTJBYkOz.js";import{V as n}from"./chunks/View-C5n3sIFi.js";import{d as h}from"./chunks/Collection-Bwoq6muu.js";import{W as l}from"./chunks/WebApp-CeiDNV6L.js";import{B as c,V as u,a as g,b as d,c as m,d as p}from"./chunks/version-CYGIXntv.js";class CircularProgress extends n{constructor(t={}){super({className:`circular-progress ${t.className||""}`,...t}),this.SIZE_PRESETS={xs:40,sm:60,md:80,lg:120,xl:180},this.STROKE_PRESETS={xs:4,sm:6,md:8,lg:12,xl:16},this.value=void 0!==t.value?t.value:0,this.min=void 0!==t.min?t.min:0,this.max=void 0!==t.max?t.max:100,this.sizePreset="string"==typeof t.size&&this.SIZE_PRESETS[t.size]?t.size:null,this.size=this.resolveSize(void 0!==t.size?t.size:"md"),this.strokeWidth="auto"===t.strokeWidth||void 0===t.strokeWidth?this.getAutoStrokeWidth(t.size):t.strokeWidth,this.theme=t.theme||"basic",this.variant=t.variant||"default",this.color=t.color,this.trackColor=t.trackColor,this.textColor=t.textColor,this.gradientColors=t.gradientColors||null,this.applyTheme(),this.applyVariant(),this.rotation=void 0!==t.rotation?t.rotation:-90,this.gap=t.gap||0,this.showValue=!1!==t.showValue,this.valueFormat=t.valueFormat||"percentage",this.valueFormatter=t.valueFormatter||null,this.label=t.label||null,this.labelHtml=t.labelHtml||null,this.icon=t.icon||null,this.animate=!1!==t.animate,this.animationDuration=t.animationDuration||600,this.animationEasing=t.animationEasing||"ease-out",this.rounded=!1!==t.rounded,this.shadow=t.shadow||!1,this.clickable=t.clickable||!1,this.tooltip=t.tooltip||null,this.tooltipPlacement=t.tooltipPlacement||"top",this.segments=t.segments||null,this.segmentGap=t.segmentGap||2,this.dataFormatter=h,this.svg=null,this.centerElement=null,this.popover=null,this.gradientId=`gradient-${Math.random().toString(36).substr(2,9)}`}resolveSize(t){return"string"==typeof t&&this.SIZE_PRESETS[t]?this.SIZE_PRESETS[t]:"number"==typeof t?t:this.SIZE_PRESETS.md}getAutoStrokeWidth(t){if("string"==typeof t&&this.STROKE_PRESETS[t])return this.STROKE_PRESETS[t];const e=this.resolveSize(t);return e<=40?4:e<=60?6:e<=80?8:e<=120?12:16}applyTheme(){const t={basic:{trackColor:"#e9ecef",textColor:null,backgroundColor:null},shadowed:{trackColor:"#d1d5db",textColor:null,backgroundColor:null,shadow:!0},dark:{trackColor:"#374151",textColor:"#e5e7eb",backgroundColor:"#1f2937"},light:{trackColor:"#f3f4f6",textColor:"#111827",backgroundColor:"#ffffff"}},e=t[this.theme]||t.basic;this.trackColor||(this.trackColor=e.trackColor),!this.textColor&&e.textColor&&(this.textColor=e.textColor),e.shadow&&!1===this.shadow&&(this.shadow=e.shadow)}applyVariant(){const t={success:{color:"#198754",trackColor:"rgba(25, 135, 84, 0.1)"},danger:{color:"#dc3545",trackColor:"rgba(220, 53, 69, 0.1)"},warning:{color:"#ffc107",trackColor:"rgba(255, 193, 7, 0.1)"},info:{color:"#0dcaf0",trackColor:"rgba(13, 202, 240, 0.1)"},default:{color:"#0d6efd"}};if(t[this.variant]){const e=t[this.variant];this.color||(this.color=e.color),e.trackColor&&this.trackColor===this.applyTheme.trackColor&&(this.trackColor=e.trackColor)}this.color||(this.color="#0d6efd")}getTemplate(){const t=this.sizePreset?`circular-progress-${this.sizePreset}`:"",e="default"!==this.variant?`circular-progress-${this.variant}`:"",s="basic"!==this.theme?`circular-progress-theme-${this.theme}`:"",i=this.clickable?"circular-progress-clickable":"",r=this.shadow?"circular-progress-shadow":"",o=this.textColor?`color: ${this.textColor};`:"";return`\n <div class="circular-progress-container ${t} ${e} ${s} ${i} ${r}"\n style="width: ${this.size}px; height: ${this.size}px;">\n <svg class="circular-progress-svg" \n width="${this.size}" \n height="${this.size}"\n viewBox="0 0 ${this.size} ${this.size}">\n </svg>\n <div class="circular-progress-center" style="${o}">\n <div class="circular-progress-content"></div>\n </div>\n </div>\n `}async onAfterRender(){this.svg=this.element.querySelector(".circular-progress-svg"),this.centerElement=this.element.querySelector(".circular-progress-content"),this.containerElement=this.element.querySelector(".circular-progress-container"),this.renderProgress(),this.renderCenterContent(),this.clickable&&this.setupClickHandler(),this.tooltip&&this.clickable&&this.setupTooltip()}renderProgress(){if(!this.svg)return;this.svg.innerHTML="";const t=this.size/2,e=(this.size-this.strokeWidth)/2,s=2*Math.PI*e;this.gradientColors&&this.gradientColors.length>1&&this.createGradient(),this.segments&&Array.isArray(this.segments)&&this.segments.length>0?this.renderSegments(t,e,s):this.renderSingleProgress(t,e,s)}renderSingleProgress(t,e,s){const i=(this.gap>0?360-this.gap:360)/360*s,r=this.createCircle(t,e,{stroke:this.trackColor,strokeWidth:this.strokeWidth,fill:"none",strokeLinecap:this.rounded?"round":"butt",strokeDasharray:this.gap>0?`${i} ${s}`:"none",transform:`rotate(${this.rotation} ${t} ${t})`});this.svg.appendChild(r);const o=i-this.getPercentage()/100*i,a=this.gradientColors?`url(#${this.gradientId})`:this.color,n=this.createCircle(t,e,{stroke:a,strokeWidth:this.strokeWidth,fill:"none",strokeLinecap:this.rounded?"round":"butt",strokeDasharray:`${i} ${s}`,strokeDashoffset:this.animate?i:o,transform:`rotate(${this.rotation} ${t} ${t})`,class:"circular-progress-bar"});this.svg.appendChild(n),this.animate&&this.animateProgress(n,o)}renderSegments(t,e,s){const i=(this.gap>0?360-this.gap:360)/360*s,r=this.createCircle(t,e,{stroke:this.trackColor,strokeWidth:this.strokeWidth,fill:"none",strokeLinecap:this.rounded?"round":"butt",strokeDasharray:this.gap>0?`${i} ${s}`:"none",transform:`rotate(${this.rotation} ${t} ${t})`});this.svg.appendChild(r),this.segments.reduce((t,e)=>t+(e.value||0),0)>this.max&&console.warn("CircularProgress: Segment total exceeds max value. Clamping to max.");let o=0;this.segments.forEach((r,a)=>{const n=(r.value||0)/(this.max-this.min)*100/100*i,h=this.segmentGap/360*s;if(n>0){const l=this.createCircle(t,e,{stroke:r.color||this.color,strokeWidth:this.strokeWidth,fill:"none",strokeLinecap:this.rounded?"round":"butt",strokeDasharray:`${n} ${s}`,strokeDashoffset:this.animate?i:-o,transform:`rotate(${this.rotation} ${t} ${t})`,class:`circular-progress-segment circular-progress-segment-${a}`,"data-segment-index":a});this.svg.appendChild(l),this.animate&&this.animateProgress(l,-o,100*a),o+=n+h}})}createCircle(t,e,s={}){const i=document.createElementNS("http://www.w3.org/2000/svg","circle");return i.setAttribute("cx",t),i.setAttribute("cy",t),i.setAttribute("r",e),Object.entries(s).forEach(([t,e])=>{"strokeWidth"===t?i.setAttribute("stroke-width",e):"strokeLinecap"===t?i.setAttribute("stroke-linecap",e):"strokeDasharray"===t?i.setAttribute("stroke-dasharray",e):"strokeDashoffset"===t?i.setAttribute("stroke-dashoffset",e):i.setAttribute(t,e)}),i}createGradient(){const t=document.createElementNS("http://www.w3.org/2000/svg","defs"),e=document.createElementNS("http://www.w3.org/2000/svg","linearGradient");e.setAttribute("id",this.gradientId),e.setAttribute("x1","0%"),e.setAttribute("y1","0%"),e.setAttribute("x2","100%"),e.setAttribute("y2","100%"),this.gradientColors.forEach((t,s)=>{const i=document.createElementNS("http://www.w3.org/2000/svg","stop"),r=s/(this.gradientColors.length-1)*100;i.setAttribute("offset",`${r}%`),i.setAttribute("stop-color",t),e.appendChild(i)}),t.appendChild(e),this.svg.appendChild(t)}animateProgress(t,e,s=0){setTimeout(()=>{t.style.transition=`stroke-dashoffset ${this.animationDuration}ms ${this.animationEasing}`,t.style.strokeDashoffset=e},s)}renderCenterContent(){if(this.centerElement)if(this.labelHtml)this.centerElement.innerHTML=this.labelHtml;else if(this.icon)this.centerElement.innerHTML=`<i class="${this.icon}"></i>`;else if(this.showValue){let t=`<div class="circular-progress-value">${this.getFormattedValue()}</div>`;this.label&&(t+=`<div class="circular-progress-label">${this.label}</div>`),this.centerElement.innerHTML=t}}getFormattedValue(){const t=this.value,e=this.min,s=this.max;if(this.valueFormatter&&"function"==typeof this.valueFormatter)return this.valueFormatter(t,e,s);switch(this.valueFormat){case"percentage":return`${Math.round(this.getPercentage())}%`;case"fraction":return`${t}/${s}`;case"value":return t.toString();default:if(this.dataFormatter)try{return this.dataFormatter.pipe(t,this.valueFormat)}catch(i){return console.warn("CircularProgress: DataFormatter error, falling back to percentage",i),`${Math.round(this.getPercentage())}%`}return`${Math.round(this.getPercentage())}%`}}getPercentage(){const t=this.max-this.min;return 0===t?0:(this.value-this.min)/t*100}setupClickHandler(){this.containerElement&&(this.containerElement.style.cursor="pointer",this.containerElement.addEventListener("click",t=>{t.preventDefault(),t.stopPropagation();const e=this.getPercentage();this.emit("progress:clicked",{value:this.value,percentage:e,min:this.min,max:this.max}),this.tooltip&&this.togglePopover()}))}setupTooltip(){}togglePopover(){if(this.containerElement&&void 0!==window.bootstrap){if(!this.popover){const t=this.getTooltipContent(),e="object"==typeof this.tooltip&&this.tooltip.title?this.tooltip.title:void 0,s={content:t,html:!0,placement:this.tooltipPlacement,trigger:"manual",container:"body"};e&&(s.title=e),this.popover=new window.bootstrap.Popover(this.containerElement,s)}window.bootstrap.Popover.getInstance(this.containerElement)&&this.containerElement.getAttribute("aria-describedby")?this.popover.hide():(this.popover.setContent({".popover-body":this.getTooltipContent()}),this.popover.show())}else console.warn("CircularProgress: Bootstrap is required for tooltip support")}getTooltipContent(){return"function"==typeof this.tooltip?this.tooltip(this.value,{min:this.min,max:this.max,percentage:this.getPercentage()}):"object"==typeof this.tooltip?this.tooltip.html||this.tooltip.content||"":this.tooltip||""}setValue(t,e=!0){if(this.value,this.value=Math.max(this.min,Math.min(this.max,t)),this.renderCenterContent(),this.svg&&!this.segments){const t=this.svg.querySelector(".circular-progress-bar");if(t){const s=this.size/2-this.strokeWidth/2,i=2*Math.PI*s,r=(this.gap>0?360-this.gap:360)/360*i,o=r-this.getPercentage()/100*r;e?(t.style.transition=`stroke-dashoffset ${this.animationDuration}ms ${this.animationEasing}`,t.style.strokeDashoffset=o):(t.style.transition="none",t.style.strokeDashoffset=o)}}else{const t=this.animate;this.animate=e,this.renderProgress(),this.animate=t}}setRange(t,e){this.min=t,this.max=e,this.renderProgress(),this.renderCenterContent()}increment(t=1){this.setValue(this.value+t)}decrement(t=1){this.setValue(this.value-t)}setColor(t){if(this.color=t,this.gradientColors=null,this.svg&&!this.segments){const e=this.svg.querySelector(".circular-progress-bar");e&&e.setAttribute("stroke",t)}else this.renderProgress()}setGradient(t){Array.isArray(t)&&t.length>1&&(this.gradientColors=t,this.gradientId=`gradient-${Math.random().toString(36).substr(2,9)}`,this.renderProgress())}setSize(t){this.containerElement&&this.sizePreset&&this.containerElement.classList.remove(`circular-progress-${this.sizePreset}`),this.sizePreset="string"==typeof t&&this.SIZE_PRESETS[t]?t:null,this.size=this.resolveSize(t),this.strokeWidth=this.getAutoStrokeWidth(t),this.containerElement&&(this.containerElement.style.width=`${this.size}px`,this.containerElement.style.height=`${this.size}px`,this.sizePreset&&this.containerElement.classList.add(`circular-progress-${this.sizePreset}`)),this.svg&&(this.svg.setAttribute("width",this.size),this.svg.setAttribute("height",this.size),this.svg.setAttribute("viewBox",`0 0 ${this.size} ${this.size}`)),this.renderProgress()}animateTo(t,e=1e3){const s=this.value,i=t-s,r=performance.now(),o=a=>{const n=a-r,h=Math.min(n/e,1),l=1-Math.pow(1-h,3),c=s+i*l;this.setValue(c,!1),h<1?requestAnimationFrame(o):this.setValue(t,!1)};requestAnimationFrame(o)}pulse(){this.containerElement&&(this.containerElement.style.animation="none",setTimeout(()=>{this.containerElement.style.animation="circular-progress-pulse 0.5s ease-out"},10),setTimeout(()=>{this.containerElement.style.animation=""},500))}complete(){this.variant="success",this.applyVariant(),this.setValue(this.max),this.pulse()}reset(){this.setValue(this.min)}hide(){this.element&&(this.element.style.display="none")}show(){this.element&&(this.element.style.display="")}getValue(){return this.value}getPercentageValue(){return this.getPercentage()}async onBeforeDestroy(){this.popover&&(this.popover.dispose(),this.popover=null),await super.onBeforeDestroy()}}export{c as BUILD_TIME,CircularProgress,t as MetricsChart,e as MetricsMiniChart,s as MetricsMiniChartWidget,i as MiniChart,r as PieChart,o as SeriesChart,u as VERSION,g as VERSION_INFO,d as VERSION_MAJOR,m as VERSION_MINOR,p as VERSION_REVISION,l as WebApp,a as exportChartPng};
|
|
2
2
|
//# sourceMappingURL=charts.es.js.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{V as t}from"./View-C5n3sIFi.js";import{C as s}from"./ChatView-W8daOwIo.js";import{AssistantConversationList as e,Assistant as n}from"../admin-models.es.js";import{A as i,a,b as o}from"./admin-vjoNbv_1.js";class AssistantPanelView extends t{constructor(t={}){super({className:"assistant-panel-view",...t}),this.app=t.app,this.ws=this.app?.ws,this.conversationId=t.conversationId||this.app?._assistantConversationId||null,this._wsHandlers={},this._messageIdCounter=0,this._hasMessages=!1,this._activePlans={},this._requestStartTime=null,this._showingHistory=!1}getTemplate(){return`\n <div class="assistant-panel-resize-handle" data-ref="resize-handle"></div>\n <div class="assistant-panel-layout">\n <div class="assistant-panel-header">\n <button class="assistant-panel-header-btn" data-action="toggle-history" type="button" title="Conversation history">\n <i class="bi bi-list"></i>\n </button>\n <span class="assistant-panel-title text-truncate" data-ref="panel-title">New conversation</span>\n <div class="d-flex gap-1 ms-auto">\n <button class="assistant-panel-header-btn" data-action="new-conversation" type="button" title="New conversation">\n <i class="bi bi-plus-lg"></i>\n </button>\n <button class="assistant-panel-header-btn" data-action="fullscreen" type="button" title="Open fullscreen">\n <i class="bi bi-arrows-fullscreen"></i>\n </button>\n <button class="assistant-panel-header-btn" data-action="pop-out" type="button" title="Open in popup window">\n <i class="bi bi-box-arrow-up-right"></i>\n </button>\n <button class="assistant-panel-header-btn" data-action="close-panel" type="button" title="Close">\n <i class="bi bi-x-lg"></i>\n </button>\n </div>\n </div>\n\n <div class="assistant-panel-history d-none" data-ref="history" data-container="conversation-list"></div>\n\n <div class="assistant-panel-chat" data-ref="chat-wrapper">\n <div class="assistant-welcome" data-ref="welcome">\n <div class="assistant-welcome-content">\n <div class="assistant-welcome-icon">\n <i class="bi bi-stars"></i>\n </div>\n <h3 class="assistant-welcome-title">Hi ${this._escapeHtml(this.app?.activeUser?.get("first_name")||"there")}</h3>\n <p class="assistant-welcome-subtitle">How can I help you today?</p>\n <div class="assistant-suggestions">\n <button class="assistant-suggestion" data-action="use-suggestion" data-text="Show me a summary of recent activity">\n <i class="bi bi-activity"></i>\n <span>Recent activity summary</span>\n </button>\n <button class="assistant-suggestion" data-action="use-suggestion" data-text="How many active users are there?">\n <i class="bi bi-people"></i>\n <span>Active user count</span>\n </button>\n </div>\n </div>\n </div>\n <div class="assistant-chat-area" data-container="chat-area"></div>\n <div class="assistant-input-wrapper">\n <div class="assistant-input-status d-none" data-ref="input-status"></div>\n <div class="assistant-input-box">\n <textarea class="assistant-input" placeholder="Message the assistant..." rows="1" data-ref="input"></textarea>\n <button class="assistant-send-btn" data-action="send" type="button" title="Send message" data-ref="send-btn">\n <i class="bi bi-arrow-up"></i>\n </button>\n <button class="assistant-stop-btn d-none" data-action="stop" type="button" title="Stop generating" data-ref="stop-btn">\n <i class="bi bi-stop-fill"></i>\n </button>\n </div>\n <div class="assistant-input-footer">\n <span class="assistant-connection-indicator" data-ref="status">\n <span class="status-dot connected"></span>\n </span>\n <span class="text-muted">Enter to send</span>\n </div>\n </div>\n </div>\n </div>\n `}async onInit(){this.conversations=new e,this.conversations.params.user=this.app?.activeUser?.id,this.conversationListView=new i({containerId:"conversation-list",collection:this.conversations}),this.addChild(this.conversationListView),this.chatView=new s({containerId:"chat-area",theme:"compact",messageViewClass:a,currentUserId:this.app?.activeUser?.id,showFileInput:!1,showInput:!1,adapter:this._createAdapter()}),this.addChild(this.chatView);const t=this.chatView.addMessage.bind(this.chatView);this.chatView.addMessage=(s,e)=>{t(s,e),"assistant"===s.role&&(s.content||s.blocks?.length)&&(this.chatView.hideThinking(),this._setInputEnabled(!0))},this.conversationListView.on("conversation:select",t=>{this._onConversationSelect(t),this._toggleHistory(!1)}),this.conversationListView.on("conversation:new",()=>{this._onNewConversation(),this._toggleHistory(!1)}),this.conversationListView.on("conversation:deleted",t=>this._onConversationDeleted(t)),this._subscribeWS()}async onAfterRender(){await super.onAfterRender();const t=this.element.querySelector('[data-ref="input"]');t&&(t.addEventListener("input",()=>this._autoResize(t)),t.addEventListener("keydown",t=>this._handleKeydown(t)),setTimeout(()=>t.focus(),100)),this.conversationId&&(this._showChatArea(),await this.chatView.refresh()),this._updateConnectionStatus(),this._updateTitle(),this._setupResizeHandle()}_setupResizeHandle(){const t=this.element?.querySelector('[data-ref="resize-handle"]');if(!t)return;const s="mojo:assistant_panel_width",e=localStorage.getItem(s);if(e){const t=parseInt(e,10);if(t>=300&&t<=700){const s=document.getElementById("assistant-panel");s&&(s.style.width=t+"px")}}let n,i;const a=t=>{const s=n-t.clientX,e=Math.min(700,Math.max(300,i+s)),a=document.getElementById("assistant-panel");a&&(a.style.width=e+"px")},o=()=>{document.removeEventListener("mousemove",a),document.removeEventListener("mouseup",o),document.body.style.cursor="",document.body.style.userSelect="";const t=document.getElementById("assistant-panel");t&&localStorage.setItem(s,parseInt(t.style.width,10))};t.addEventListener("mousedown",t=>{t.preventDefault(),n=t.clientX;const s=document.getElementById("assistant-panel");i=s?s.offsetWidth:500,document.body.style.cursor="col-resize",document.body.style.userSelect="none",document.addEventListener("mousemove",a),document.addEventListener("mouseup",o)})}onActionToggleHistory(){this._toggleHistory(!this._showingHistory)}onActionNewConversation(){this._onNewConversation(),this._showingHistory&&this._toggleHistory(!1)}onActionClosePanel(){this.emit("panel:close")}onActionFullscreen(){this.emit("panel:fullscreen",{conversationId:this.conversationId})}onActionPopOut(){this.emit("panel:popout",{conversationId:this.conversationId})}onActionUseSuggestion(t,s){const e=s.dataset.text||s.closest("[data-text]")?.dataset.text;if(!e)return;const n=this.element.querySelector('[data-ref="input"]');n&&(n.value=e,this._autoResize(n)),this._sendMessage()}onActionSend(){this._sendMessage()}onActionStop(){this.chatView.hideThinking(),this._setInputEnabled(!0),this._showSystemMessage("Response cancelled.");const t=this.element?.querySelector('[data-ref="input"]');t&&t.focus()}_toggleHistory(t){this._showingHistory=t;const s=this.element?.querySelector('[data-ref="history"]'),e=this.element?.querySelector('[data-ref="chat-wrapper"]'),n=this.element?.querySelector('[data-action="toggle-history"] i');s&&s.classList.toggle("d-none",!t),e&&e.classList.toggle("d-none",t),n&&(n.className=t?"bi bi-chat-dots":"bi bi-list"),t&&this.conversationListView.refresh()}_autoResize(t){t.style.height="auto",t.style.height=Math.min(t.scrollHeight,200)+"px"}_handleKeydown(t){"Enter"!==t.key||t.shiftKey||(t.preventDefault(),this._sendMessage())}async _sendMessage(){const t=this.element.querySelector('[data-ref="input"]');if(!t)return;const s=t.value.trim();s&&(t.value="",t.style.height="auto",this._showChatArea(),await this.chatView.adapter.addNote({text:s,files:[]}))}_showChatArea(){if(this._hasMessages)return;this._hasMessages=!0;const t=this.element.querySelector('[data-ref="welcome"]'),s=this.element.querySelector('[data-container="chat-area"]');t&&t.classList.add("d-none"),s&&s.classList.remove("d-none")}_showWelcome(){this._hasMessages=!1;const t=this.element.querySelector('[data-ref="welcome"]'),s=this.element.querySelector('[data-container="chat-area"]');t&&t.classList.remove("d-none"),s&&s.classList.add("d-none")}_setInputEnabled(t,s){const e=this.element?.querySelector('[data-ref="input"]'),n=this.element?.querySelector('[data-ref="send-btn"]'),i=this.element?.querySelector('[data-ref="stop-btn"]');e&&(e.disabled=!t),n&&n.classList.toggle("d-none",!t),i&&i.classList.toggle("d-none",t),this._setInputStatus(t?null:s),this._responseTimeout&&clearTimeout(this._responseTimeout),t?this._requestStartTime=null:this._responseTimeout=setTimeout(()=>this._onResponseTimeout(),6e4)}_setInputStatus(t){const s=this.element?.querySelector('[data-ref="input-status"]');s&&(t?(s.innerHTML=`${this._escapeHtml(t)} <span class="assistant-input-status-dismiss">Click to dismiss</span>`,s.classList.remove("d-none"),s._hasDismiss||(s._hasDismiss=!0,s.addEventListener("click",()=>{this.chatView.hideThinking(),this._setInputEnabled(!0);const t=this.element?.querySelector('[data-ref="input"]');t&&t.focus()}))):(s.classList.add("d-none"),s.innerHTML=""))}_onResponseTimeout(){this._responseTimeout=null,this.chatView.hideThinking(),this._setInputEnabled(!0),this._showSystemMessage("Request timed out. Please try again.")}_updateTitle(t){const s=this.element?.querySelector('[data-ref="panel-title"]');s&&(s.textContent=t||(this.conversationId?"Assistant":"New conversation"))}_createAdapter(){return{fetch:async()=>{if(!this.conversationId)return[];try{const t=new n({id:this.conversationId});await t.fetch({graph:"detail"});const s=t.get("title")||t.get("summary");s&&this._updateTitle(s);const e=(t.get("messages")||[]).map(t=>this._transformMessage(t)).filter(Boolean);return o._collapseMessages(e)}catch(t){return 404===t.status&&(this._onNewConversation(),this._showSystemMessage("Conversation not found.")),[]}},addNote:async t=>{if(!t.text||!t.text.trim())return{success:!1};const s={id:"local-"+ ++this._messageIdCounter,role:"user",author:{id:this.app?.activeUser?.id,name:this.app?.activeUser?.get("display_name")||"You"},content:t.text,timestamp:/* @__PURE__ */(new Date).toISOString()};if(this.chatView.addMessage(s),this.chatView.showThinking("Thinking..."),this._requestStartTime=Date.now(),this._setInputEnabled(!1,"Waiting for response…"),this.ws&&this.ws.isConnected)this.ws.send({type:"assistant_message",message:t.text,conversation_id:this.conversationId});else try{const s=await this.app.rest.post("/api/assistant",{message:t.text,conversation_id:this.conversationId}),e=s?.data?.data||s?.data||s;e.conversation_id&&(this.conversationId=e.conversation_id,this.app._assistantConversationId=this.conversationId),e.response&&this.chatView.addMessage(this._transformMessage(e.response)),this._setInputEnabled(!0)}catch(e){this._handleAPIError(e)}return{success:!0}}}}_subscribeWS(){this.ws&&(this._wsHandlers={thinking:t=>this._onThinking(t),text:t=>this._onText(t),tool_call:t=>this._onToolCall(t),response:t=>this._onResponse(t),error:t=>this._onError(t),plan:t=>this._onPlan(t),plan_update:t=>this._onPlanUpdate(t),message:t=>this._dispatchWSMessage(t),connected:()=>this._updateConnectionStatus(),disconnected:()=>this._updateConnectionStatus(),reconnecting:()=>this._updateConnectionStatus()},this.ws.on("message:assistant_thinking",this._wsHandlers.thinking),this.ws.on("message:assistant_text",this._wsHandlers.text),this.ws.on("message:assistant_tool_call",this._wsHandlers.tool_call),this.ws.on("message:assistant_response",this._wsHandlers.response),this.ws.on("message:assistant_error",this._wsHandlers.error),this.ws.on("message:assistant_plan",this._wsHandlers.plan),this.ws.on("message:assistant_plan_update",this._wsHandlers.plan_update),this.ws.on("message:message",this._wsHandlers.message),this.ws.on("connected",this._wsHandlers.connected),this.ws.on("disconnected",this._wsHandlers.disconnected),this.ws.on("reconnecting",this._wsHandlers.reconnecting))}_unsubscribeWS(){this.ws&&this._wsHandlers&&(this.ws.off("message:assistant_thinking",this._wsHandlers.thinking),this.ws.off("message:assistant_text",this._wsHandlers.text),this.ws.off("message:assistant_tool_call",this._wsHandlers.tool_call),this.ws.off("message:assistant_response",this._wsHandlers.response),this.ws.off("message:assistant_error",this._wsHandlers.error),this.ws.off("message:assistant_plan",this._wsHandlers.plan),this.ws.off("message:assistant_plan_update",this._wsHandlers.plan_update),this.ws.off("message:message",this._wsHandlers.message),this.ws.off("connected",this._wsHandlers.connected),this.ws.off("disconnected",this._wsHandlers.disconnected),this.ws.off("reconnecting",this._wsHandlers.reconnecting),this._wsHandlers={})}_dispatchWSMessage(t){const s=t?.data;if(s?.type)switch(s.type){case"assistant_thinking":this._onThinking(s);break;case"assistant_text":this._onText(s);break;case"assistant_tool_call":this._onToolCall(s);break;case"assistant_response":this._onResponse(s);break;case"assistant_error":this._onError(s);break;case"assistant_plan":this._onPlan(s);break;case"assistant_plan_update":this._onPlanUpdate(s)}}_isMyConversation(t){return!t.conversation_id||!this.conversationId||String(t.conversation_id)===String(this.conversationId)}_adoptConversationId(t){t.conversation_id&&!this.conversationId&&(this.conversationId=t.conversation_id,this.app._assistantConversationId=this.conversationId)}_onThinking(t){this._isMyConversation(t)&&(this._adoptConversationId(t),this._showChatArea(),this.chatView.showThinking("Thinking..."),this._setInputEnabled(!1,"Assistant is thinking…"))}_onText(t){if(!this._isMyConversation(t))return;this._adoptConversationId(t),this._resetResponseTimeout();const s=this._transformMessage({id:t.message_id||"text-"+ ++this._messageIdCounter,role:"assistant",content:t.text||"",blocks:t.blocks||[],tool_calls:[],created:t.created||t.timestamp||/* @__PURE__ */(new Date).toISOString()});s&&(s.content||s.blocks?.length)&&this.chatView.addMessage(s)}_onToolCall(t){this._isMyConversation(t)&&(this.chatView.showThinking(`Using ${t.tool||t.name||"tool"}...`),this._resetResponseTimeout())}_resetResponseTimeout(){if(this._responseTimeout){if(this._requestStartTime&&Date.now()-this._requestStartTime>=3e5)return void this._onResponseTimeout();clearTimeout(this._responseTimeout),this._responseTimeout=setTimeout(()=>this._onResponseTimeout(),6e4)}}_onResponse(t){if(!this._isMyConversation(t))return;this.chatView.hideThinking(),this._setInputEnabled(!0),this._adoptConversationId(t);const s=this.element?.querySelector('[data-ref="input"]');s&&s.focus();const e=this._transformMessage({id:t.message_id||"resp-"+ ++this._messageIdCounter,role:"assistant",content:t.response||t.content||t.message||"",blocks:t.blocks||[],tool_calls:t.tool_calls_made||t.tool_calls||[],created:t.created||t.timestamp||/* @__PURE__ */(new Date).toISOString()});e&&(e.content||e.blocks?.length||e.tool_calls?.length)&&this.chatView.addMessage(e)}_onError(t){if(!this._isMyConversation(t))return;this.chatView.hideThinking(),this._setInputEnabled(!0),this._adoptConversationId(t);const s=t.error||t.message||"An error occurred";this._showSystemMessage(s)}_onPlan(t){if(!this._isMyConversation(t))return;this._adoptConversationId(t),this._showChatArea();const s=t.plan;s&&(this._activePlans[s.plan_id]=s,this.chatView.addMessage({id:`plan-${s.plan_id}`,role:"assistant",author:{name:"Assistant"},content:"",timestamp:/* @__PURE__ */(new Date).toISOString(),blocks:[{type:"progress",...s}],tool_calls:[]}))}_onPlanUpdate(t){if(!this._isMyConversation(t))return;const s=this._activePlans[t.plan_id];if(s){const e=s.steps.find(s=>s.id===t.step_id);e&&(e.status=t.status,e.summary=t.summary)}const e=this.chatView.messageViews.get(`plan-${t.plan_id}`);e?.updateProgressStep&&e.updateProgressStep(t.plan_id,t.step_id,t.status,t.summary),this._resetResponseTimeout()}async _onConversationSelect(t){this.conversationId=t.id,this.app._assistantConversationId=this.conversationId,this.conversationListView.setActive(t.id),this._showChatArea(),this._updateTitle(t.model?.get("title")||t.model?.get("summary")),await this.chatView.refresh()}_onNewConversation(){this.conversationId=null,this.app._assistantConversationId=null,this.conversationListView.setActive(null),this.chatView.clearMessages(),this._setInputEnabled(!0),this._showWelcome(),this._updateTitle();const t=this.element?.querySelector('[data-ref="input"]');t&&t.focus()}_onConversationDeleted(t){String(t.id)===String(this.conversationId)&&this._onNewConversation()}_transformMessage(t){if("tool_result"===t.role)return null;let s=t.content||t.text||"",e=t.blocks||[],n=t.tool_calls||[];if(n.length>0){n=n.map(t=>!t.type&&t.tool?{type:"tool_use",name:t.tool,input:t.input}:t);const t=n.filter(t=>"text"===t.type&&t.text).map(t=>t.text);!s&&t.length>0&&(s=t.join("\n\n")),n=n.filter(t=>"tool_use"===t.type).filter(t=>!o.INTERNAL_TOOLS.has(t.name))}if(0===e.length&&s.includes("assistant_block")){const t=o._parseBlocks(s);s=t.content,e=t.blocks}const i=this.app?.activeUser?.id;return{id:t.id,role:t.role||"user",author:"assistant"===t.role?{name:"Assistant"}:t.author||{name:t.user?.display_name||this.app?.activeUser?.get("display_name")||"You",id:t.user?.id||i},content:s,timestamp:t.created||t.timestamp,blocks:e,tool_calls:n,_conversationId:this.conversationId}}_showSystemMessage(t){this._showChatArea(),this.chatView.addMessage({id:"sys-"+ ++this._messageIdCounter,type:"system_event",content:t,timestamp:/* @__PURE__ */(new Date).toISOString()})}_handleAPIError(t){404===t.status?this._showSystemMessage("Assistant is not enabled on this server."):503===t.status?this._showSystemMessage("LLM API key not configured. Contact your administrator."):this._showSystemMessage("Failed to send message. Please try again."),this._setInputEnabled(!0)}_updateConnectionStatus(){const t=this.element?.querySelector(".status-dot");t&&(this.ws?.isConnected?(t.className="status-dot connected",t.title="Connected",this._responseTimeout?this._setInputEnabled(!1,"Waiting for response…"):this._setInputEnabled(!0)):this.ws?.isReconnecting?(t.className="status-dot reconnecting",t.title="Reconnecting...",this._setInputEnabled(!1,"Reconnecting…"),this._responseTimeout&&(clearTimeout(this._responseTimeout),this._responseTimeout=null)):(t.className="status-dot disconnected",t.title="Disconnected",this._setInputEnabled(!1,"Disconnected — reconnecting…"),this._responseTimeout&&(clearTimeout(this._responseTimeout),this._responseTimeout=null)))}_escapeHtml(t){const s=document.createElement("div");return s.textContent=t,s.innerHTML}focusInput(){const t=this.element?.querySelector('[data-ref="input"]');t&&t.focus()}async onBeforeDestroy(){this._unsubscribeWS(),this._responseTimeout&&(clearTimeout(this._responseTimeout),this._responseTimeout=null)}}export{AssistantPanelView as default};
|
|
2
|
-
//# sourceMappingURL=AssistantPanelView-
|
|
1
|
+
import{V as t}from"./View-C5n3sIFi.js";import{C as s}from"./ChatView-W8daOwIo.js";import{AssistantConversationList as e,Assistant as n}from"../admin-models.es.js";import{A as i,a,b as o}from"./admin-B5tf0zOO.js";class AssistantPanelView extends t{constructor(t={}){super({className:"assistant-panel-view",...t}),this.app=t.app,this.ws=this.app?.ws,this.conversationId=t.conversationId||this.app?._assistantConversationId||null,this._wsHandlers={},this._messageIdCounter=0,this._hasMessages=!1,this._activePlans={},this._requestStartTime=null,this._showingHistory=!1}getTemplate(){return`\n <div class="assistant-panel-resize-handle" data-ref="resize-handle"></div>\n <div class="assistant-panel-layout">\n <div class="assistant-panel-header">\n <button class="assistant-panel-header-btn" data-action="toggle-history" type="button" title="Conversation history">\n <i class="bi bi-list"></i>\n </button>\n <span class="assistant-panel-title text-truncate" data-ref="panel-title">New conversation</span>\n <div class="d-flex gap-1 ms-auto">\n <button class="assistant-panel-header-btn" data-action="new-conversation" type="button" title="New conversation">\n <i class="bi bi-plus-lg"></i>\n </button>\n <button class="assistant-panel-header-btn" data-action="fullscreen" type="button" title="Open fullscreen">\n <i class="bi bi-arrows-fullscreen"></i>\n </button>\n <button class="assistant-panel-header-btn" data-action="pop-out" type="button" title="Open in popup window">\n <i class="bi bi-box-arrow-up-right"></i>\n </button>\n <button class="assistant-panel-header-btn" data-action="close-panel" type="button" title="Close">\n <i class="bi bi-x-lg"></i>\n </button>\n </div>\n </div>\n\n <div class="assistant-panel-history d-none" data-ref="history" data-container="conversation-list"></div>\n\n <div class="assistant-panel-chat" data-ref="chat-wrapper">\n <div class="assistant-welcome" data-ref="welcome">\n <div class="assistant-welcome-content">\n <div class="assistant-welcome-icon">\n <i class="bi bi-stars"></i>\n </div>\n <h3 class="assistant-welcome-title">Hi ${this._escapeHtml(this.app?.activeUser?.get("first_name")||"there")}</h3>\n <p class="assistant-welcome-subtitle">How can I help you today?</p>\n <div class="assistant-suggestions">\n <button class="assistant-suggestion" data-action="use-suggestion" data-text="Show me a summary of recent activity">\n <i class="bi bi-activity"></i>\n <span>Recent activity summary</span>\n </button>\n <button class="assistant-suggestion" data-action="use-suggestion" data-text="How many active users are there?">\n <i class="bi bi-people"></i>\n <span>Active user count</span>\n </button>\n </div>\n </div>\n </div>\n <div class="assistant-chat-area" data-container="chat-area"></div>\n <div class="assistant-input-wrapper">\n <div class="assistant-input-status d-none" data-ref="input-status"></div>\n <div class="assistant-input-box">\n <textarea class="assistant-input" placeholder="Message the assistant..." rows="1" data-ref="input"></textarea>\n <button class="assistant-send-btn" data-action="send" type="button" title="Send message" data-ref="send-btn">\n <i class="bi bi-arrow-up"></i>\n </button>\n <button class="assistant-stop-btn d-none" data-action="stop" type="button" title="Stop generating" data-ref="stop-btn">\n <i class="bi bi-stop-fill"></i>\n </button>\n </div>\n <div class="assistant-input-footer">\n <span class="assistant-connection-indicator" data-ref="status">\n <span class="status-dot connected"></span>\n </span>\n <span class="text-muted">Enter to send</span>\n </div>\n </div>\n </div>\n </div>\n `}async onInit(){this.conversations=new e,this.conversations.params.user=this.app?.activeUser?.id,this.conversationListView=new i({containerId:"conversation-list",collection:this.conversations}),this.addChild(this.conversationListView),this.chatView=new s({containerId:"chat-area",theme:"compact",messageViewClass:a,currentUserId:this.app?.activeUser?.id,showFileInput:!1,showInput:!1,adapter:this._createAdapter()}),this.addChild(this.chatView);const t=this.chatView.addMessage.bind(this.chatView);this.chatView.addMessage=(s,e)=>{t(s,e),"assistant"===s.role&&(s.content||s.blocks?.length)&&(this.chatView.hideThinking(),this._setInputEnabled(!0))},this.conversationListView.on("conversation:select",t=>{this._onConversationSelect(t),this._toggleHistory(!1)}),this.conversationListView.on("conversation:new",()=>{this._onNewConversation(),this._toggleHistory(!1)}),this.conversationListView.on("conversation:deleted",t=>this._onConversationDeleted(t)),this._subscribeWS()}async onAfterRender(){await super.onAfterRender();const t=this.element.querySelector('[data-ref="input"]');t&&(t.addEventListener("input",()=>this._autoResize(t)),t.addEventListener("keydown",t=>this._handleKeydown(t)),setTimeout(()=>t.focus(),100)),this.conversationId&&(this._showChatArea(),await this.chatView.refresh()),this._updateConnectionStatus(),this._updateTitle(),this._setupResizeHandle()}_setupResizeHandle(){const t=this.element?.querySelector('[data-ref="resize-handle"]');if(!t)return;const s="mojo:assistant_panel_width",e=localStorage.getItem(s);if(e){const t=parseInt(e,10);if(t>=300&&t<=700){const s=document.getElementById("assistant-panel");s&&(s.style.width=t+"px")}}let n,i;const a=t=>{const s=n-t.clientX,e=Math.min(700,Math.max(300,i+s)),a=document.getElementById("assistant-panel");a&&(a.style.width=e+"px")},o=()=>{document.removeEventListener("mousemove",a),document.removeEventListener("mouseup",o),document.body.style.cursor="",document.body.style.userSelect="";const t=document.getElementById("assistant-panel");t&&localStorage.setItem(s,parseInt(t.style.width,10))};t.addEventListener("mousedown",t=>{t.preventDefault(),n=t.clientX;const s=document.getElementById("assistant-panel");i=s?s.offsetWidth:500,document.body.style.cursor="col-resize",document.body.style.userSelect="none",document.addEventListener("mousemove",a),document.addEventListener("mouseup",o)})}onActionToggleHistory(){this._toggleHistory(!this._showingHistory)}onActionNewConversation(){this._onNewConversation(),this._showingHistory&&this._toggleHistory(!1)}onActionClosePanel(){this.emit("panel:close")}onActionFullscreen(){this.emit("panel:fullscreen",{conversationId:this.conversationId})}onActionPopOut(){this.emit("panel:popout",{conversationId:this.conversationId})}onActionUseSuggestion(t,s){const e=s.dataset.text||s.closest("[data-text]")?.dataset.text;if(!e)return;const n=this.element.querySelector('[data-ref="input"]');n&&(n.value=e,this._autoResize(n)),this._sendMessage()}onActionSend(){this._sendMessage()}onActionStop(){this.chatView.hideThinking(),this._setInputEnabled(!0),this._showSystemMessage("Response cancelled.");const t=this.element?.querySelector('[data-ref="input"]');t&&t.focus()}_toggleHistory(t){this._showingHistory=t;const s=this.element?.querySelector('[data-ref="history"]'),e=this.element?.querySelector('[data-ref="chat-wrapper"]'),n=this.element?.querySelector('[data-action="toggle-history"] i');s&&s.classList.toggle("d-none",!t),e&&e.classList.toggle("d-none",t),n&&(n.className=t?"bi bi-chat-dots":"bi bi-list"),t&&this.conversationListView.refresh()}_autoResize(t){t.style.height="auto",t.style.height=Math.min(t.scrollHeight,200)+"px"}_handleKeydown(t){"Enter"!==t.key||t.shiftKey||(t.preventDefault(),this._sendMessage())}async _sendMessage(){const t=this.element.querySelector('[data-ref="input"]');if(!t)return;const s=t.value.trim();s&&(t.value="",t.style.height="auto",this._showChatArea(),await this.chatView.adapter.addNote({text:s,files:[]}))}_showChatArea(){if(this._hasMessages)return;this._hasMessages=!0;const t=this.element.querySelector('[data-ref="welcome"]'),s=this.element.querySelector('[data-container="chat-area"]');t&&t.classList.add("d-none"),s&&s.classList.remove("d-none")}_showWelcome(){this._hasMessages=!1;const t=this.element.querySelector('[data-ref="welcome"]'),s=this.element.querySelector('[data-container="chat-area"]');t&&t.classList.remove("d-none"),s&&s.classList.add("d-none")}_setInputEnabled(t,s){const e=this.element?.querySelector('[data-ref="input"]'),n=this.element?.querySelector('[data-ref="send-btn"]'),i=this.element?.querySelector('[data-ref="stop-btn"]');e&&(e.disabled=!t),n&&n.classList.toggle("d-none",!t),i&&i.classList.toggle("d-none",t),this._setInputStatus(t?null:s),this._responseTimeout&&clearTimeout(this._responseTimeout),t?this._requestStartTime=null:this._responseTimeout=setTimeout(()=>this._onResponseTimeout(),6e4)}_setInputStatus(t){const s=this.element?.querySelector('[data-ref="input-status"]');s&&(t?(s.innerHTML=`${this._escapeHtml(t)} <span class="assistant-input-status-dismiss">Click to dismiss</span>`,s.classList.remove("d-none"),s._hasDismiss||(s._hasDismiss=!0,s.addEventListener("click",()=>{this.chatView.hideThinking(),this._setInputEnabled(!0);const t=this.element?.querySelector('[data-ref="input"]');t&&t.focus()}))):(s.classList.add("d-none"),s.innerHTML=""))}_onResponseTimeout(){this._responseTimeout=null,this.chatView.hideThinking(),this._setInputEnabled(!0),this._showSystemMessage("Request timed out. Please try again.")}_updateTitle(t){const s=this.element?.querySelector('[data-ref="panel-title"]');s&&(s.textContent=t||(this.conversationId?"Assistant":"New conversation"))}_createAdapter(){return{fetch:async()=>{if(!this.conversationId)return[];try{const t=new n({id:this.conversationId});await t.fetch({graph:"detail"});const s=t.get("title")||t.get("summary");s&&this._updateTitle(s);const e=(t.get("messages")||[]).map(t=>this._transformMessage(t)).filter(Boolean);return o._collapseMessages(e)}catch(t){return 404===t.status&&(this._onNewConversation(),this._showSystemMessage("Conversation not found.")),[]}},addNote:async t=>{if(!t.text||!t.text.trim())return{success:!1};const s={id:"local-"+ ++this._messageIdCounter,role:"user",author:{id:this.app?.activeUser?.id,name:this.app?.activeUser?.get("display_name")||"You"},content:t.text,timestamp:/* @__PURE__ */(new Date).toISOString()};if(this.chatView.addMessage(s),this.chatView.showThinking("Thinking..."),this._requestStartTime=Date.now(),this._setInputEnabled(!1,"Waiting for response…"),this.ws&&this.ws.isConnected)this.ws.send({type:"assistant_message",message:t.text,conversation_id:this.conversationId});else try{const s=await this.app.rest.post("/api/assistant",{message:t.text,conversation_id:this.conversationId}),e=s?.data?.data||s?.data||s;e.conversation_id&&(this.conversationId=e.conversation_id,this.app._assistantConversationId=this.conversationId),e.response&&this.chatView.addMessage(this._transformMessage(e.response)),this._setInputEnabled(!0)}catch(e){this._handleAPIError(e)}return{success:!0}}}}_subscribeWS(){this.ws&&(this._wsHandlers={thinking:t=>this._onThinking(t),text:t=>this._onText(t),tool_call:t=>this._onToolCall(t),response:t=>this._onResponse(t),error:t=>this._onError(t),plan:t=>this._onPlan(t),plan_update:t=>this._onPlanUpdate(t),message:t=>this._dispatchWSMessage(t),connected:()=>this._updateConnectionStatus(),disconnected:()=>this._updateConnectionStatus(),reconnecting:()=>this._updateConnectionStatus()},this.ws.on("message:assistant_thinking",this._wsHandlers.thinking),this.ws.on("message:assistant_text",this._wsHandlers.text),this.ws.on("message:assistant_tool_call",this._wsHandlers.tool_call),this.ws.on("message:assistant_response",this._wsHandlers.response),this.ws.on("message:assistant_error",this._wsHandlers.error),this.ws.on("message:assistant_plan",this._wsHandlers.plan),this.ws.on("message:assistant_plan_update",this._wsHandlers.plan_update),this.ws.on("message:message",this._wsHandlers.message),this.ws.on("connected",this._wsHandlers.connected),this.ws.on("disconnected",this._wsHandlers.disconnected),this.ws.on("reconnecting",this._wsHandlers.reconnecting))}_unsubscribeWS(){this.ws&&this._wsHandlers&&(this.ws.off("message:assistant_thinking",this._wsHandlers.thinking),this.ws.off("message:assistant_text",this._wsHandlers.text),this.ws.off("message:assistant_tool_call",this._wsHandlers.tool_call),this.ws.off("message:assistant_response",this._wsHandlers.response),this.ws.off("message:assistant_error",this._wsHandlers.error),this.ws.off("message:assistant_plan",this._wsHandlers.plan),this.ws.off("message:assistant_plan_update",this._wsHandlers.plan_update),this.ws.off("message:message",this._wsHandlers.message),this.ws.off("connected",this._wsHandlers.connected),this.ws.off("disconnected",this._wsHandlers.disconnected),this.ws.off("reconnecting",this._wsHandlers.reconnecting),this._wsHandlers={})}_dispatchWSMessage(t){const s=t?.data;if(s?.type)switch(s.type){case"assistant_thinking":this._onThinking(s);break;case"assistant_text":this._onText(s);break;case"assistant_tool_call":this._onToolCall(s);break;case"assistant_response":this._onResponse(s);break;case"assistant_error":this._onError(s);break;case"assistant_plan":this._onPlan(s);break;case"assistant_plan_update":this._onPlanUpdate(s)}}_isMyConversation(t){return!t.conversation_id||!this.conversationId||String(t.conversation_id)===String(this.conversationId)}_adoptConversationId(t){t.conversation_id&&!this.conversationId&&(this.conversationId=t.conversation_id,this.app._assistantConversationId=this.conversationId)}_onThinking(t){this._isMyConversation(t)&&(this._adoptConversationId(t),this._showChatArea(),this.chatView.showThinking("Thinking..."),this._setInputEnabled(!1,"Assistant is thinking…"))}_onText(t){if(!this._isMyConversation(t))return;this._adoptConversationId(t),this._resetResponseTimeout();const s=this._transformMessage({id:t.message_id||"text-"+ ++this._messageIdCounter,role:"assistant",content:t.text||"",blocks:t.blocks||[],tool_calls:[],created:t.created||t.timestamp||/* @__PURE__ */(new Date).toISOString()});s&&(s.content||s.blocks?.length)&&this.chatView.addMessage(s)}_onToolCall(t){this._isMyConversation(t)&&(this.chatView.showThinking(`Using ${t.tool||t.name||"tool"}...`),this._resetResponseTimeout())}_resetResponseTimeout(){if(this._responseTimeout){if(this._requestStartTime&&Date.now()-this._requestStartTime>=3e5)return void this._onResponseTimeout();clearTimeout(this._responseTimeout),this._responseTimeout=setTimeout(()=>this._onResponseTimeout(),6e4)}}_onResponse(t){if(!this._isMyConversation(t))return;this.chatView.hideThinking(),this._setInputEnabled(!0),this._adoptConversationId(t);const s=this.element?.querySelector('[data-ref="input"]');s&&s.focus();const e=this._transformMessage({id:t.message_id||"resp-"+ ++this._messageIdCounter,role:"assistant",content:t.response||t.content||t.message||"",blocks:t.blocks||[],tool_calls:t.tool_calls_made||t.tool_calls||[],created:t.created||t.timestamp||/* @__PURE__ */(new Date).toISOString()});e&&(e.content||e.blocks?.length||e.tool_calls?.length)&&this.chatView.addMessage(e)}_onError(t){if(!this._isMyConversation(t))return;this.chatView.hideThinking(),this._setInputEnabled(!0),this._adoptConversationId(t);const s=t.error||t.message||"An error occurred";this._showSystemMessage(s)}_onPlan(t){if(!this._isMyConversation(t))return;this._adoptConversationId(t),this._showChatArea();const s=t.plan;s&&(this._activePlans[s.plan_id]=s,this.chatView.addMessage({id:`plan-${s.plan_id}`,role:"assistant",author:{name:"Assistant"},content:"",timestamp:/* @__PURE__ */(new Date).toISOString(),blocks:[{type:"progress",...s}],tool_calls:[]}))}_onPlanUpdate(t){if(!this._isMyConversation(t))return;const s=this._activePlans[t.plan_id];if(s){const e=s.steps.find(s=>s.id===t.step_id);e&&(e.status=t.status,e.summary=t.summary)}const e=this.chatView.messageViews.get(`plan-${t.plan_id}`);e?.updateProgressStep&&e.updateProgressStep(t.plan_id,t.step_id,t.status,t.summary),this._resetResponseTimeout()}async _onConversationSelect(t){this.conversationId=t.id,this.app._assistantConversationId=this.conversationId,this.conversationListView.setActive(t.id),this._showChatArea(),this._updateTitle(t.model?.get("title")||t.model?.get("summary")),await this.chatView.refresh()}_onNewConversation(){this.conversationId=null,this.app._assistantConversationId=null,this.conversationListView.setActive(null),this.chatView.clearMessages(),this._setInputEnabled(!0),this._showWelcome(),this._updateTitle();const t=this.element?.querySelector('[data-ref="input"]');t&&t.focus()}_onConversationDeleted(t){String(t.id)===String(this.conversationId)&&this._onNewConversation()}_transformMessage(t){if("tool_result"===t.role)return null;let s=t.content||t.text||"",e=t.blocks||[],n=t.tool_calls||[];if(n.length>0){n=n.map(t=>!t.type&&t.tool?{type:"tool_use",name:t.tool,input:t.input}:t);const t=n.filter(t=>"text"===t.type&&t.text).map(t=>t.text);!s&&t.length>0&&(s=t.join("\n\n")),n=n.filter(t=>"tool_use"===t.type).filter(t=>!o.INTERNAL_TOOLS.has(t.name))}if(0===e.length&&s.includes("assistant_block")){const t=o._parseBlocks(s);s=t.content,e=t.blocks}const i=this.app?.activeUser?.id;return{id:t.id,role:t.role||"user",author:"assistant"===t.role?{name:"Assistant"}:t.author||{name:t.user?.display_name||this.app?.activeUser?.get("display_name")||"You",id:t.user?.id||i},content:s,timestamp:t.created||t.timestamp,blocks:e,tool_calls:n,_conversationId:this.conversationId}}_showSystemMessage(t){this._showChatArea(),this.chatView.addMessage({id:"sys-"+ ++this._messageIdCounter,type:"system_event",content:t,timestamp:/* @__PURE__ */(new Date).toISOString()})}_handleAPIError(t){404===t.status?this._showSystemMessage("Assistant is not enabled on this server."):503===t.status?this._showSystemMessage("LLM API key not configured. Contact your administrator."):this._showSystemMessage("Failed to send message. Please try again."),this._setInputEnabled(!0)}_updateConnectionStatus(){const t=this.element?.querySelector(".status-dot");t&&(this.ws?.isConnected?(t.className="status-dot connected",t.title="Connected",this._responseTimeout?this._setInputEnabled(!1,"Waiting for response…"):this._setInputEnabled(!0)):this.ws?.isReconnecting?(t.className="status-dot reconnecting",t.title="Reconnecting...",this._setInputEnabled(!1,"Reconnecting…"),this._responseTimeout&&(clearTimeout(this._responseTimeout),this._responseTimeout=null)):(t.className="status-dot disconnected",t.title="Disconnected",this._setInputEnabled(!1,"Disconnected — reconnecting…"),this._responseTimeout&&(clearTimeout(this._responseTimeout),this._responseTimeout=null)))}_escapeHtml(t){const s=document.createElement("div");return s.textContent=t,s.innerHTML}focusInput(){const t=this.element?.querySelector('[data-ref="input"]');t&&t.focus()}async onBeforeDestroy(){this._unsubscribeWS(),this._responseTimeout&&(clearTimeout(this._responseTimeout),this._responseTimeout=null)}}export{AssistantPanelView as default};
|
|
2
|
+
//# sourceMappingURL=AssistantPanelView-BG34Qbfj.js.map
|