@samanhappy/mcphub 1.0.1 → 1.0.2
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/dist/betterAuth.js +21 -0
- package/dist/betterAuth.js.map +1 -1
- package/dist/controllers/serverController.js +3 -0
- package/dist/controllers/serverController.js.map +1 -1
- package/dist/dao/ActivityDao.js +2 -0
- package/dist/dao/ActivityDao.js.map +1 -1
- package/dist/db/entities/Activity.js +4 -0
- package/dist/db/entities/Activity.js.map +1 -1
- package/dist/services/activityLoggingService.js +1 -0
- package/dist/services/activityLoggingService.js.map +1 -1
- package/dist/services/betterAuthConfig.js +18 -1
- package/dist/services/betterAuthConfig.js.map +1 -1
- package/dist/services/mcpService.js +41 -12
- package/dist/services/mcpService.js.map +1 -1
- package/dist/utils/rateLimit.js +3 -3
- package/frontend/dist/assets/ActivityPage-B1B9ySGe.js +2 -0
- package/frontend/dist/assets/ActivityPage-B1B9ySGe.js.map +1 -0
- package/frontend/dist/assets/{Dashboard-BUCJcvk-.js → Dashboard-CYzpYZ1d.js} +2 -2
- package/frontend/dist/assets/{Dashboard-BUCJcvk-.js.map → Dashboard-CYzpYZ1d.js.map} +1 -1
- package/frontend/dist/assets/{EndpointCopy-D5NjDdYi.js → EndpointCopy-DVmlWW-s.js} +2 -2
- package/frontend/dist/assets/{EndpointCopy-D5NjDdYi.js.map → EndpointCopy-DVmlWW-s.js.map} +1 -1
- package/frontend/dist/assets/{GroupsPage-DfLlww4U.js → GroupsPage-CsyoUc8S.js} +2 -2
- package/frontend/dist/assets/{GroupsPage-DfLlww4U.js.map → GroupsPage-CsyoUc8S.js.map} +1 -1
- package/frontend/dist/assets/LoginPage-C3t8hbb2.js +2 -0
- package/frontend/dist/assets/LoginPage-C3t8hbb2.js.map +1 -0
- package/frontend/dist/assets/{LogsPage-CTa8kuDf.js → LogsPage-DOZeagVs.js} +2 -2
- package/frontend/dist/assets/{LogsPage-CTa8kuDf.js.map → LogsPage-DOZeagVs.js.map} +1 -1
- package/frontend/dist/assets/{MarketPage-C2Rh4WJB.js → MarketPage-kMEHUGfJ.js} +2 -2
- package/frontend/dist/assets/{MarketPage-C2Rh4WJB.js.map → MarketPage-kMEHUGfJ.js.map} +1 -1
- package/frontend/dist/assets/{PromptsPage-Dh3qjX3x.js → PromptsPage-D7JYoTav.js} +2 -2
- package/frontend/dist/assets/{PromptsPage-Dh3qjX3x.js.map → PromptsPage-D7JYoTav.js.map} +1 -1
- package/frontend/dist/assets/{ResourcesPage-Bc5ZpCIh.js → ResourcesPage-BlwePI9a.js} +2 -2
- package/frontend/dist/assets/{ResourcesPage-Bc5ZpCIh.js.map → ResourcesPage-BlwePI9a.js.map} +1 -1
- package/frontend/dist/assets/{ServersPage-hgCbCglG.js → ServersPage-DrkPpCgK.js} +4 -4
- package/frontend/dist/assets/{ServersPage-hgCbCglG.js.map → ServersPage-DrkPpCgK.js.map} +1 -1
- package/frontend/dist/assets/{SettingsPage-BzNX8mXv.js → SettingsPage-BWigWLml.js} +2 -2
- package/frontend/dist/assets/{SettingsPage-BzNX8mXv.js.map → SettingsPage-BWigWLml.js.map} +1 -1
- package/frontend/dist/assets/{StatusDot-CQzailBQ.js → StatusDot-BDBIaafQ.js} +2 -2
- package/frontend/dist/assets/{StatusDot-CQzailBQ.js.map → StatusDot-BDBIaafQ.js.map} +1 -1
- package/frontend/dist/assets/{ToggleGroup-CNBBvo3C.js → ToggleGroup-OOcsllhw.js} +2 -2
- package/frontend/dist/assets/{ToggleGroup-CNBBvo3C.js.map → ToggleGroup-OOcsllhw.js.map} +1 -1
- package/frontend/dist/assets/{UsersPage-C33b7LCM.js → UsersPage-DL8E7KtW.js} +2 -2
- package/frontend/dist/assets/{UsersPage-C33b7LCM.js.map → UsersPage-DL8E7KtW.js.map} +1 -1
- package/frontend/dist/assets/index-C7wNc_3N.js +3 -0
- package/frontend/dist/assets/index-C7wNc_3N.js.map +1 -0
- package/frontend/dist/assets/{resourceService-C6umWRgq.js → resourceService-B-U4FKGB.js} +2 -2
- package/frontend/dist/assets/{resourceService-C6umWRgq.js.map → resourceService-B-U4FKGB.js.map} +1 -1
- package/frontend/dist/assets/{useServerData-P5In98R4.js → useServerData-DYoDryJj.js} +2 -2
- package/frontend/dist/assets/{useServerData-P5In98R4.js.map → useServerData-DYoDryJj.js.map} +1 -1
- package/frontend/dist/assets/useSettingsData-6utb1Z46.js +2 -0
- package/frontend/dist/assets/{useSettingsData-Cz7vKGLE.js.map → useSettingsData-6utb1Z46.js.map} +1 -1
- package/frontend/dist/index.html +1 -1
- package/package.json +1 -1
- package/frontend/dist/assets/ActivityPage-DwzGiMh_.js +0 -2
- package/frontend/dist/assets/ActivityPage-DwzGiMh_.js.map +0 -1
- package/frontend/dist/assets/LoginPage-DCjqYw_8.js +0 -2
- package/frontend/dist/assets/LoginPage-DCjqYw_8.js.map +0 -1
- package/frontend/dist/assets/index-BGiKkKzj.js +0 -3
- package/frontend/dist/assets/index-BGiKkKzj.js.map +0 -1
- package/frontend/dist/assets/useSettingsData-Cz7vKGLE.js +0 -2
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{b as F,j as e,r as n,u as Q}from"./framework-vendor-BUhDPOUZ.js";import{u as X,g as Y,G as A,T as Z,L as ee,a as se,s as te,b as D,c as ae}from"./index-C7wNc_3N.js";import{u as G}from"./i18n-vendor-Kbr87Ofu.js";import{B as re,j as O}from"./icons-vendor-CKgJB3SC.js";const ne=({isOpen:s,onClose:o})=>{const{t:c}=G(),d=F();if(!s)return null;const f=()=>{o(),d("/settings"),setTimeout(()=>{const l=document.querySelector('[data-section="password"]');if(l){l.scrollIntoView({behavior:"smooth",block:"start"});const h=l.querySelector('[role="button"]');h&&!l.querySelector(".mt-4")&&h.click()}},100)},b=l=>{l.target===l.currentTarget&&o()},u=l=>{l.key==="Escape"&&o()};return e.jsx("div",{className:"fixed inset-0 bg-black/50 z-[100] flex items-center justify-center p-4",onClick:b,onKeyDown:u,tabIndex:-1,children:e.jsx("div",{className:"bg-white dark:bg-gray-800 rounded-lg shadow-xl max-w-md w-full transform transition-all duration-200 ease-out",role:"dialog","aria-modal":"true","aria-labelledby":"password-warning-title","aria-describedby":"password-warning-message",children:e.jsxs("div",{className:"p-6",children:[e.jsxs("div",{className:"flex items-start space-x-3",children:[e.jsx("div",{className:"flex-shrink-0",children:e.jsx("svg",{className:"w-6 h-6 text-yellow-600 dark:text-yellow-400",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",children:e.jsx("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z"})})}),e.jsxs("div",{className:"flex-1",children:[e.jsx("h3",{id:"password-warning-title",className:"text-lg font-medium text-gray-900 dark:text-white mb-2",children:c("auth.defaultPasswordWarning")}),e.jsx("p",{id:"password-warning-message",className:"text-gray-600 dark:text-gray-300 leading-relaxed",children:c("auth.defaultPasswordMessage")})]})]}),e.jsxs("div",{className:"flex justify-end space-x-3 mt-6",children:[e.jsx("button",{onClick:o,className:"hub-btn",children:c("common.cancel")}),e.jsx("button",{onClick:f,className:"hub-btn primary",autoFocus:!0,children:c("auth.goToSettings")})]})]})})})},le=s=>{if(!s)return null;try{const o=typeof window<"u"?window.location.origin:"http://localhost",c=new URL(s,o);return c.origin!==o?null:`${c.pathname}${c.search}${c.hash}`||"/"}catch{return s.startsWith("/")&&!s.startsWith("//")?s:null}},ue=()=>{const{t:s}=G(),[o,c]=n.useState(""),[d,f]=n.useState(""),[b,u]=n.useState(null),[l,h]=n.useState(!1),[g,j]=n.useState(null),[y,w]=n.useState(null),[k,M]=n.useState(void 0),[m,N]=n.useState({google:!1,github:!1,oidc:!1}),[q,H]=n.useState("oidc"),[K,S]=n.useState(!1),{login:_,auth:p}=X(),C=Q(),L=F(),i=n.useMemo(()=>{const a=new URLSearchParams(C.search);return le(a.get("returnUrl"))},[C.search]),P=n.useCallback(a=>{if(!a)return!1;const t=a.toLowerCase();return t.includes("failed to fetch")||t.includes("networkerror")||t.includes("network error")||t.includes("connection refused")||t.includes("unable to connect")||t.includes("fetch error")||t.includes("econnrefused")||t.includes("http 500")||t.includes("internal server error")||t.includes("proxy error")},[]),U=n.useCallback(()=>{if(!i)return"/";if(!i.startsWith("/oauth/authorize"))return i;const a=Y();if(!a)return i;try{const t=window.location.origin,r=new URL(i,t);return r.searchParams.set("token",a),`${r.pathname}${r.search}${r.hash}`}catch{const t=i.includes("?")?"&":"?";return`${i}${t}token=${encodeURIComponent(a)}`}},[i]),x=n.useCallback(()=>{i?window.location.assign(U()):L("/")},[U,L,i]);n.useEffect(()=>{!p.loading&&p.isAuthenticated&&x()},[p.isAuthenticated,p.loading,x]),n.useEffect(()=>{(async()=>{var R,z,I,W,T,B,E,$;const r=(await se()).betterAuth;if(!(r!=null&&r.enabled)){N({google:!1,github:!1,oidc:!1});return}M(r.basePath),H(((z=(R=r.providers)==null?void 0:R.oidc)==null?void 0:z.providerId)||"oidc"),N({google:((W=(I=r.providers)==null?void 0:I.google)==null?void 0:W.enabled)===!0,github:((B=(T=r.providers)==null?void 0:T.github)==null?void 0:B.enabled)===!0,oidc:(($=(E=r.providers)==null?void 0:E.oidc)==null?void 0:$.enabled)===!0})})()},[]);const V=async a=>{a.preventDefault(),u(null),w(null),h(!0);try{if(!o||!d){u(s("auth.emptyFields")),h(!1);return}const t=await _(o,d);if(t.success)t.isUsingDefaultPassword?S(!0):x();else{const r=t.message;u(P(r)?s("auth.serverUnavailable"):s("auth.loginFailed"))}}catch(t){const r=t instanceof Error?t.message:void 0;u(P(r)?s("auth.serverUnavailable"):s("auth.loginError"))}finally{h(!1)}},v=async a=>{w(null),j(a);try{if(a==="oidc"){await te({providerId:q,callbackURL:i||"/",errorCallbackURL:`${D()}/login`,basePathOverride:k});return}await ae(k).signIn.social({provider:a,callbackURL:i||"/",errorCallbackURL:`${D()}/login`})}catch(t){console.error("Social login error:",t),w(s("auth.socialLoginFailed")),j(null)}},J=()=>{S(!1),x()};return e.jsxs("div",{className:"relative min-h-screen w-full overflow-hidden",style:{background:"var(--hub-bg)",color:"var(--hub-ink)"},children:[e.jsxs("div",{className:"absolute top-3 right-4 z-20 flex items-center gap-1",children:[e.jsx("a",{href:"https://github.com/samanhappy/mcphub",target:"_blank",rel:"noopener noreferrer",className:"hub-icon-btn","aria-label":"GitHub Repository",children:e.jsx(A,{className:"h-4 w-4"})}),e.jsx("a",{href:"https://docs.mcphub.app",target:"_blank",rel:"noopener noreferrer",className:"hub-icon-btn","aria-label":"Documentation",children:e.jsx(re,{className:"h-4 w-4"})}),e.jsx(Z,{}),e.jsx(ee,{})]}),e.jsx("div",{className:"pointer-events-none absolute inset-0 -z-10",children:e.jsxs("svg",{className:"h-full w-full",style:{opacity:.5},xmlns:"http://www.w3.org/2000/svg",children:[e.jsx("defs",{children:e.jsx("pattern",{id:"grid",width:"32",height:"32",patternUnits:"userSpaceOnUse",children:e.jsx("path",{d:"M 32 0 L 0 0 0 32",fill:"none",stroke:"var(--hub-line-2)",strokeWidth:"0.5"})})}),e.jsx("rect",{width:"100%",height:"100%",fill:"url(#grid)"})]})}),e.jsx("div",{className:"relative mx-auto flex min-h-screen w-full max-w-md items-center justify-center px-6",children:e.jsxs("div",{className:"w-full space-y-8",children:[e.jsxs("div",{className:"flex flex-col items-center gap-3",children:[e.jsxs("div",{className:"relative grid place-items-center",style:{width:44,height:44,borderRadius:10,background:"var(--hub-ink)",color:"white"},children:[e.jsx("span",{className:"hub-mono font-semibold",style:{fontSize:18},children:"M"}),e.jsx("span",{className:"absolute",style:{right:-2,bottom:-2,width:8,height:8,borderRadius:50,background:"var(--hub-ok)",boxShadow:"0 0 0 3px var(--hub-bg)"}})]}),e.jsxs("div",{className:"text-center",children:[e.jsx("h1",{style:{fontSize:20,fontWeight:600,letterSpacing:"-0.02em",color:"var(--hub-ink)"},children:s("app.title")}),e.jsx("p",{className:"hub-sub",style:{marginTop:4},children:s("auth.slogan")})]})]}),e.jsxs("div",{className:"hub-card",style:{padding:"22px 22px 20px",boxShadow:"0 1px 2px rgba(0,0,0,0.02)"},children:[e.jsxs("form",{className:"space-y-3",onSubmit:V,children:[e.jsxs("div",{children:[e.jsx("label",{htmlFor:"username",className:"hub-sect block",style:{marginBottom:6},children:s("auth.username")}),e.jsx("input",{id:"username",name:"username",type:"text",autoComplete:"username",required:!0,className:"hub-input",placeholder:s("auth.username"),value:o,onChange:a=>c(a.target.value)})]}),e.jsxs("div",{children:[e.jsx("label",{htmlFor:"password",className:"hub-sect block",style:{marginBottom:6},children:s("auth.password")}),e.jsx("input",{id:"password",name:"password",type:"password",autoComplete:"current-password",required:!0,className:"hub-input",placeholder:s("auth.password"),value:d,onChange:a=>f(a.target.value)})]}),b&&e.jsxs("div",{className:"flex items-center gap-2",style:{padding:"8px 10px",borderRadius:7,border:"1px solid oklch(0.85 0.1 25)",background:"oklch(0.97 0.03 25)",color:"oklch(0.4 0.18 25)",fontSize:12.5},children:[e.jsx(O,{size:13,className:"flex-shrink-0"}),e.jsx("span",{children:b})]}),e.jsx("button",{type:"submit",disabled:l,className:"hub-btn primary w-full justify-center",style:{height:34},children:s(l?"auth.loggingIn":"auth.login")})]}),(m.google||m.github||m.oidc)&&e.jsxs("div",{className:"mt-5 space-y-3",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("div",{className:"h-px flex-1",style:{background:"var(--hub-line)"}}),e.jsx("span",{className:"hub-sect",style:{textTransform:"uppercase",letterSpacing:"0.08em"},children:s("auth.orContinue")}),e.jsx("div",{className:"h-px flex-1",style:{background:"var(--hub-line)"}})]}),y&&e.jsxs("div",{className:"flex items-center gap-2",style:{padding:"8px 10px",borderRadius:7,border:"1px solid oklch(0.85 0.1 25)",background:"oklch(0.97 0.03 25)",color:"oklch(0.4 0.18 25)",fontSize:12.5},children:[e.jsx(O,{size:13,className:"flex-shrink-0"}),e.jsx("span",{children:y})]}),e.jsxs("div",{className:"space-y-2",children:[m.google&&e.jsx("button",{type:"button",onClick:()=>v("google"),disabled:g!==null,className:"hub-btn w-full justify-center",style:{height:34},children:s(g==="google"?"auth.loggingIn":"auth.loginWithGoogle")}),m.github&&e.jsxs("button",{type:"button",onClick:()=>v("github"),disabled:g!==null,className:"hub-btn w-full justify-center",style:{height:34,background:"var(--hub-ink)",color:"var(--hub-bg)",borderColor:"var(--hub-ink)"},children:[e.jsx(A,{className:"h-3.5 w-3.5"}),s(g==="github"?"auth.loggingIn":"auth.loginWithGithub")]}),m.oidc&&e.jsx("button",{type:"button",onClick:()=>v("oidc"),disabled:g!==null,className:"hub-btn w-full justify-center",style:{height:34},children:s(g==="oidc"?"auth.loggingIn":"auth.loginWithOIDC")})]})]})]}),e.jsxs("p",{className:"text-center hub-mono",style:{fontSize:11,color:"var(--hub-ink-3)"},children:["v","1.0.2"]})]})}),e.jsx(ne,{isOpen:K,onClose:J})]})};export{ue as default};
|
|
2
|
+
//# sourceMappingURL=LoginPage-C3t8hbb2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LoginPage-C3t8hbb2.js","sources":["../../src/components/ui/DefaultPasswordWarningModal.tsx","../../src/pages/LoginPage.tsx"],"sourcesContent":["import React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { useNavigate } from 'react-router-dom';\n\ninterface DefaultPasswordWarningModalProps {\n isOpen: boolean;\n onClose: () => void;\n}\n\nconst DefaultPasswordWarningModal: React.FC<DefaultPasswordWarningModalProps> = ({\n isOpen,\n onClose,\n}) => {\n const { t } = useTranslation();\n const navigate = useNavigate();\n\n if (!isOpen) return null;\n\n const handleGoToSettings = () => {\n onClose();\n navigate('/settings');\n // Auto-scroll to password section after a small delay to ensure page is loaded\n setTimeout(() => {\n const passwordSection = document.querySelector('[data-section=\"password\"]');\n if (passwordSection) {\n passwordSection.scrollIntoView({ behavior: 'smooth', block: 'start' });\n // If the section is collapsed, expand it\n const clickTarget = passwordSection.querySelector('[role=\"button\"]');\n if (clickTarget && !passwordSection.querySelector('.mt-4')) {\n (clickTarget as HTMLElement).click();\n }\n }\n }, 100);\n };\n\n const handleBackdropClick = (e: React.MouseEvent) => {\n if (e.target === e.currentTarget) {\n onClose();\n }\n };\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === 'Escape') {\n onClose();\n }\n };\n\n return (\n <div\n className=\"fixed inset-0 bg-black/50 z-[100] flex items-center justify-center p-4\"\n onClick={handleBackdropClick}\n onKeyDown={handleKeyDown}\n tabIndex={-1}\n >\n <div\n className=\"bg-white dark:bg-gray-800 rounded-lg shadow-xl max-w-md w-full transform transition-all duration-200 ease-out\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"password-warning-title\"\n aria-describedby=\"password-warning-message\"\n >\n <div className=\"p-6\">\n <div className=\"flex items-start space-x-3\">\n <div className=\"flex-shrink-0\">\n <svg\n className=\"w-6 h-6 text-yellow-600 dark:text-yellow-400\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z\"\n />\n </svg>\n </div>\n <div className=\"flex-1\">\n <h3\n id=\"password-warning-title\"\n className=\"text-lg font-medium text-gray-900 dark:text-white mb-2\"\n >\n {t('auth.defaultPasswordWarning')}\n </h3>\n <p\n id=\"password-warning-message\"\n className=\"text-gray-600 dark:text-gray-300 leading-relaxed\"\n >\n {t('auth.defaultPasswordMessage')}\n </p>\n </div>\n </div>\n\n <div className=\"flex justify-end space-x-3 mt-6\">\n <button\n onClick={onClose}\n className=\"hub-btn\"\n >\n {t('common.cancel')}\n </button>\n <button\n onClick={handleGoToSettings}\n className=\"hub-btn primary\"\n autoFocus\n >\n {t('auth.goToSettings')}\n </button>\n </div>\n </div>\n </div>\n </div>\n );\n};\n\nexport default DefaultPasswordWarningModal;\n","import React, { useState, useMemo, useCallback, useEffect } from 'react';\nimport { useLocation, useNavigate } from 'react-router-dom';\nimport { useTranslation } from 'react-i18next';\nimport { BookOpen, AlertCircle } from 'lucide-react';\nimport { useAuth } from '../contexts/AuthContext';\nimport { getToken } from '../services/authService';\nimport { getPublicConfig } from '../services/configService';\nimport { createBetterAuthClient, startOidcLogin } from '../services/betterAuthClient';\nimport { getBasePath } from '../utils/runtime';\nimport ThemeSwitch from '@/components/ui/ThemeSwitch';\nimport LanguageSwitch from '@/components/ui/LanguageSwitch';\nimport GitHubIcon from '@/components/icons/GitHubIcon';\nimport DefaultPasswordWarningModal from '@/components/ui/DefaultPasswordWarningModal';\n\ntype SocialProvider = 'google' | 'github' | 'oidc';\n\nconst sanitizeReturnUrl = (value: string | null): string | null => {\n if (!value) return null;\n try {\n const origin = typeof window !== 'undefined' ? window.location.origin : 'http://localhost';\n const url = new URL(value, origin);\n if (url.origin !== origin) return null;\n const relativePath = `${url.pathname}${url.search}${url.hash}`;\n return relativePath || '/';\n } catch {\n if (value.startsWith('/') && !value.startsWith('//')) return value;\n return null;\n }\n};\n\nconst LoginPage: React.FC = () => {\n const { t } = useTranslation();\n const [username, setUsername] = useState('');\n const [password, setPassword] = useState('');\n const [error, setError] = useState<string | null>(null);\n const [loading, setLoading] = useState(false);\n const [socialLoading, setSocialLoading] = useState<SocialProvider | null>(null);\n const [socialError, setSocialError] = useState<string | null>(null);\n const [betterAuthBasePath, setBetterAuthBasePath] = useState<string | undefined>(undefined);\n const [socialProviders, setSocialProviders] = useState({\n google: false,\n github: false,\n oidc: false,\n });\n const [oidcProviderId, setOidcProviderId] = useState<string>('oidc');\n const [showDefaultPasswordWarning, setShowDefaultPasswordWarning] = useState(false);\n const { login, auth } = useAuth();\n const location = useLocation();\n const navigate = useNavigate();\n const returnUrl = useMemo(() => {\n const params = new URLSearchParams(location.search);\n return sanitizeReturnUrl(params.get('returnUrl'));\n }, [location.search]);\n\n const isServerUnavailableError = useCallback((message?: string) => {\n if (!message) return false;\n const normalized = message.toLowerCase();\n return (\n normalized.includes('failed to fetch') ||\n normalized.includes('networkerror') ||\n normalized.includes('network error') ||\n normalized.includes('connection refused') ||\n normalized.includes('unable to connect') ||\n normalized.includes('fetch error') ||\n normalized.includes('econnrefused') ||\n normalized.includes('http 500') ||\n normalized.includes('internal server error') ||\n normalized.includes('proxy error')\n );\n }, []);\n\n const buildRedirectTarget = useCallback(() => {\n if (!returnUrl) return '/';\n if (!returnUrl.startsWith('/oauth/authorize')) return returnUrl;\n const token = getToken();\n if (!token) return returnUrl;\n try {\n const origin = window.location.origin;\n const url = new URL(returnUrl, origin);\n url.searchParams.set('token', token);\n return `${url.pathname}${url.search}${url.hash}`;\n } catch {\n const separator = returnUrl.includes('?') ? '&' : '?';\n return `${returnUrl}${separator}token=${encodeURIComponent(token)}`;\n }\n }, [returnUrl]);\n\n const redirectAfterLogin = useCallback(() => {\n if (returnUrl) {\n window.location.assign(buildRedirectTarget());\n } else {\n navigate('/');\n }\n }, [buildRedirectTarget, navigate, returnUrl]);\n\n useEffect(() => {\n if (!auth.loading && auth.isAuthenticated) redirectAfterLogin();\n }, [auth.isAuthenticated, auth.loading, redirectAfterLogin]);\n\n useEffect(() => {\n const loadAuthProviders = async () => {\n const publicConfig = await getPublicConfig();\n const betterAuth = publicConfig.betterAuth;\n if (!betterAuth?.enabled) {\n setSocialProviders({ google: false, github: false, oidc: false });\n return;\n }\n setBetterAuthBasePath(betterAuth.basePath);\n setOidcProviderId(betterAuth.providers?.oidc?.providerId || 'oidc');\n setSocialProviders({\n google: betterAuth.providers?.google?.enabled === true,\n github: betterAuth.providers?.github?.enabled === true,\n oidc: betterAuth.providers?.oidc?.enabled === true,\n });\n };\n loadAuthProviders();\n }, []);\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n setError(null);\n setSocialError(null);\n setLoading(true);\n try {\n if (!username || !password) {\n setError(t('auth.emptyFields'));\n setLoading(false);\n return;\n }\n const result = await login(username, password);\n if (result.success) {\n if (result.isUsingDefaultPassword) setShowDefaultPasswordWarning(true);\n else redirectAfterLogin();\n } else {\n const message = result.message;\n setError(isServerUnavailableError(message) ? t('auth.serverUnavailable') : t('auth.loginFailed'));\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : undefined;\n setError(isServerUnavailableError(message) ? t('auth.serverUnavailable') : t('auth.loginError'));\n } finally {\n setLoading(false);\n }\n };\n\n const handleSocialLogin = async (provider: SocialProvider) => {\n setSocialError(null);\n setSocialLoading(provider);\n try {\n if (provider === 'oidc') {\n await startOidcLogin({\n providerId: oidcProviderId,\n callbackURL: returnUrl || '/',\n errorCallbackURL: `${getBasePath()}/login`,\n basePathOverride: betterAuthBasePath,\n });\n return;\n }\n\n const client = createBetterAuthClient(betterAuthBasePath);\n await client.signIn.social({\n provider,\n callbackURL: returnUrl || '/',\n errorCallbackURL: `${getBasePath()}/login`,\n });\n } catch (err) {\n console.error('Social login error:', err);\n setSocialError(t('auth.socialLoginFailed'));\n setSocialLoading(null);\n }\n };\n\n const handleCloseWarning = () => {\n setShowDefaultPasswordWarning(false);\n redirectAfterLogin();\n };\n\n return (\n <div\n className=\"relative min-h-screen w-full overflow-hidden\"\n style={{ background: 'var(--hub-bg)', color: 'var(--hub-ink)' }}\n >\n {/* Top-right controls */}\n <div className=\"absolute top-3 right-4 z-20 flex items-center gap-1\">\n <a\n href=\"https://github.com/samanhappy/mcphub\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"hub-icon-btn\"\n aria-label=\"GitHub Repository\"\n >\n <GitHubIcon className=\"h-4 w-4\" />\n </a>\n <a\n href=\"https://docs.mcphub.app\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"hub-icon-btn\"\n aria-label=\"Documentation\"\n >\n <BookOpen className=\"h-4 w-4\" />\n </a>\n <ThemeSwitch />\n <LanguageSwitch />\n </div>\n\n {/* Subtle grid pattern (kept low-key, hair-line) */}\n <div className=\"pointer-events-none absolute inset-0 -z-10\">\n <svg\n className=\"h-full w-full\"\n style={{ opacity: 0.5 }}\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <defs>\n <pattern id=\"grid\" width=\"32\" height=\"32\" patternUnits=\"userSpaceOnUse\">\n <path\n d=\"M 32 0 L 0 0 0 32\"\n fill=\"none\"\n stroke=\"var(--hub-line-2)\"\n strokeWidth=\"0.5\"\n />\n </pattern>\n </defs>\n <rect width=\"100%\" height=\"100%\" fill=\"url(#grid)\" />\n </svg>\n </div>\n\n <div className=\"relative mx-auto flex min-h-screen w-full max-w-md items-center justify-center px-6\">\n <div className=\"w-full space-y-8\">\n {/* Brand */}\n <div className=\"flex flex-col items-center gap-3\">\n <div\n className=\"relative grid place-items-center\"\n style={{\n width: 44,\n height: 44,\n borderRadius: 10,\n background: 'var(--hub-ink)',\n color: 'white',\n }}\n >\n <span className=\"hub-mono font-semibold\" style={{ fontSize: 18 }}>\n M\n </span>\n <span\n className=\"absolute\"\n style={{\n right: -2,\n bottom: -2,\n width: 8,\n height: 8,\n borderRadius: 50,\n background: 'var(--hub-ok)',\n boxShadow: '0 0 0 3px var(--hub-bg)',\n }}\n />\n </div>\n <div className=\"text-center\">\n <h1\n style={{\n fontSize: 20,\n fontWeight: 600,\n letterSpacing: '-0.02em',\n color: 'var(--hub-ink)',\n }}\n >\n {t('app.title')}\n </h1>\n <p className=\"hub-sub\" style={{ marginTop: 4 }}>\n {t('auth.slogan')}\n </p>\n </div>\n </div>\n\n {/* Login card */}\n <div\n className=\"hub-card\"\n style={{\n padding: '22px 22px 20px',\n boxShadow: '0 1px 2px rgba(0,0,0,0.02)',\n }}\n >\n <form className=\"space-y-3\" onSubmit={handleSubmit}>\n <div>\n <label\n htmlFor=\"username\"\n className=\"hub-sect block\"\n style={{ marginBottom: 6 }}\n >\n {t('auth.username')}\n </label>\n <input\n id=\"username\"\n name=\"username\"\n type=\"text\"\n autoComplete=\"username\"\n required\n className=\"hub-input\"\n placeholder={t('auth.username')}\n value={username}\n onChange={(e) => setUsername(e.target.value)}\n />\n </div>\n <div>\n <label\n htmlFor=\"password\"\n className=\"hub-sect block\"\n style={{ marginBottom: 6 }}\n >\n {t('auth.password')}\n </label>\n <input\n id=\"password\"\n name=\"password\"\n type=\"password\"\n autoComplete=\"current-password\"\n required\n className=\"hub-input\"\n placeholder={t('auth.password')}\n value={password}\n onChange={(e) => setPassword(e.target.value)}\n />\n </div>\n\n {error && (\n <div\n className=\"flex items-center gap-2\"\n style={{\n padding: '8px 10px',\n borderRadius: 7,\n border: '1px solid oklch(0.85 0.1 25)',\n background: 'oklch(0.97 0.03 25)',\n color: 'oklch(0.4 0.18 25)',\n fontSize: 12.5,\n }}\n >\n <AlertCircle size={13} className=\"flex-shrink-0\" />\n <span>{error}</span>\n </div>\n )}\n\n <button\n type=\"submit\"\n disabled={loading}\n className=\"hub-btn primary w-full justify-center\"\n style={{ height: 34 }}\n >\n {loading ? t('auth.loggingIn') : t('auth.login')}\n </button>\n </form>\n\n {(socialProviders.google || socialProviders.github || socialProviders.oidc) && (\n <div className=\"mt-5 space-y-3\">\n <div className=\"flex items-center gap-3\">\n <div className=\"h-px flex-1\" style={{ background: 'var(--hub-line)' }} />\n <span\n className=\"hub-sect\"\n style={{ textTransform: 'uppercase', letterSpacing: '0.08em' }}\n >\n {t('auth.orContinue')}\n </span>\n <div className=\"h-px flex-1\" style={{ background: 'var(--hub-line)' }} />\n </div>\n\n {socialError && (\n <div\n className=\"flex items-center gap-2\"\n style={{\n padding: '8px 10px',\n borderRadius: 7,\n border: '1px solid oklch(0.85 0.1 25)',\n background: 'oklch(0.97 0.03 25)',\n color: 'oklch(0.4 0.18 25)',\n fontSize: 12.5,\n }}\n >\n <AlertCircle size={13} className=\"flex-shrink-0\" />\n <span>{socialError}</span>\n </div>\n )}\n\n <div className=\"space-y-2\">\n {socialProviders.google && (\n <button\n type=\"button\"\n onClick={() => handleSocialLogin('google')}\n disabled={socialLoading !== null}\n className=\"hub-btn w-full justify-center\"\n style={{ height: 34 }}\n >\n {socialLoading === 'google'\n ? t('auth.loggingIn')\n : t('auth.loginWithGoogle')}\n </button>\n )}\n {socialProviders.github && (\n <button\n type=\"button\"\n onClick={() => handleSocialLogin('github')}\n disabled={socialLoading !== null}\n className=\"hub-btn w-full justify-center\"\n style={{\n height: 34,\n background: 'var(--hub-ink)',\n color: 'var(--hub-bg)',\n borderColor: 'var(--hub-ink)',\n }}\n >\n <GitHubIcon className=\"h-3.5 w-3.5\" />\n {socialLoading === 'github'\n ? t('auth.loggingIn')\n : t('auth.loginWithGithub')}\n </button>\n )}\n {socialProviders.oidc && (\n <button\n type=\"button\"\n onClick={() => handleSocialLogin('oidc')}\n disabled={socialLoading !== null}\n className=\"hub-btn w-full justify-center\"\n style={{ height: 34 }}\n >\n {socialLoading === 'oidc'\n ? t('auth.loggingIn')\n : t('auth.loginWithOIDC')}\n </button>\n )}\n </div>\n </div>\n )}\n </div>\n\n <p\n className=\"text-center hub-mono\"\n style={{ fontSize: 11, color: 'var(--hub-ink-3)' }}\n >\n v{import.meta.env.PACKAGE_VERSION}\n </p>\n </div>\n </div>\n\n <DefaultPasswordWarningModal\n isOpen={showDefaultPasswordWarning}\n onClose={handleCloseWarning}\n />\n </div>\n );\n};\n\nexport default LoginPage;\n"],"names":["DefaultPasswordWarningModal","isOpen","onClose","t","useTranslation","navigate","useNavigate","handleGoToSettings","passwordSection","clickTarget","handleBackdropClick","e","handleKeyDown","jsx","jsxs","sanitizeReturnUrl","value","origin","url","LoginPage","username","setUsername","useState","password","setPassword","error","setError","loading","setLoading","socialLoading","setSocialLoading","socialError","setSocialError","betterAuthBasePath","setBetterAuthBasePath","socialProviders","setSocialProviders","oidcProviderId","setOidcProviderId","showDefaultPasswordWarning","setShowDefaultPasswordWarning","login","auth","useAuth","location","useLocation","returnUrl","useMemo","params","isServerUnavailableError","useCallback","message","normalized","buildRedirectTarget","token","getToken","separator","redirectAfterLogin","useEffect","betterAuth","getPublicConfig","_b","_a","_d","_c","_f","_e","_h","_g","handleSubmit","result","err","handleSocialLogin","provider","startOidcLogin","getBasePath","createBetterAuthClient","handleCloseWarning","GitHubIcon","BookOpen","ThemeSwitch","LanguageSwitch","AlertCircle"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{r as o,j as r}from"./framework-vendor-BUhDPOUZ.js";import{m as w,q as E}from"./index-
|
|
2
|
-
//# sourceMappingURL=LogsPage-
|
|
1
|
+
import{r as o,j as r}from"./framework-vendor-BUhDPOUZ.js";import{m as w,q as E}from"./index-C7wNc_3N.js";import{u as k}from"./i18n-vendor-Kbr87Ofu.js";import"./icons-vendor-CKgJB3SC.js";function C(s,n){if(typeof s=="function")return s(n);s!=null&&(s.current=n)}function R(...s){return n=>{let l=!1;const a=s.map(e=>{const i=C(e,n);return!l&&typeof i=="function"&&(l=!0),i});if(l)return()=>{for(let e=0;e<a.length;e++){const i=a[e];typeof i=="function"?i():C(s[e],null)}}}}function T(s){const n=V(s),l=o.forwardRef((a,e)=>{const{children:i,...c}=a,d=o.Children.toArray(i),u=d.find(I);if(u){const m=u.props.children,g=d.map(p=>p===u?o.Children.count(m)>1?o.Children.only(null):o.isValidElement(m)?m.props.children:null:p);return r.jsx(n,{...c,ref:e,children:o.isValidElement(m)?o.cloneElement(m,void 0,g):null})}return r.jsx(n,{...c,ref:e,children:i})});return l.displayName=`${s}.Slot`,l}var $=T("Slot");function V(s){const n=o.forwardRef((l,a)=>{const{children:e,...i}=l;if(o.isValidElement(e)){const c=A(e),d=P(i,e.props);return e.type!==o.Fragment&&(d.ref=a?R(a,c):c),o.cloneElement(e,d)}return o.Children.count(e)>1?o.Children.only(null):null});return n.displayName=`${s}.SlotClone`,n}var F=Symbol("radix.slottable");function I(s){return o.isValidElement(s)&&typeof s.type=="function"&&"__radixId"in s.type&&s.type.__radixId===F}function P(s,n){const l={...n};for(const a in n){const e=s[a],i=n[a];/^on[A-Z]/.test(a)?e&&i?l[a]=(...d)=>{const u=i(...d);return e(...d),u}:e&&(l[a]=e):a==="style"?l[a]={...e,...i}:a==="className"&&(l[a]=[e,i].filter(Boolean).join(" "))}return{...s,...l}}function A(s){var a,e;let n=(a=Object.getOwnPropertyDescriptor(s.props,"ref"))==null?void 0:a.get,l=n&&"isReactWarning"in n&&n.isReactWarning;return l?s.ref:(n=(e=Object.getOwnPropertyDescriptor(s,"ref"))==null?void 0:e.get,l=n&&"isReactWarning"in n&&n.isReactWarning,l?s.props.ref:s.props.ref||s.ref)}const W={default:"bg-blue-500 text-white hover:bg-blue-600 focus:ring-blue-500",outline:"border border-gray-300 dark:border-gray-700 bg-transparent hover:bg-gray-100 dark:hover:bg-gray-800 text-gray-700 dark:text-gray-300",ghost:"bg-transparent hover:bg-gray-100 dark:hover:bg-gray-800 text-gray-700 dark:text-gray-300",link:"bg-transparent underline-offset-4 hover:underline text-blue-500 hover:text-blue-600",destructive:"bg-red-500 text-white hover:bg-red-600 focus:ring-red-500"},B={default:"h-10 py-2 px-4",sm:"h-8 px-3 text-sm",lg:"h-12 px-6",icon:"h-10 w-10 p-0 text-center"};function H({variant:s="default",size:n="default",className:l,disabled:a,loading:e=!1,asChild:i=!1,children:c,onClick:d,...u}){const[m,g]=o.useState(!1),p=e||m,h=async v=>{if(d)try{const x=d(v);x&&typeof x.then=="function"&&(g(!0),await x)}finally{g(!1)}},y=i?$:"button";return r.jsx(y,{className:w("rounded-md inline-flex items-center justify-center font-medium transition-all duration-200 active:scale-95 focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none relative",W[s],B[n],l),disabled:a||p,onClick:h,...u,children:i?c:r.jsxs(r.Fragment,{children:[r.jsx("span",{className:w("flex items-center justify-center",p&&"invisible"),children:c}),p&&r.jsx("span",{className:"absolute inset-0 flex items-center justify-center",children:r.jsxs("svg",{className:"animate-spin h-5 w-5",xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24",children:[r.jsx("circle",{className:"opacity-25",cx:"12",cy:"12",r:"10",stroke:"currentColor",strokeWidth:"4"}),r.jsx("path",{className:"opacity-75",fill:"currentColor",d:"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"})]})})]})})}const O={default:"bg-blue-500 text-white hover:bg-blue-600",secondary:"bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-600",outline:"bg-transparent border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800",destructive:"bg-red-500 text-white hover:bg-red-600"};function j({children:s,variant:n="default",className:l,onClick:a}){return r.jsx("span",{className:w("inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-semibold transition-colors",O[n],a?"cursor-pointer":"",l),onClick:a,children:s})}const _=({logs:s,isLoading:n=!1,error:l=null,onClear:a})=>{const{t:e}=k(),i=o.useRef(null),[c,d]=o.useState(!0),[u,m]=o.useState(""),[g,p]=o.useState(["info","error","warn","debug"]),[h,y]=o.useState(["main","child"]);o.useEffect(()=>{c&&i.current&&(i.current.scrollTop=i.current.scrollHeight)},[s,c]);const v=s.filter(t=>{const f=u?t.message.toLowerCase().includes(u.toLowerCase()):!0,b=g.includes(t.type),L=h.includes(t.source);return f&&b&&L}),x=t=>new Date(t).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:!1}),N=t=>{switch(t){case"error":return"bg-red-400/80 text-white";case"warn":return"bg-yellow-400/80 text-gray-900";case"debug":return"bg-purple-400/80 text-white";case"info":return"bg-blue-400/80 text-white";default:return"bg-blue-400/80 text-white"}},S=t=>{switch(t){case"main":return"bg-green-400/80 text-white";case"child":return"bg-orange-400/80 text-white";default:return"bg-gray-400/80 text-white"}};return r.jsxs("div",{className:"flex flex-col h-full",children:[r.jsxs("div",{className:"bg-card p-3 rounded-t-md flex flex-wrap items-center justify-between gap-2",children:[r.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[r.jsxs("span",{className:"font-semibold text-sm",children:[e("logs.filters"),":"]}),r.jsx("input",{type:"text",placeholder:e("logs.search"),className:"shadow appearance-none border border-gray-200 dark:border-gray-700 rounded py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline form-input",value:u,onChange:t=>m(t.target.value)}),r.jsx("div",{className:"flex gap-1 items-center",children:["debug","info","error","warn"].map(t=>r.jsx(j,{variant:g.includes(t)?"default":"outline",className:`cursor-pointer ${g.includes(t)?N(t):""}`,onClick:()=>{g.includes(t)?p(f=>f.filter(b=>b!==t)):p(f=>[...f,t])},children:t},t))}),r.jsx("div",{className:"flex gap-1 items-center ml-2",children:["main","child"].map(t=>r.jsx(j,{variant:h.includes(t)?"default":"outline",className:`cursor-pointer ${h.includes(t)?S(t):""}`,onClick:()=>{h.includes(t)?y(f=>f.filter(b=>b!==t)):y(f=>[...f,t])},children:e(t==="main"?"logs.mainProcess":"logs.childProcess")},t))})]}),r.jsxs("div",{className:"flex items-center gap-2",children:[r.jsxs("label",{className:"flex items-center gap-1 text-sm",children:[r.jsx("input",{type:"checkbox",checked:c,onChange:()=>d(!c),className:"form-checkbox h-4 w-4"}),e("logs.autoScroll")]}),r.jsx(H,{variant:"outline",size:"sm",onClick:a,className:"btn-secondary",disabled:n||s.length===0,children:e("logs.clearLogs")})]})]}),r.jsx("div",{ref:i,className:"flex-grow p-2 overflow-auto bg-card rounded-b-md font-mono text-sm",style:{maxHeight:"calc(100vh - 300px)"},children:n?r.jsx("div",{className:"flex justify-center items-center h-full",children:r.jsx("span",{children:e("logs.loading")})}):l?r.jsx("div",{className:"text-red-500 p-2",children:l.message}):v.length===0?r.jsx("div",{className:"text-center text-muted-foreground p-8",children:u||g.length<4||h.length<2?e("logs.noMatch"):e("logs.noLogs")}):v.map((t,f)=>r.jsxs("div",{className:`py-1 ${t.type==="error"?"text-red-500":t.type==="warn"?"text-yellow-500":""}`,children:[r.jsxs("span",{className:"text-gray-400",children:["[",x(t.timestamp),"]"]}),r.jsx(j,{className:`ml-2 mr-1 ${N(t.type)}`,children:t.type}),r.jsxs(j,{variant:"default",className:`mr-2 ${S(t.source)}`,children:[t.source==="main"?e("logs.main"):e("logs.child"),t.processId?` (${t.processId})`:""]}),r.jsx("span",{className:"whitespace-pre-wrap",children:t.message})]},`${t.timestamp}-${f}`))})]})},Z=()=>{const{t:s}=k(),{logs:n,loading:l,error:a,clearLogs:e}=E();return r.jsxs("div",{children:[r.jsxs("div",{className:"mb-6",children:[r.jsx("h1",{className:"hub-h1",children:s("pages.logs.title")}),r.jsxs("p",{className:"hub-sub",children:[r.jsx("span",{className:"hub-num",children:n.length})," entries"]})]}),r.jsx("div",{className:"hub-card overflow-hidden",children:r.jsx(_,{logs:n,isLoading:l,error:a,onClear:e})})]})};export{Z as default};
|
|
2
|
+
//# sourceMappingURL=LogsPage-DOZeagVs.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LogsPage-CTa8kuDf.js","sources":["../../../node_modules/.pnpm/@radix-ui+react-compose-refs@1.1.2_@types+react@19.2.7_react@19.2.1/node_modules/@radix-ui/react-compose-refs/dist/index.mjs","../../../node_modules/.pnpm/@radix-ui+react-slot@1.2.3_@types+react@19.2.7_react@19.2.1/node_modules/@radix-ui/react-slot/dist/index.mjs","../../src/components/ui/Button.tsx","../../src/components/ui/Badge.tsx","../../src/components/LogViewer.tsx","../../src/pages/LogsPage.tsx"],"sourcesContent":["// packages/react/compose-refs/src/compose-refs.tsx\nimport * as React from \"react\";\nfunction setRef(ref, value) {\n if (typeof ref === \"function\") {\n return ref(value);\n } else if (ref !== null && ref !== void 0) {\n ref.current = value;\n }\n}\nfunction composeRefs(...refs) {\n return (node) => {\n let hasCleanup = false;\n const cleanups = refs.map((ref) => {\n const cleanup = setRef(ref, node);\n if (!hasCleanup && typeof cleanup == \"function\") {\n hasCleanup = true;\n }\n return cleanup;\n });\n if (hasCleanup) {\n return () => {\n for (let i = 0; i < cleanups.length; i++) {\n const cleanup = cleanups[i];\n if (typeof cleanup == \"function\") {\n cleanup();\n } else {\n setRef(refs[i], null);\n }\n }\n };\n }\n };\n}\nfunction useComposedRefs(...refs) {\n return React.useCallback(composeRefs(...refs), refs);\n}\nexport {\n composeRefs,\n useComposedRefs\n};\n//# sourceMappingURL=index.mjs.map\n","// src/slot.tsx\nimport * as React from \"react\";\nimport { composeRefs } from \"@radix-ui/react-compose-refs\";\nimport { Fragment as Fragment2, jsx } from \"react/jsx-runtime\";\n// @__NO_SIDE_EFFECTS__\nfunction createSlot(ownerName) {\n const SlotClone = /* @__PURE__ */ createSlotClone(ownerName);\n const Slot2 = React.forwardRef((props, forwardedRef) => {\n const { children, ...slotProps } = props;\n const childrenArray = React.Children.toArray(children);\n const slottable = childrenArray.find(isSlottable);\n if (slottable) {\n const newElement = slottable.props.children;\n const newChildren = childrenArray.map((child) => {\n if (child === slottable) {\n if (React.Children.count(newElement) > 1) return React.Children.only(null);\n return React.isValidElement(newElement) ? newElement.props.children : null;\n } else {\n return child;\n }\n });\n return /* @__PURE__ */ jsx(SlotClone, { ...slotProps, ref: forwardedRef, children: React.isValidElement(newElement) ? React.cloneElement(newElement, void 0, newChildren) : null });\n }\n return /* @__PURE__ */ jsx(SlotClone, { ...slotProps, ref: forwardedRef, children });\n });\n Slot2.displayName = `${ownerName}.Slot`;\n return Slot2;\n}\nvar Slot = /* @__PURE__ */ createSlot(\"Slot\");\n// @__NO_SIDE_EFFECTS__\nfunction createSlotClone(ownerName) {\n const SlotClone = React.forwardRef((props, forwardedRef) => {\n const { children, ...slotProps } = props;\n if (React.isValidElement(children)) {\n const childrenRef = getElementRef(children);\n const props2 = mergeProps(slotProps, children.props);\n if (children.type !== React.Fragment) {\n props2.ref = forwardedRef ? composeRefs(forwardedRef, childrenRef) : childrenRef;\n }\n return React.cloneElement(children, props2);\n }\n return React.Children.count(children) > 1 ? React.Children.only(null) : null;\n });\n SlotClone.displayName = `${ownerName}.SlotClone`;\n return SlotClone;\n}\nvar SLOTTABLE_IDENTIFIER = Symbol(\"radix.slottable\");\n// @__NO_SIDE_EFFECTS__\nfunction createSlottable(ownerName) {\n const Slottable2 = ({ children }) => {\n return /* @__PURE__ */ jsx(Fragment2, { children });\n };\n Slottable2.displayName = `${ownerName}.Slottable`;\n Slottable2.__radixId = SLOTTABLE_IDENTIFIER;\n return Slottable2;\n}\nvar Slottable = /* @__PURE__ */ createSlottable(\"Slottable\");\nfunction isSlottable(child) {\n return React.isValidElement(child) && typeof child.type === \"function\" && \"__radixId\" in child.type && child.type.__radixId === SLOTTABLE_IDENTIFIER;\n}\nfunction mergeProps(slotProps, childProps) {\n const overrideProps = { ...childProps };\n for (const propName in childProps) {\n const slotPropValue = slotProps[propName];\n const childPropValue = childProps[propName];\n const isHandler = /^on[A-Z]/.test(propName);\n if (isHandler) {\n if (slotPropValue && childPropValue) {\n overrideProps[propName] = (...args) => {\n const result = childPropValue(...args);\n slotPropValue(...args);\n return result;\n };\n } else if (slotPropValue) {\n overrideProps[propName] = slotPropValue;\n }\n } else if (propName === \"style\") {\n overrideProps[propName] = { ...slotPropValue, ...childPropValue };\n } else if (propName === \"className\") {\n overrideProps[propName] = [slotPropValue, childPropValue].filter(Boolean).join(\" \");\n }\n }\n return { ...slotProps, ...overrideProps };\n}\nfunction getElementRef(element) {\n let getter = Object.getOwnPropertyDescriptor(element.props, \"ref\")?.get;\n let mayWarn = getter && \"isReactWarning\" in getter && getter.isReactWarning;\n if (mayWarn) {\n return element.ref;\n }\n getter = Object.getOwnPropertyDescriptor(element, \"ref\")?.get;\n mayWarn = getter && \"isReactWarning\" in getter && getter.isReactWarning;\n if (mayWarn) {\n return element.props.ref;\n }\n return element.props.ref || element.ref;\n}\nexport {\n Slot as Root,\n Slot,\n Slottable,\n createSlot,\n createSlottable\n};\n//# sourceMappingURL=index.mjs.map\n","import React, { useState } from 'react';\nimport { Slot } from '@radix-ui/react-slot';\nimport { cn } from '../../utils/cn';\n\ntype ButtonVariant = 'default' | 'outline' | 'ghost' | 'link' | 'destructive';\ntype ButtonSize = 'default' | 'sm' | 'lg' | 'icon';\n\ninterface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n variant?: ButtonVariant;\n size?: ButtonSize;\n asChild?: boolean;\n loading?: boolean;\n children: React.ReactNode;\n}\n\nconst variantStyles: Record<ButtonVariant, string> = {\n default: 'bg-blue-500 text-white hover:bg-blue-600 focus:ring-blue-500',\n outline: 'border border-gray-300 dark:border-gray-700 bg-transparent hover:bg-gray-100 dark:hover:bg-gray-800 text-gray-700 dark:text-gray-300',\n ghost: 'bg-transparent hover:bg-gray-100 dark:hover:bg-gray-800 text-gray-700 dark:text-gray-300',\n link: 'bg-transparent underline-offset-4 hover:underline text-blue-500 hover:text-blue-600',\n destructive: 'bg-red-500 text-white hover:bg-red-600 focus:ring-red-500',\n};\n\nconst sizeStyles: Record<ButtonSize, string> = {\n default: 'h-10 py-2 px-4',\n sm: 'h-8 px-3 text-sm',\n lg: 'h-12 px-6',\n icon: 'h-10 w-10 p-0 text-center',\n};\n\nexport function Button({\n variant = 'default',\n size = 'default',\n className,\n disabled,\n loading: externalLoading = false,\n asChild = false,\n children,\n onClick,\n ...props\n}: ButtonProps) {\n const [internalLoading, setInternalLoading] = useState(false);\n const isLoading = externalLoading || internalLoading;\n\n const handleClick = async (e: React.MouseEvent<HTMLButtonElement>) => {\n if (!onClick) return;\n \n try {\n const result = onClick(e);\n if (result && typeof (result as any).then === 'function') {\n setInternalLoading(true);\n await result;\n }\n } finally {\n if (internalLoading) {\n // Need to check if component unmounted?\n // It's a standard pattern, state update on unmounted is no longer an error in React 18+\n }\n setInternalLoading(false);\n }\n };\n\n const Comp = asChild ? Slot : 'button';\n\n return (\n <Comp\n className={cn(\n 'rounded-md inline-flex items-center justify-center font-medium transition-all duration-200 active:scale-95 focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none relative',\n variantStyles[variant],\n sizeStyles[size],\n className\n )}\n disabled={disabled || isLoading}\n onClick={handleClick}\n {...props}\n >\n {asChild ? (\n children\n ) : (\n <>\n <span className={cn('flex items-center justify-center', isLoading && 'invisible')}>\n {children}\n </span>\n {isLoading && (\n <span className=\"absolute inset-0 flex items-center justify-center\">\n <svg className=\"animate-spin h-5 w-5\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\">\n <circle className=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" strokeWidth=\"4\"></circle>\n <path className=\"opacity-75\" fill=\"currentColor\" d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"></path>\n </svg>\n </span>\n )}\n </>\n )}\n </Comp>\n );\n}","import React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { cn } from '../../utils/cn';\n\ntype BadgeVariant = 'default' | 'secondary' | 'outline' | 'destructive';\n\ntype BadgeProps = {\n children: React.ReactNode;\n variant?: BadgeVariant;\n className?: string;\n onClick?: () => void;\n};\n\nconst badgeVariants = {\n default: 'bg-blue-500 text-white hover:bg-blue-600',\n secondary:\n 'bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-600',\n outline:\n 'bg-transparent border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800',\n destructive: 'bg-red-500 text-white hover:bg-red-600',\n};\n\nexport function Badge({ children, variant = 'default', className, onClick }: BadgeProps) {\n return (\n <span\n className={cn(\n 'inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-semibold transition-colors',\n badgeVariants[variant],\n onClick ? 'cursor-pointer' : '',\n className,\n )}\n onClick={onClick}\n >\n {children}\n </span>\n );\n}\n\n// For backward compatibility with existing code\nexport const StatusBadge = ({\n status,\n onAuthClick,\n}: {\n status: 'connected' | 'disconnected' | 'connecting' | 'oauth_required';\n onAuthClick?: (e: React.MouseEvent) => void;\n}) => {\n const { t } = useTranslation();\n\n const colors = {\n connecting: 'status-badge-connecting',\n connected: 'status-badge-online',\n disconnected: 'status-badge-offline',\n oauth_required: 'status-badge-oauth-required',\n };\n\n // Map status to translation keys\n const statusTranslations = {\n connected: 'status.online',\n disconnected: 'status.offline',\n connecting: 'status.connecting',\n oauth_required: 'status.oauthRequired',\n };\n\n const isOAuthRequired = status === 'oauth_required';\n\n return (\n <span\n className={`px-2 inline-flex text-xs leading-5 font-semibold rounded-full ${colors[status]} ${isOAuthRequired && onAuthClick ? 'cursor-pointer hover:opacity-80' : ''}`}\n onClick={isOAuthRequired && onAuthClick ? (e) => onAuthClick(e) : undefined}\n title={isOAuthRequired ? t('status.clickToAuthorize') : undefined}\n >\n {isOAuthRequired && '🔐 '}\n {t(statusTranslations[status] || status)}\n </span>\n );\n};\n","import React, { useEffect, useRef, useState } from 'react';\nimport { LogEntry } from '../services/logService';\nimport { Button } from './ui/Button';\nimport { Badge } from './ui/Badge';\nimport { useTranslation } from 'react-i18next';\n\ninterface LogViewerProps {\n logs: LogEntry[];\n isLoading?: boolean;\n error?: Error | null;\n onClear?: () => void;\n}\n\nconst LogViewer: React.FC<LogViewerProps> = ({ logs, isLoading = false, error = null, onClear }) => {\n const { t } = useTranslation();\n const logContainerRef = useRef<HTMLDivElement>(null);\n const [autoScroll, setAutoScroll] = useState(true);\n const [filter, setFilter] = useState<string>('');\n const [typeFilter, setTypeFilter] = useState<Array<'info' | 'error' | 'warn' | 'debug'>>(['info', 'error', 'warn', 'debug']);\n const [sourceFilter, setSourceFilter] = useState<Array<'main' | 'child'>>(['main', 'child']);\n\n // Auto scroll to bottom when new logs come in if autoScroll is enabled\n useEffect(() => {\n if (autoScroll && logContainerRef.current) {\n logContainerRef.current.scrollTop = logContainerRef.current.scrollHeight;\n }\n }, [logs, autoScroll]);\n\n // Filter logs based on current filter settings\n const filteredLogs = logs.filter(log => {\n const matchesText = filter ? log.message.toLowerCase().includes(filter.toLowerCase()) : true;\n const matchesType = typeFilter.includes(log.type);\n const matchesSource = sourceFilter.includes(log.source as 'main' | 'child');\n return matchesText && matchesType && matchesSource;\n });\n\n // Format timestamp to readable format\n const formatTimestamp = (timestamp: number) => {\n const date = new Date(timestamp);\n return date.toLocaleTimeString([], {\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n hour12: false\n });\n };\n\n // Get badge color based on log type\n const getLogTypeColor = (type: string) => {\n switch (type) {\n case 'error': return 'bg-red-400/80 text-white';\n case 'warn': return 'bg-yellow-400/80 text-gray-900';\n case 'debug': return 'bg-purple-400/80 text-white';\n case 'info': return 'bg-blue-400/80 text-white';\n default: return 'bg-blue-400/80 text-white';\n }\n };\n\n // Get badge color based on log source\n const getSourceColor = (source: string) => {\n switch (source) {\n case 'main': return 'bg-green-400/80 text-white';\n case 'child': return 'bg-orange-400/80 text-white';\n default: return 'bg-gray-400/80 text-white';\n }\n };\n\n return (\n <div className=\"flex flex-col h-full\">\n <div className=\"bg-card p-3 rounded-t-md flex flex-wrap items-center justify-between gap-2\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"font-semibold text-sm\">{t('logs.filters')}:</span>\n\n {/* Text search filter */}\n <input\n type=\"text\"\n placeholder={t('logs.search')}\n className=\"shadow appearance-none border border-gray-200 dark:border-gray-700 rounded py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline form-input\"\n value={filter}\n onChange={(e) => setFilter(e.target.value)}\n />\n\n {/* Log type filters */}\n <div className=\"flex gap-1 items-center\">\n {(['debug', 'info', 'error', 'warn'] as const).map(type => (\n <Badge\n key={type}\n variant={typeFilter.includes(type) ? 'default' : 'outline'}\n className={`cursor-pointer ${typeFilter.includes(type) ? getLogTypeColor(type) : ''}`}\n onClick={() => {\n if (typeFilter.includes(type)) {\n setTypeFilter(prev => prev.filter(t => t !== type));\n } else {\n setTypeFilter(prev => [...prev, type]);\n }\n }}\n >\n {type}\n </Badge>\n ))}\n </div>\n\n {/* Log source filters */}\n <div className=\"flex gap-1 items-center ml-2\">\n {(['main', 'child'] as const).map(source => (\n <Badge\n key={source}\n variant={sourceFilter.includes(source) ? 'default' : 'outline'}\n className={`cursor-pointer ${sourceFilter.includes(source) ? getSourceColor(source) : ''}`}\n onClick={() => {\n if (sourceFilter.includes(source)) {\n setSourceFilter(prev => prev.filter(s => s !== source));\n } else {\n setSourceFilter(prev => [...prev, source]);\n }\n }}\n >\n {source === 'main' ? t('logs.mainProcess') : t('logs.childProcess')}\n </Badge>\n ))}\n </div>\n </div>\n\n <div className=\"flex items-center gap-2\">\n <label className=\"flex items-center gap-1 text-sm\">\n <input\n type=\"checkbox\"\n checked={autoScroll}\n onChange={() => setAutoScroll(!autoScroll)}\n className=\"form-checkbox h-4 w-4\"\n />\n {t('logs.autoScroll')}\n </label>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={onClear}\n className='btn-secondary'\n disabled={isLoading || logs.length === 0}\n >\n {t('logs.clearLogs')}\n </Button>\n </div>\n </div>\n\n <div\n ref={logContainerRef}\n className=\"flex-grow p-2 overflow-auto bg-card rounded-b-md font-mono text-sm\"\n style={{ maxHeight: 'calc(100vh - 300px)' }}\n >\n {isLoading ? (\n <div className=\"flex justify-center items-center h-full\">\n <span>{t('logs.loading')}</span>\n </div>\n ) : error ? (\n <div className=\"text-red-500 p-2\">\n {error.message}\n </div>\n ) : filteredLogs.length === 0 ? (\n <div className=\"text-center text-muted-foreground p-8\">\n {filter || typeFilter.length < 4 || sourceFilter.length < 2\n ? t('logs.noMatch')\n : t('logs.noLogs')}\n </div>\n ) : (\n filteredLogs.map((log, index) => (\n <div\n key={`${log.timestamp}-${index}`}\n className={`py-1 ${log.type === 'error' ? 'text-red-500' :\n log.type === 'warn' ? 'text-yellow-500' : ''\n }`}\n >\n <span className=\"text-gray-400\">[{formatTimestamp(log.timestamp)}]</span>\n <Badge className={`ml-2 mr-1 ${getLogTypeColor(log.type)}`}>\n {log.type}\n </Badge>\n <Badge\n variant=\"default\"\n className={`mr-2 ${getSourceColor(log.source)}`}\n >\n {log.source === 'main' ? t('logs.main') : t('logs.child')}\n {log.processId ? ` (${log.processId})` : ''}\n </Badge>\n <span className=\"whitespace-pre-wrap\">{log.message}</span>\n </div>\n ))\n )}\n </div>\n </div>\n );\n};\n\nexport default LogViewer;","import React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport LogViewer from '../components/LogViewer';\nimport { useLogs } from '../services/logService';\n\nconst LogsPage: React.FC = () => {\n const { t } = useTranslation();\n const { logs, loading, error, clearLogs } = useLogs();\n\n return (\n <div>\n <div className=\"mb-6\">\n <h1 className=\"hub-h1\">{t('pages.logs.title')}</h1>\n <p className=\"hub-sub\">\n <span className=\"hub-num\">{logs.length}</span> entries\n </p>\n </div>\n <div className=\"hub-card overflow-hidden\">\n <LogViewer logs={logs} isLoading={loading} error={error} onClear={clearLogs} />\n </div>\n </div>\n );\n};\n\nexport default LogsPage;\n"],"names":["setRef","ref","value","composeRefs","refs","node","hasCleanup","cleanups","cleanup","i","createSlot","ownerName","SlotClone","createSlotClone","Slot2","React.forwardRef","props","forwardedRef","children","slotProps","childrenArray","React.Children","slottable","isSlottable","newElement","newChildren","child","React.isValidElement","jsx","React.cloneElement","Slot","childrenRef","getElementRef","props2","mergeProps","React.Fragment","SLOTTABLE_IDENTIFIER","childProps","overrideProps","propName","slotPropValue","childPropValue","args","result","element","getter","_a","mayWarn","_b","variantStyles","sizeStyles","Button","variant","size","className","disabled","externalLoading","asChild","onClick","internalLoading","setInternalLoading","useState","isLoading","handleClick","e","Comp","cn","jsxs","Fragment","badgeVariants","Badge","LogViewer","logs","error","onClear","t","useTranslation","logContainerRef","useRef","autoScroll","setAutoScroll","filter","setFilter","typeFilter","setTypeFilter","sourceFilter","setSourceFilter","useEffect","filteredLogs","log","matchesText","matchesType","matchesSource","formatTimestamp","timestamp","getLogTypeColor","type","getSourceColor","source","prev","s","index","LogsPage","loading","clearLogs","useLogs"],"mappings":"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","x_google_ignoreList":[0,1]}
|
|
1
|
+
{"version":3,"file":"LogsPage-DOZeagVs.js","sources":["../../../node_modules/.pnpm/@radix-ui+react-compose-refs@1.1.2_@types+react@19.2.7_react@19.2.1/node_modules/@radix-ui/react-compose-refs/dist/index.mjs","../../../node_modules/.pnpm/@radix-ui+react-slot@1.2.3_@types+react@19.2.7_react@19.2.1/node_modules/@radix-ui/react-slot/dist/index.mjs","../../src/components/ui/Button.tsx","../../src/components/ui/Badge.tsx","../../src/components/LogViewer.tsx","../../src/pages/LogsPage.tsx"],"sourcesContent":["// packages/react/compose-refs/src/compose-refs.tsx\nimport * as React from \"react\";\nfunction setRef(ref, value) {\n if (typeof ref === \"function\") {\n return ref(value);\n } else if (ref !== null && ref !== void 0) {\n ref.current = value;\n }\n}\nfunction composeRefs(...refs) {\n return (node) => {\n let hasCleanup = false;\n const cleanups = refs.map((ref) => {\n const cleanup = setRef(ref, node);\n if (!hasCleanup && typeof cleanup == \"function\") {\n hasCleanup = true;\n }\n return cleanup;\n });\n if (hasCleanup) {\n return () => {\n for (let i = 0; i < cleanups.length; i++) {\n const cleanup = cleanups[i];\n if (typeof cleanup == \"function\") {\n cleanup();\n } else {\n setRef(refs[i], null);\n }\n }\n };\n }\n };\n}\nfunction useComposedRefs(...refs) {\n return React.useCallback(composeRefs(...refs), refs);\n}\nexport {\n composeRefs,\n useComposedRefs\n};\n//# sourceMappingURL=index.mjs.map\n","// src/slot.tsx\nimport * as React from \"react\";\nimport { composeRefs } from \"@radix-ui/react-compose-refs\";\nimport { Fragment as Fragment2, jsx } from \"react/jsx-runtime\";\n// @__NO_SIDE_EFFECTS__\nfunction createSlot(ownerName) {\n const SlotClone = /* @__PURE__ */ createSlotClone(ownerName);\n const Slot2 = React.forwardRef((props, forwardedRef) => {\n const { children, ...slotProps } = props;\n const childrenArray = React.Children.toArray(children);\n const slottable = childrenArray.find(isSlottable);\n if (slottable) {\n const newElement = slottable.props.children;\n const newChildren = childrenArray.map((child) => {\n if (child === slottable) {\n if (React.Children.count(newElement) > 1) return React.Children.only(null);\n return React.isValidElement(newElement) ? newElement.props.children : null;\n } else {\n return child;\n }\n });\n return /* @__PURE__ */ jsx(SlotClone, { ...slotProps, ref: forwardedRef, children: React.isValidElement(newElement) ? React.cloneElement(newElement, void 0, newChildren) : null });\n }\n return /* @__PURE__ */ jsx(SlotClone, { ...slotProps, ref: forwardedRef, children });\n });\n Slot2.displayName = `${ownerName}.Slot`;\n return Slot2;\n}\nvar Slot = /* @__PURE__ */ createSlot(\"Slot\");\n// @__NO_SIDE_EFFECTS__\nfunction createSlotClone(ownerName) {\n const SlotClone = React.forwardRef((props, forwardedRef) => {\n const { children, ...slotProps } = props;\n if (React.isValidElement(children)) {\n const childrenRef = getElementRef(children);\n const props2 = mergeProps(slotProps, children.props);\n if (children.type !== React.Fragment) {\n props2.ref = forwardedRef ? composeRefs(forwardedRef, childrenRef) : childrenRef;\n }\n return React.cloneElement(children, props2);\n }\n return React.Children.count(children) > 1 ? React.Children.only(null) : null;\n });\n SlotClone.displayName = `${ownerName}.SlotClone`;\n return SlotClone;\n}\nvar SLOTTABLE_IDENTIFIER = Symbol(\"radix.slottable\");\n// @__NO_SIDE_EFFECTS__\nfunction createSlottable(ownerName) {\n const Slottable2 = ({ children }) => {\n return /* @__PURE__ */ jsx(Fragment2, { children });\n };\n Slottable2.displayName = `${ownerName}.Slottable`;\n Slottable2.__radixId = SLOTTABLE_IDENTIFIER;\n return Slottable2;\n}\nvar Slottable = /* @__PURE__ */ createSlottable(\"Slottable\");\nfunction isSlottable(child) {\n return React.isValidElement(child) && typeof child.type === \"function\" && \"__radixId\" in child.type && child.type.__radixId === SLOTTABLE_IDENTIFIER;\n}\nfunction mergeProps(slotProps, childProps) {\n const overrideProps = { ...childProps };\n for (const propName in childProps) {\n const slotPropValue = slotProps[propName];\n const childPropValue = childProps[propName];\n const isHandler = /^on[A-Z]/.test(propName);\n if (isHandler) {\n if (slotPropValue && childPropValue) {\n overrideProps[propName] = (...args) => {\n const result = childPropValue(...args);\n slotPropValue(...args);\n return result;\n };\n } else if (slotPropValue) {\n overrideProps[propName] = slotPropValue;\n }\n } else if (propName === \"style\") {\n overrideProps[propName] = { ...slotPropValue, ...childPropValue };\n } else if (propName === \"className\") {\n overrideProps[propName] = [slotPropValue, childPropValue].filter(Boolean).join(\" \");\n }\n }\n return { ...slotProps, ...overrideProps };\n}\nfunction getElementRef(element) {\n let getter = Object.getOwnPropertyDescriptor(element.props, \"ref\")?.get;\n let mayWarn = getter && \"isReactWarning\" in getter && getter.isReactWarning;\n if (mayWarn) {\n return element.ref;\n }\n getter = Object.getOwnPropertyDescriptor(element, \"ref\")?.get;\n mayWarn = getter && \"isReactWarning\" in getter && getter.isReactWarning;\n if (mayWarn) {\n return element.props.ref;\n }\n return element.props.ref || element.ref;\n}\nexport {\n Slot as Root,\n Slot,\n Slottable,\n createSlot,\n createSlottable\n};\n//# sourceMappingURL=index.mjs.map\n","import React, { useState } from 'react';\nimport { Slot } from '@radix-ui/react-slot';\nimport { cn } from '../../utils/cn';\n\ntype ButtonVariant = 'default' | 'outline' | 'ghost' | 'link' | 'destructive';\ntype ButtonSize = 'default' | 'sm' | 'lg' | 'icon';\n\ninterface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n variant?: ButtonVariant;\n size?: ButtonSize;\n asChild?: boolean;\n loading?: boolean;\n children: React.ReactNode;\n}\n\nconst variantStyles: Record<ButtonVariant, string> = {\n default: 'bg-blue-500 text-white hover:bg-blue-600 focus:ring-blue-500',\n outline: 'border border-gray-300 dark:border-gray-700 bg-transparent hover:bg-gray-100 dark:hover:bg-gray-800 text-gray-700 dark:text-gray-300',\n ghost: 'bg-transparent hover:bg-gray-100 dark:hover:bg-gray-800 text-gray-700 dark:text-gray-300',\n link: 'bg-transparent underline-offset-4 hover:underline text-blue-500 hover:text-blue-600',\n destructive: 'bg-red-500 text-white hover:bg-red-600 focus:ring-red-500',\n};\n\nconst sizeStyles: Record<ButtonSize, string> = {\n default: 'h-10 py-2 px-4',\n sm: 'h-8 px-3 text-sm',\n lg: 'h-12 px-6',\n icon: 'h-10 w-10 p-0 text-center',\n};\n\nexport function Button({\n variant = 'default',\n size = 'default',\n className,\n disabled,\n loading: externalLoading = false,\n asChild = false,\n children,\n onClick,\n ...props\n}: ButtonProps) {\n const [internalLoading, setInternalLoading] = useState(false);\n const isLoading = externalLoading || internalLoading;\n\n const handleClick = async (e: React.MouseEvent<HTMLButtonElement>) => {\n if (!onClick) return;\n \n try {\n const result = onClick(e);\n if (result && typeof (result as any).then === 'function') {\n setInternalLoading(true);\n await result;\n }\n } finally {\n if (internalLoading) {\n // Need to check if component unmounted?\n // It's a standard pattern, state update on unmounted is no longer an error in React 18+\n }\n setInternalLoading(false);\n }\n };\n\n const Comp = asChild ? Slot : 'button';\n\n return (\n <Comp\n className={cn(\n 'rounded-md inline-flex items-center justify-center font-medium transition-all duration-200 active:scale-95 focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none relative',\n variantStyles[variant],\n sizeStyles[size],\n className\n )}\n disabled={disabled || isLoading}\n onClick={handleClick}\n {...props}\n >\n {asChild ? (\n children\n ) : (\n <>\n <span className={cn('flex items-center justify-center', isLoading && 'invisible')}>\n {children}\n </span>\n {isLoading && (\n <span className=\"absolute inset-0 flex items-center justify-center\">\n <svg className=\"animate-spin h-5 w-5\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\">\n <circle className=\"opacity-25\" cx=\"12\" cy=\"12\" r=\"10\" stroke=\"currentColor\" strokeWidth=\"4\"></circle>\n <path className=\"opacity-75\" fill=\"currentColor\" d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"></path>\n </svg>\n </span>\n )}\n </>\n )}\n </Comp>\n );\n}","import React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { cn } from '../../utils/cn';\n\ntype BadgeVariant = 'default' | 'secondary' | 'outline' | 'destructive';\n\ntype BadgeProps = {\n children: React.ReactNode;\n variant?: BadgeVariant;\n className?: string;\n onClick?: () => void;\n};\n\nconst badgeVariants = {\n default: 'bg-blue-500 text-white hover:bg-blue-600',\n secondary:\n 'bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-600',\n outline:\n 'bg-transparent border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800',\n destructive: 'bg-red-500 text-white hover:bg-red-600',\n};\n\nexport function Badge({ children, variant = 'default', className, onClick }: BadgeProps) {\n return (\n <span\n className={cn(\n 'inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-semibold transition-colors',\n badgeVariants[variant],\n onClick ? 'cursor-pointer' : '',\n className,\n )}\n onClick={onClick}\n >\n {children}\n </span>\n );\n}\n\n// For backward compatibility with existing code\nexport const StatusBadge = ({\n status,\n onAuthClick,\n}: {\n status: 'connected' | 'disconnected' | 'connecting' | 'oauth_required';\n onAuthClick?: (e: React.MouseEvent) => void;\n}) => {\n const { t } = useTranslation();\n\n const colors = {\n connecting: 'status-badge-connecting',\n connected: 'status-badge-online',\n disconnected: 'status-badge-offline',\n oauth_required: 'status-badge-oauth-required',\n };\n\n // Map status to translation keys\n const statusTranslations = {\n connected: 'status.online',\n disconnected: 'status.offline',\n connecting: 'status.connecting',\n oauth_required: 'status.oauthRequired',\n };\n\n const isOAuthRequired = status === 'oauth_required';\n\n return (\n <span\n className={`px-2 inline-flex text-xs leading-5 font-semibold rounded-full ${colors[status]} ${isOAuthRequired && onAuthClick ? 'cursor-pointer hover:opacity-80' : ''}`}\n onClick={isOAuthRequired && onAuthClick ? (e) => onAuthClick(e) : undefined}\n title={isOAuthRequired ? t('status.clickToAuthorize') : undefined}\n >\n {isOAuthRequired && '🔐 '}\n {t(statusTranslations[status] || status)}\n </span>\n );\n};\n","import React, { useEffect, useRef, useState } from 'react';\nimport { LogEntry } from '../services/logService';\nimport { Button } from './ui/Button';\nimport { Badge } from './ui/Badge';\nimport { useTranslation } from 'react-i18next';\n\ninterface LogViewerProps {\n logs: LogEntry[];\n isLoading?: boolean;\n error?: Error | null;\n onClear?: () => void;\n}\n\nconst LogViewer: React.FC<LogViewerProps> = ({ logs, isLoading = false, error = null, onClear }) => {\n const { t } = useTranslation();\n const logContainerRef = useRef<HTMLDivElement>(null);\n const [autoScroll, setAutoScroll] = useState(true);\n const [filter, setFilter] = useState<string>('');\n const [typeFilter, setTypeFilter] = useState<Array<'info' | 'error' | 'warn' | 'debug'>>(['info', 'error', 'warn', 'debug']);\n const [sourceFilter, setSourceFilter] = useState<Array<'main' | 'child'>>(['main', 'child']);\n\n // Auto scroll to bottom when new logs come in if autoScroll is enabled\n useEffect(() => {\n if (autoScroll && logContainerRef.current) {\n logContainerRef.current.scrollTop = logContainerRef.current.scrollHeight;\n }\n }, [logs, autoScroll]);\n\n // Filter logs based on current filter settings\n const filteredLogs = logs.filter(log => {\n const matchesText = filter ? log.message.toLowerCase().includes(filter.toLowerCase()) : true;\n const matchesType = typeFilter.includes(log.type);\n const matchesSource = sourceFilter.includes(log.source as 'main' | 'child');\n return matchesText && matchesType && matchesSource;\n });\n\n // Format timestamp to readable format\n const formatTimestamp = (timestamp: number) => {\n const date = new Date(timestamp);\n return date.toLocaleTimeString([], {\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n hour12: false\n });\n };\n\n // Get badge color based on log type\n const getLogTypeColor = (type: string) => {\n switch (type) {\n case 'error': return 'bg-red-400/80 text-white';\n case 'warn': return 'bg-yellow-400/80 text-gray-900';\n case 'debug': return 'bg-purple-400/80 text-white';\n case 'info': return 'bg-blue-400/80 text-white';\n default: return 'bg-blue-400/80 text-white';\n }\n };\n\n // Get badge color based on log source\n const getSourceColor = (source: string) => {\n switch (source) {\n case 'main': return 'bg-green-400/80 text-white';\n case 'child': return 'bg-orange-400/80 text-white';\n default: return 'bg-gray-400/80 text-white';\n }\n };\n\n return (\n <div className=\"flex flex-col h-full\">\n <div className=\"bg-card p-3 rounded-t-md flex flex-wrap items-center justify-between gap-2\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"font-semibold text-sm\">{t('logs.filters')}:</span>\n\n {/* Text search filter */}\n <input\n type=\"text\"\n placeholder={t('logs.search')}\n className=\"shadow appearance-none border border-gray-200 dark:border-gray-700 rounded py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline form-input\"\n value={filter}\n onChange={(e) => setFilter(e.target.value)}\n />\n\n {/* Log type filters */}\n <div className=\"flex gap-1 items-center\">\n {(['debug', 'info', 'error', 'warn'] as const).map(type => (\n <Badge\n key={type}\n variant={typeFilter.includes(type) ? 'default' : 'outline'}\n className={`cursor-pointer ${typeFilter.includes(type) ? getLogTypeColor(type) : ''}`}\n onClick={() => {\n if (typeFilter.includes(type)) {\n setTypeFilter(prev => prev.filter(t => t !== type));\n } else {\n setTypeFilter(prev => [...prev, type]);\n }\n }}\n >\n {type}\n </Badge>\n ))}\n </div>\n\n {/* Log source filters */}\n <div className=\"flex gap-1 items-center ml-2\">\n {(['main', 'child'] as const).map(source => (\n <Badge\n key={source}\n variant={sourceFilter.includes(source) ? 'default' : 'outline'}\n className={`cursor-pointer ${sourceFilter.includes(source) ? getSourceColor(source) : ''}`}\n onClick={() => {\n if (sourceFilter.includes(source)) {\n setSourceFilter(prev => prev.filter(s => s !== source));\n } else {\n setSourceFilter(prev => [...prev, source]);\n }\n }}\n >\n {source === 'main' ? t('logs.mainProcess') : t('logs.childProcess')}\n </Badge>\n ))}\n </div>\n </div>\n\n <div className=\"flex items-center gap-2\">\n <label className=\"flex items-center gap-1 text-sm\">\n <input\n type=\"checkbox\"\n checked={autoScroll}\n onChange={() => setAutoScroll(!autoScroll)}\n className=\"form-checkbox h-4 w-4\"\n />\n {t('logs.autoScroll')}\n </label>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={onClear}\n className='btn-secondary'\n disabled={isLoading || logs.length === 0}\n >\n {t('logs.clearLogs')}\n </Button>\n </div>\n </div>\n\n <div\n ref={logContainerRef}\n className=\"flex-grow p-2 overflow-auto bg-card rounded-b-md font-mono text-sm\"\n style={{ maxHeight: 'calc(100vh - 300px)' }}\n >\n {isLoading ? (\n <div className=\"flex justify-center items-center h-full\">\n <span>{t('logs.loading')}</span>\n </div>\n ) : error ? (\n <div className=\"text-red-500 p-2\">\n {error.message}\n </div>\n ) : filteredLogs.length === 0 ? (\n <div className=\"text-center text-muted-foreground p-8\">\n {filter || typeFilter.length < 4 || sourceFilter.length < 2\n ? t('logs.noMatch')\n : t('logs.noLogs')}\n </div>\n ) : (\n filteredLogs.map((log, index) => (\n <div\n key={`${log.timestamp}-${index}`}\n className={`py-1 ${log.type === 'error' ? 'text-red-500' :\n log.type === 'warn' ? 'text-yellow-500' : ''\n }`}\n >\n <span className=\"text-gray-400\">[{formatTimestamp(log.timestamp)}]</span>\n <Badge className={`ml-2 mr-1 ${getLogTypeColor(log.type)}`}>\n {log.type}\n </Badge>\n <Badge\n variant=\"default\"\n className={`mr-2 ${getSourceColor(log.source)}`}\n >\n {log.source === 'main' ? t('logs.main') : t('logs.child')}\n {log.processId ? ` (${log.processId})` : ''}\n </Badge>\n <span className=\"whitespace-pre-wrap\">{log.message}</span>\n </div>\n ))\n )}\n </div>\n </div>\n );\n};\n\nexport default LogViewer;","import React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport LogViewer from '../components/LogViewer';\nimport { useLogs } from '../services/logService';\n\nconst LogsPage: React.FC = () => {\n const { t } = useTranslation();\n const { logs, loading, error, clearLogs } = useLogs();\n\n return (\n <div>\n <div className=\"mb-6\">\n <h1 className=\"hub-h1\">{t('pages.logs.title')}</h1>\n <p className=\"hub-sub\">\n <span className=\"hub-num\">{logs.length}</span> entries\n </p>\n </div>\n <div className=\"hub-card overflow-hidden\">\n <LogViewer logs={logs} isLoading={loading} error={error} onClear={clearLogs} />\n </div>\n </div>\n );\n};\n\nexport default LogsPage;\n"],"names":["setRef","ref","value","composeRefs","refs","node","hasCleanup","cleanups","cleanup","i","createSlot","ownerName","SlotClone","createSlotClone","Slot2","React.forwardRef","props","forwardedRef","children","slotProps","childrenArray","React.Children","slottable","isSlottable","newElement","newChildren","child","React.isValidElement","jsx","React.cloneElement","Slot","childrenRef","getElementRef","props2","mergeProps","React.Fragment","SLOTTABLE_IDENTIFIER","childProps","overrideProps","propName","slotPropValue","childPropValue","args","result","element","getter","_a","mayWarn","_b","variantStyles","sizeStyles","Button","variant","size","className","disabled","externalLoading","asChild","onClick","internalLoading","setInternalLoading","useState","isLoading","handleClick","e","Comp","cn","jsxs","Fragment","badgeVariants","Badge","LogViewer","logs","error","onClear","t","useTranslation","logContainerRef","useRef","autoScroll","setAutoScroll","filter","setFilter","typeFilter","setTypeFilter","sourceFilter","setSourceFilter","useEffect","filteredLogs","log","matchesText","matchesType","matchesSource","formatTimestamp","timestamp","getLogTypeColor","type","getSourceColor","source","prev","s","index","LogsPage","loading","clearLogs","useLogs"],"mappings":"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","x_google_ignoreList":[0,1]}
|