@xopcai/xopc 0.0.34 → 0.0.35
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/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/{agents-BENeGWaV.js → agents-3MgROWaB.js} +2 -2
- package/dist/gateway/static/root/assets/{agents-BENeGWaV.js.map → agents-3MgROWaB.js.map} +1 -1
- package/dist/gateway/static/root/assets/{apps-page-C8S_3XR3.js → apps-page-Dh89sZVt.js} +2 -2
- package/dist/gateway/static/root/assets/{apps-page-C8S_3XR3.js.map → apps-page-Dh89sZVt.js.map} +1 -1
- package/dist/gateway/static/root/assets/{channels-settings-Z0gz9LEn.js → channels-settings-BNR4uMFv.js} +2 -2
- package/dist/gateway/static/root/assets/{channels-settings-Z0gz9LEn.js.map → channels-settings-BNR4uMFv.js.map} +1 -1
- package/dist/gateway/static/root/assets/{cron-api-DHcunvTO.js → cron-api-HehSuhku.js} +2 -2
- package/dist/gateway/static/root/assets/{cron-api-DHcunvTO.js.map → cron-api-HehSuhku.js.map} +1 -1
- package/dist/gateway/static/root/assets/{cron-page-CdZjOHQ5.js → cron-page-cNl5O7jj.js} +2 -2
- package/dist/gateway/static/root/assets/{cron-page-CdZjOHQ5.js.map → cron-page-cNl5O7jj.js.map} +1 -1
- package/dist/gateway/static/root/assets/{dist-DPEltH1B.js → dist-RpqJxYGW.js} +2 -2
- package/dist/gateway/static/root/assets/{dist-DPEltH1B.js.map → dist-RpqJxYGW.js.map} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-DyEkbdRu.js → extension-debug-page-C38A0UVx.js} +2 -2
- package/dist/gateway/static/root/assets/{extension-debug-page-DyEkbdRu.js.map → extension-debug-page-C38A0UVx.js.map} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-Vr_24oNG.js → extension-page-BHVeBMn8.js} +2 -2
- package/dist/gateway/static/root/assets/{extension-page-Vr_24oNG.js.map → extension-page-BHVeBMn8.js.map} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-D3wIHYGH.js → extension-settings-page-D1iDIHYn.js} +2 -2
- package/dist/gateway/static/root/assets/{extension-settings-page-D3wIHYGH.js.map → extension-settings-page-D1iDIHYn.js.map} +1 -1
- package/dist/gateway/static/root/assets/{index-DfzxemgG.js → index-C9ACajYe.js} +5 -5
- package/dist/gateway/static/root/assets/{index-DfzxemgG.js.map → index-C9ACajYe.js.map} +1 -1
- package/dist/gateway/static/root/assets/{logs-page-D-swbxzE.js → logs-page-DxbZy88k.js} +2 -2
- package/dist/gateway/static/root/assets/{logs-page-D-swbxzE.js.map → logs-page-DxbZy88k.js.map} +1 -1
- package/dist/gateway/static/root/assets/{sessions-page-CkevfEBJ.js → sessions-page-Cl-1QJM9.js} +2 -2
- package/dist/gateway/static/root/assets/{sessions-page-CkevfEBJ.js.map → sessions-page-Cl-1QJM9.js.map} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-CGDCcKXO.js → settings-page-DUYYElOB.js} +2 -2
- package/dist/gateway/static/root/assets/{settings-page-CGDCcKXO.js.map → settings-page-DUYYElOB.js.map} +1 -1
- package/dist/gateway/static/root/assets/skills-page-MiXi4U0-.js +3 -0
- package/dist/gateway/static/root/assets/skills-page-MiXi4U0-.js.map +1 -0
- package/dist/gateway/static/root/index.html +1 -1
- package/dist/package.js +1 -1
- package/package.json +1 -1
- package/dist/gateway/static/root/assets/skills-page-ZTABuog7.js +0 -3
- package/dist/gateway/static/root/assets/skills-page-ZTABuog7.js.map +0 -1
- /package/skills/{meta → tools}/skill-creator/LICENSE.txt +0 -0
- /package/skills/{meta → tools}/skill-creator/SKILL-zh.md +0 -0
- /package/skills/{meta → tools}/skill-creator/SKILL.md +0 -0
- /package/skills/{meta → tools}/skill-creator/agents/analyzer.md +0 -0
- /package/skills/{meta → tools}/skill-creator/agents/comparator.md +0 -0
- /package/skills/{meta → tools}/skill-creator/agents/grader.md +0 -0
- /package/skills/{meta → tools}/skill-creator/assets/eval_review.html +0 -0
- /package/skills/{meta → tools}/skill-creator/eval-viewer/generate_review.py +0 -0
- /package/skills/{meta → tools}/skill-creator/eval-viewer/viewer.html +0 -0
- /package/skills/{meta → tools}/skill-creator/references/schemas.md +0 -0
- /package/skills/{meta → tools}/skill-creator/scripts/__init__.py +0 -0
- /package/skills/{meta → tools}/skill-creator/scripts/aggregate_benchmark.py +0 -0
- /package/skills/{meta → tools}/skill-creator/scripts/generate_report.py +0 -0
- /package/skills/{meta → tools}/skill-creator/scripts/improve_description.py +0 -0
- /package/skills/{meta → tools}/skill-creator/scripts/package_skill.py +0 -0
- /package/skills/{meta → tools}/skill-creator/scripts/quick_validate.py +0 -0
- /package/skills/{meta → tools}/skill-creator/scripts/run_eval.py +0 -0
- /package/skills/{meta → tools}/skill-creator/scripts/run_loop.py +0 -0
- /package/skills/{meta → tools}/skill-creator/scripts/utils.py +0 -0
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{i as e}from"./rolldown-runtime-DWdDZTNf.js";import{i as t,t as n}from"./vendor-react-DbimaAId.js";import{a as r,i}from"./vendor-swr-B5fPo7KK.js";import{t as a}from"./cn-BMCV0OMB.js";import{At as o,Cr as s,Dt as c,Et as l,Gr as u,Nn as d,On as f,Ot as p,Qn as m,Tt as h,an as g,bn as _,cn as v,cr as y,hn as b,ii as x,in as S,kt as C,mi as w,mn as T,mr as E,on as D,pn as O,rn as k,tr as A,ui as j,yi as M}from"./index-DfzxemgG.js";var N=e(t(),1),P=n();function F({className:e}){let t=b(e=>!!e.token),[n,r]=(0,N.useState)(``),[o,s]=(0,N.useState)(``),c=t?`marketplace-${o}`:null;(0,N.useEffect)(()=>{let e=window.setTimeout(()=>s(n.trim()),300);return()=>window.clearTimeout(e)},[n]);let{data:l,isLoading:d,error:f}=i(c,async()=>O(o.length>0?v(`/api/marketplace?q=${encodeURIComponent(o)}`):v(`/api/marketplace`)),{revalidateOnFocus:!1}),p=l?.extensions??[];return(0,P.jsxs)(`div`,{className:a(`flex flex-col gap-4`,e),children:[(0,P.jsxs)(`div`,{className:`relative`,children:[(0,P.jsx)(A,{className:`pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-fg-muted`,strokeWidth:1.75,"aria-hidden":!0}),(0,P.jsx)(`input`,{type:`search`,value:n,onChange:e=>r(e.target.value),placeholder:`Search extensions…`,className:`ui-input h-10 w-full rounded-lg border border-edge bg-surface-base pl-9 pr-3 text-sm text-fg placeholder:text-fg-muted`})]}),f?(0,P.jsx)(`p`,{className:`text-sm text-fg-muted`,children:f instanceof Error?f.message:`Failed to load marketplace`}):null,d&&!l?(0,P.jsx)(`p`,{className:`text-sm text-fg-muted`,children:`Loading…`}):(0,P.jsx)(`ul`,{className:`flex flex-col gap-3`,children:p.length===0?(0,P.jsx)(`li`,{className:`text-sm text-fg-muted`,children:`No extensions in registry.`}):p.map(e=>(0,P.jsxs)(`li`,{className:`rounded-xl border border-edge bg-surface-base p-4 shadow-surface`,children:[(0,P.jsx)(`div`,{className:`flex flex-wrap items-start justify-between gap-2`,children:(0,P.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,P.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,P.jsx)(`h3`,{className:`font-semibold text-fg`,children:e.name}),e.verified?(0,P.jsx)(x,{className:`size-4 shrink-0 text-emerald-600 dark:text-emerald-400`,strokeWidth:1.75,"aria-label":`Verified`}):null,e.version?(0,P.jsx)(`span`,{className:`text-xs text-fg-muted`,children:e.version}):null]}),e.description?(0,P.jsx)(`p`,{className:`mt-1 text-sm text-fg-muted`,children:e.description}):null,(0,P.jsx)(`div`,{className:`mt-2 flex flex-wrap gap-1.5`,children:(e.categories??[]).map(e=>(0,P.jsx)(`span`,{className:`rounded-md border border-edge bg-surface-panel px-2 py-0.5 text-[11px] text-fg-muted`,children:e},e))}),(0,P.jsxs)(`p`,{className:`mt-2 flex items-center gap-1.5 text-xs text-fg-muted`,children:[(0,P.jsx)(E,{className:`size-3.5 shrink-0`,strokeWidth:1.75,"aria-hidden":!0}),(0,P.jsx)(`code`,{className:`rounded bg-surface-panel px-1 py-0.5`,children:e.npmPackage})]}),e.homepage?(0,P.jsxs)(`a`,{href:e.homepage,target:`_blank`,rel:`noreferrer`,className:`mt-2 inline-flex items-center gap-1 text-xs text-accent hover:underline`,children:[(0,P.jsx)(u,{className:`size-3.5`,strokeWidth:1.75,"aria-hidden":!0}),`Homepage`]}):null]})}),(0,P.jsxs)(`p`,{className:`mt-3 text-[11px] text-fg-muted`,children:[`npm package:`,` `,(0,P.jsx)(`code`,{className:`rounded bg-surface-panel px-1 py-0.5`,children:e.npmPackage})]})]},e.id))})]})}function I(){let e=_(e=>e.language),t=f(e),n=T(e=>e.setPageHeader),i=T(e=>e.clearPageHeader),a=g(),o=D(),{mutate:s}=r(),[c,l]=(0,N.useState)(`all`),[u,d]=(0,N.useState)(``),[p,m]=(0,N.useState)(null),h=(0,N.useMemo)(()=>{let t=a;c===`ui`&&(t=t.filter(e=>e.hasUi)),c===`backend`&&(t=t.filter(e=>!e.hasUi));let n=u.trim().toLowerCase();return n&&(t=t.filter(e=>(e.name??``).toLowerCase().includes(n)||e.id.toLowerCase().includes(n)||(e.description??``).toLowerCase().includes(n))),[...t].sort((t,n)=>t.hasUi===n.hasUi?(t.name||t.id).localeCompare(n.name||n.id,e):t.hasUi?-1:1)},[a,c,u,e]);return(0,N.useEffect)(()=>{m(e=>{if(!e)return e;let t=a.find(t=>t.id===e.id);return t?R(e)===R(t)&&e.active===t.active?e:t:null})},[a]),(0,N.useLayoutEffect)(()=>(n({startExtra:null,main:(0,P.jsx)(`div`,{className:`w-full min-w-0 px-3 sm:px-5 xl:px-6`,children:(0,P.jsx)(`h1`,{className:`min-w-0 truncate text-base font-semibold tracking-tight text-fg`,children:t.appsPage.title})}),end:null}),()=>i()),[i,t.appsPage.title,n]),o&&c!==`marketplace`?(0,P.jsx)(W,{}):(0,P.jsxs)(`div`,{className:`flex min-h-0 flex-1 flex-col overflow-y-auto bg-surface-panel`,children:[(0,P.jsxs)(`div`,{className:`mx-auto w-full max-w-app-main px-4 py-8`,children:[(0,P.jsxs)(`header`,{className:`mb-6`,children:[(0,P.jsx)(`h1`,{className:`text-xl font-semibold text-fg`,children:t.appsPage.title}),(0,P.jsx)(`p`,{className:`mt-1 text-sm text-fg-muted`,children:t.appsPage.subtitle})]}),(0,P.jsxs)(`div`,{className:`mb-5 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between`,children:[(0,P.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,P.jsx)(L,{active:c===`all`,onClick:()=>l(`all`),label:t.appsPage.tabAll}),(0,P.jsx)(L,{active:c===`ui`,onClick:()=>l(`ui`),label:t.appsPage.tabWithUi}),(0,P.jsx)(L,{active:c===`backend`,onClick:()=>l(`backend`),label:t.appsPage.tabBackend}),(0,P.jsx)(L,{active:c===`marketplace`,onClick:()=>l(`marketplace`),label:t.appsPage.tabMarketplace})]}),c!==`marketplace`&&a.length>0?(0,P.jsxs)(`div`,{className:`relative w-full sm:max-w-xs`,children:[(0,P.jsx)(A,{className:`pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-fg-muted`,"aria-hidden":!0}),(0,P.jsx)(`input`,{type:`search`,value:u,onChange:e=>d(e.target.value),placeholder:t.appsPage.searchPlaceholder,className:`w-full rounded-lg border border-edge bg-surface-base py-2 pl-9 pr-3 text-sm text-fg placeholder:text-fg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent`,autoComplete:`off`})]}):null]}),c===`marketplace`?(0,P.jsx)(F,{}):a.length===0?(0,P.jsx)(G,{message:t.appsPage.empty}):h.length===0?(0,P.jsx)(`p`,{className:`rounded-xl border border-dashed border-edge-subtle bg-surface-hover/30 px-4 py-8 text-center text-sm text-fg-muted dark:bg-surface-hover/15`,children:t.appsPage.noSearchResults}):(0,P.jsx)(`div`,{className:`grid gap-4 sm:grid-cols-2 lg:grid-cols-3`,children:h.map(e=>(0,P.jsx)(V,{extension:e,copy:t.appsPage,onOpen:()=>m(e)},e.id))})]}),p?(0,P.jsx)(H,{extension:p,copy:t.appsPage,onClose:()=>m(null),onAfterToggle:async()=>{await s(`gateway-extensions-list`)}},p.id):null]})}function L({active:e,onClick:t,label:n}){return(0,P.jsx)(`button`,{type:`button`,onClick:t,className:a(`rounded-full border px-3 py-1.5 text-xs font-medium transition-colors`,`focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent`,e?`border-accent/40 bg-accent-soft text-accent-fg`:`border-edge bg-surface-base text-fg-muted hover:bg-surface-hover hover:text-fg`),children:n})}function R(e){return e.activationEligible??e.active}function z(e,t){return e.source===`bundled`?t.providerBundled:e.source===`global`?t.providerGlobal:e.source===`workspace`?t.providerWorkspace:t.providerOther}function B(e,t){let n=R(e);return n&&e.active?t.runStateLive:n&&!e.active?t.runStatePendingOn:!n&&e.active?t.runStatePendingOff:t.runStateOff}function V({extension:e,copy:t,onOpen:n}){let r=R(e);return(0,P.jsx)(`button`,{type:`button`,onClick:n,className:a(`group flex w-full flex-col rounded-xl border border-edge bg-surface-base p-4 text-left shadow-sm transition-colors`,`hover:border-edge-subtle hover:bg-surface-hover/40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent`,`dark:hover:bg-surface-hover/25`),children:(0,P.jsxs)(`div`,{className:`flex gap-3`,children:[(0,P.jsx)(`div`,{className:`flex size-12 shrink-0 items-center justify-center rounded-xl bg-accent-soft text-base font-semibold text-accent-fg`,"aria-hidden":!0,children:(e.name||e.id).charAt(0).toUpperCase()}),(0,P.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,P.jsxs)(`div`,{className:`flex items-start justify-between gap-2`,children:[(0,P.jsxs)(`div`,{className:`min-w-0`,children:[(0,P.jsx)(`h2`,{className:`truncate text-sm font-semibold text-fg`,children:e.name}),e.version?(0,P.jsxs)(`span`,{className:`text-[11px] text-fg-muted`,children:[`v`,e.version]}):null]}),r?(0,P.jsxs)(`span`,{className:`inline-flex shrink-0 items-center gap-1 rounded-full bg-surface-hover px-2 py-0.5 text-[11px] font-medium text-fg-muted`,children:[(0,P.jsx)(j,{className:`size-3`,strokeWidth:2.5,"aria-hidden":!0}),t.statusEnabled]}):(0,P.jsx)(`span`,{className:`flex size-8 shrink-0 items-center justify-center rounded-full border-2 border-accent text-accent`,"aria-hidden":!0,children:(0,P.jsx)(y,{className:`size-4`,strokeWidth:2.5})})]}),(0,P.jsx)(`p`,{className:`mt-2 line-clamp-2 text-xs leading-relaxed text-fg-muted`,children:e.description?.trim()||t.cardNoDescription}),(0,P.jsxs)(`div`,{className:`mt-2 flex flex-wrap gap-1.5`,children:[(0,P.jsx)(`span`,{className:`rounded-md bg-surface-hover px-1.5 py-0.5 text-[10px] font-medium uppercase tracking-wide text-fg-muted`,children:e.hasUi?t.badgeKindUi:t.badgeKindBackend}),e.source===`bundled`?(0,P.jsx)(`span`,{className:`rounded-md bg-surface-hover px-1.5 py-0.5 text-[10px] font-medium uppercase tracking-wide text-fg-muted`,children:t.badgeBundled}):null]})]})]})})}function H({extension:e,copy:t,onClose:n,onAfterToggle:r}){let[i,f]=(0,N.useState)(!1),[g,_]=(0,N.useState)(null),y=e.ui?.contributions?.pages??[],b=e.ui?.contributions?.settingsPanels??[],x=e.ui?.contributions?.chatWidgets??[],T=e.ui?.contributions?.sidebarPanels??[],E=y.find(e=>e.showInNav)??y[0],D=b[0],A=E?k(e.id,E):null,j=D?`/settings/ext/${e.id}/${D.id}`:e.hasConfigSchema?`/settings/ext/${e.id}`:null,F=R(e),I=e.source===`bundled`,L=async n=>{_(null),f(!0);try{await O(v(`/api/extensions/bundled/activation`),{method:`POST`,body:JSON.stringify({extensionId:e.id,enabled:n})}),await r()}catch(e){_(e instanceof Error?e.message:t.toggleError)}finally{f(!1)}};return(0,P.jsx)(C,{defaultOpen:!0,onOpenChange:e=>!e&&n(),children:(0,P.jsxs)(p,{children:[(0,P.jsx)(c,{className:`xopc-dialog-overlay fixed inset-0 z-[130] bg-scrim`}),(0,P.jsxs)(h,{className:`fixed left-1/2 top-1/2 z-[131] flex max-h-[min(90vh,44rem)] w-[min(42rem,calc(100vw-1.5rem))] -translate-x-1/2 -translate-y-1/2 flex-col overflow-hidden rounded-xl border border-edge bg-surface-panel shadow-elevated`,onOpenAutoFocus:e=>e.preventDefault(),children:[(0,P.jsxs)(`div`,{className:`flex shrink-0 items-center justify-between gap-2 border-b border-edge px-4 py-3`,children:[(0,P.jsx)(`button`,{type:`button`,onClick:n,className:`inline-flex size-9 items-center justify-center rounded-lg text-fg-muted hover:bg-surface-hover hover:text-fg focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent`,"aria-label":t.detailBack,children:(0,P.jsx)(w,{className:`size-5`})}),(0,P.jsx)(o,{className:`min-w-0 flex-1 truncate text-center text-sm font-semibold text-fg`,children:t.detailTitle}),(0,P.jsxs)(l,{className:`sr-only`,children:[e.name,` (`,e.id,`)`]}),(0,P.jsx)(`button`,{type:`button`,onClick:n,className:`inline-flex size-9 items-center justify-center rounded-lg text-fg-muted hover:bg-surface-hover hover:text-fg focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent`,"aria-label":t.detailClose,children:(0,P.jsx)(d,{className:`size-5`})})]}),(0,P.jsxs)(`div`,{className:`min-h-0 flex-1 overflow-y-auto px-5 py-5`,children:[(0,P.jsxs)(`div`,{className:`flex flex-wrap items-start gap-4`,children:[(0,P.jsx)(`div`,{className:`flex size-16 shrink-0 items-center justify-center rounded-2xl bg-accent-soft text-xl font-semibold text-accent-fg`,"aria-hidden":!0,children:(e.name||e.id).charAt(0).toUpperCase()}),(0,P.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,P.jsx)(`h3`,{className:`text-lg font-semibold text-fg`,children:e.name}),(0,P.jsxs)(`p`,{className:`mt-0.5 text-sm text-fg-muted`,children:[t.detailProviderPrefix,` `,z(e,t)]}),e.version?(0,P.jsxs)(`p`,{className:`mt-1 text-xs text-fg-muted`,children:[`v`,e.version]}):null]}),I?(0,P.jsx)(`div`,{className:`flex w-full flex-col items-stretch gap-2 sm:w-auto sm:items-end`,children:(0,P.jsxs)(`button`,{type:`button`,disabled:i,"aria-busy":i,onClick:()=>void L(!F),className:a(`relative inline-flex max-w-full rounded-full py-1.5 text-sm font-medium`,`transition-[color,background-color,border-color,opacity] duration-200 ease-out`,`focus-visible:outline-none focus-visible:ring-2 motion-reduce:transition-none`,F?`border-2 border-red-500/50 text-red-600 hover:bg-red-500/10 focus-visible:ring-red-500/40 dark:text-red-400`:`border-2 border-transparent bg-accent text-white hover:opacity-90 focus-visible:ring-accent`,i&&`cursor-wait opacity-80`),children:[(0,P.jsx)(`span`,{className:`block whitespace-nowrap px-4 text-center leading-none`,children:F?t.actionDisable:t.actionEnable}),(0,P.jsx)(s,{className:a(`pointer-events-none absolute right-2 top-1/2 size-3 -translate-y-1/2 text-current opacity-90`,i?`animate-spin`:`invisible`),"aria-hidden":!0})]})}):null]}),(0,P.jsx)(`p`,{className:`mt-5 text-sm leading-relaxed text-fg`,children:e.description?.trim()||t.detailNoDescription}),e.hasUi?null:(0,P.jsx)(`p`,{className:`mt-3 text-xs text-fg-muted`,children:t.backendOnlyHint}),(0,P.jsx)(`p`,{className:`mt-2 text-xs text-fg-muted`,children:B(e,t)}),g?(0,P.jsx)(`p`,{className:`mt-3 rounded-lg border border-red-500/30 bg-red-500/10 px-3 py-2 text-xs text-fg`,role:`alert`,children:g}):null,I?null:(0,P.jsx)(`p`,{className:`mt-4 rounded-lg border border-edge-subtle bg-surface-hover/40 px-3 py-2 text-xs text-fg-muted dark:bg-surface-hover/20`,children:t.cliManageHint}),e.hasUi&&(y.length>0||b.length>0||x.length>0)?(0,P.jsxs)(`section`,{className:`mt-8`,children:[(0,P.jsx)(`h4`,{className:`mb-3 text-sm font-semibold text-fg`,children:t.detailSectionFeatures}),(0,P.jsxs)(`div`,{className:`flex flex-wrap gap-1.5`,children:[(0,P.jsx)(U,{template:t.badgePages,count:y.length,hidden:y.length===0}),(0,P.jsx)(U,{template:t.badgeSettings,count:b.length,hidden:b.length===0}),(0,P.jsx)(U,{template:t.badgeWidgets,count:x.length,hidden:x.length===0}),(0,P.jsx)(U,{template:t.badgeSidebar,count:T.length,hidden:T.length===0})]})]}):null,S(e)&&(A||j)?(0,P.jsxs)(`div`,{className:`mt-6 flex flex-wrap gap-2 border-t border-edge-subtle pt-4`,children:[A?(0,P.jsxs)(M,{to:A,onClick:n,className:a(`inline-flex items-center gap-1.5 rounded-lg border border-edge px-3 py-2 text-sm font-medium text-fg`,`hover:bg-surface-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent`),children:[(0,P.jsx)(u,{className:`size-4 shrink-0 opacity-80`,"aria-hidden":!0}),t.open]}):null,j?(0,P.jsxs)(M,{to:j,onClick:n,className:a(`inline-flex items-center gap-1.5 rounded-lg border border-edge px-3 py-2 text-sm font-medium text-fg`,`hover:bg-surface-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent`),children:[(0,P.jsx)(m,{className:`size-4 shrink-0 opacity-80`,"aria-hidden":!0}),t.openSettings]}):null]}):null,(0,P.jsx)(`p`,{className:`mt-6 text-[11px] leading-relaxed text-fg-muted`,children:t.restartNote})]})]})]})})}function U({template:e,count:t,hidden:n}){return n||t===0?null:(0,P.jsx)(`span`,{className:`inline-flex items-center rounded-md bg-surface-hover px-2 py-0.5 text-[11px] font-medium text-fg-muted`,children:e.replace(/\{\{count\}\}/g,String(t))})}function W(){return(0,P.jsx)(`div`,{className:`flex min-h-0 flex-1 flex-col overflow-y-auto bg-surface-panel`,children:(0,P.jsxs)(`div`,{className:`mx-auto w-full max-w-app-main px-4 py-8`,children:[(0,P.jsx)(`div`,{className:`mb-6 h-8 w-40 max-w-full animate-pulse rounded-md bg-surface-hover`}),(0,P.jsx)(`div`,{className:`mb-2 h-4 w-full max-w-md animate-pulse rounded bg-surface-hover`}),(0,P.jsx)(`div`,{className:`mb-5 h-9 w-full max-w-lg animate-pulse rounded-full bg-surface-hover`}),(0,P.jsx)(`div`,{className:`mt-6 grid gap-4 sm:grid-cols-2 lg:grid-cols-3`,children:[0,1,2,3,4,5].map(e=>(0,P.jsx)(`div`,{className:`h-36 animate-pulse rounded-xl border border-edge bg-surface-base`},e))})]})})}function G({message:e}){return(0,P.jsx)(`div`,{className:`flex min-h-[min(40vh,16rem)] flex-col items-center justify-center rounded-xl border border-dashed border-edge-subtle bg-surface-hover/40 px-4 py-12 text-center dark:bg-surface-hover/20`,children:(0,P.jsx)(`p`,{className:`text-sm text-fg-muted`,children:e})})}export{I as AppsPage};
|
|
2
|
-
//# sourceMappingURL=apps-page-
|
|
1
|
+
import{i as e}from"./rolldown-runtime-DWdDZTNf.js";import{i as t,t as n}from"./vendor-react-DbimaAId.js";import{a as r,i}from"./vendor-swr-B5fPo7KK.js";import{t as a}from"./cn-BMCV0OMB.js";import{At as o,Cr as s,Dt as c,Et as l,Gr as u,Nn as d,On as f,Ot as p,Qn as m,Tt as h,an as g,bn as _,cn as v,cr as y,hn as b,ii as x,in as S,kt as C,mi as w,mn as T,mr as E,on as D,pn as O,rn as k,tr as A,ui as j,yi as M}from"./index-C9ACajYe.js";var N=e(t(),1),P=n();function F({className:e}){let t=b(e=>!!e.token),[n,r]=(0,N.useState)(``),[o,s]=(0,N.useState)(``),c=t?`marketplace-${o}`:null;(0,N.useEffect)(()=>{let e=window.setTimeout(()=>s(n.trim()),300);return()=>window.clearTimeout(e)},[n]);let{data:l,isLoading:d,error:f}=i(c,async()=>O(o.length>0?v(`/api/marketplace?q=${encodeURIComponent(o)}`):v(`/api/marketplace`)),{revalidateOnFocus:!1}),p=l?.extensions??[];return(0,P.jsxs)(`div`,{className:a(`flex flex-col gap-4`,e),children:[(0,P.jsxs)(`div`,{className:`relative`,children:[(0,P.jsx)(A,{className:`pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-fg-muted`,strokeWidth:1.75,"aria-hidden":!0}),(0,P.jsx)(`input`,{type:`search`,value:n,onChange:e=>r(e.target.value),placeholder:`Search extensions…`,className:`ui-input h-10 w-full rounded-lg border border-edge bg-surface-base pl-9 pr-3 text-sm text-fg placeholder:text-fg-muted`})]}),f?(0,P.jsx)(`p`,{className:`text-sm text-fg-muted`,children:f instanceof Error?f.message:`Failed to load marketplace`}):null,d&&!l?(0,P.jsx)(`p`,{className:`text-sm text-fg-muted`,children:`Loading…`}):(0,P.jsx)(`ul`,{className:`flex flex-col gap-3`,children:p.length===0?(0,P.jsx)(`li`,{className:`text-sm text-fg-muted`,children:`No extensions in registry.`}):p.map(e=>(0,P.jsxs)(`li`,{className:`rounded-xl border border-edge bg-surface-base p-4 shadow-surface`,children:[(0,P.jsx)(`div`,{className:`flex flex-wrap items-start justify-between gap-2`,children:(0,P.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,P.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,P.jsx)(`h3`,{className:`font-semibold text-fg`,children:e.name}),e.verified?(0,P.jsx)(x,{className:`size-4 shrink-0 text-emerald-600 dark:text-emerald-400`,strokeWidth:1.75,"aria-label":`Verified`}):null,e.version?(0,P.jsx)(`span`,{className:`text-xs text-fg-muted`,children:e.version}):null]}),e.description?(0,P.jsx)(`p`,{className:`mt-1 text-sm text-fg-muted`,children:e.description}):null,(0,P.jsx)(`div`,{className:`mt-2 flex flex-wrap gap-1.5`,children:(e.categories??[]).map(e=>(0,P.jsx)(`span`,{className:`rounded-md border border-edge bg-surface-panel px-2 py-0.5 text-[11px] text-fg-muted`,children:e},e))}),(0,P.jsxs)(`p`,{className:`mt-2 flex items-center gap-1.5 text-xs text-fg-muted`,children:[(0,P.jsx)(E,{className:`size-3.5 shrink-0`,strokeWidth:1.75,"aria-hidden":!0}),(0,P.jsx)(`code`,{className:`rounded bg-surface-panel px-1 py-0.5`,children:e.npmPackage})]}),e.homepage?(0,P.jsxs)(`a`,{href:e.homepage,target:`_blank`,rel:`noreferrer`,className:`mt-2 inline-flex items-center gap-1 text-xs text-accent hover:underline`,children:[(0,P.jsx)(u,{className:`size-3.5`,strokeWidth:1.75,"aria-hidden":!0}),`Homepage`]}):null]})}),(0,P.jsxs)(`p`,{className:`mt-3 text-[11px] text-fg-muted`,children:[`npm package:`,` `,(0,P.jsx)(`code`,{className:`rounded bg-surface-panel px-1 py-0.5`,children:e.npmPackage})]})]},e.id))})]})}function I(){let e=_(e=>e.language),t=f(e),n=T(e=>e.setPageHeader),i=T(e=>e.clearPageHeader),a=g(),o=D(),{mutate:s}=r(),[c,l]=(0,N.useState)(`all`),[u,d]=(0,N.useState)(``),[p,m]=(0,N.useState)(null),h=(0,N.useMemo)(()=>{let t=a;c===`ui`&&(t=t.filter(e=>e.hasUi)),c===`backend`&&(t=t.filter(e=>!e.hasUi));let n=u.trim().toLowerCase();return n&&(t=t.filter(e=>(e.name??``).toLowerCase().includes(n)||e.id.toLowerCase().includes(n)||(e.description??``).toLowerCase().includes(n))),[...t].sort((t,n)=>t.hasUi===n.hasUi?(t.name||t.id).localeCompare(n.name||n.id,e):t.hasUi?-1:1)},[a,c,u,e]);return(0,N.useEffect)(()=>{m(e=>{if(!e)return e;let t=a.find(t=>t.id===e.id);return t?R(e)===R(t)&&e.active===t.active?e:t:null})},[a]),(0,N.useLayoutEffect)(()=>(n({startExtra:null,main:(0,P.jsx)(`div`,{className:`w-full min-w-0 px-3 sm:px-5 xl:px-6`,children:(0,P.jsx)(`h1`,{className:`min-w-0 truncate text-base font-semibold tracking-tight text-fg`,children:t.appsPage.title})}),end:null}),()=>i()),[i,t.appsPage.title,n]),o&&c!==`marketplace`?(0,P.jsx)(W,{}):(0,P.jsxs)(`div`,{className:`flex min-h-0 flex-1 flex-col overflow-y-auto bg-surface-panel`,children:[(0,P.jsxs)(`div`,{className:`mx-auto w-full max-w-app-main px-4 py-8`,children:[(0,P.jsxs)(`header`,{className:`mb-6`,children:[(0,P.jsx)(`h1`,{className:`text-xl font-semibold text-fg`,children:t.appsPage.title}),(0,P.jsx)(`p`,{className:`mt-1 text-sm text-fg-muted`,children:t.appsPage.subtitle})]}),(0,P.jsxs)(`div`,{className:`mb-5 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between`,children:[(0,P.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,P.jsx)(L,{active:c===`all`,onClick:()=>l(`all`),label:t.appsPage.tabAll}),(0,P.jsx)(L,{active:c===`ui`,onClick:()=>l(`ui`),label:t.appsPage.tabWithUi}),(0,P.jsx)(L,{active:c===`backend`,onClick:()=>l(`backend`),label:t.appsPage.tabBackend}),(0,P.jsx)(L,{active:c===`marketplace`,onClick:()=>l(`marketplace`),label:t.appsPage.tabMarketplace})]}),c!==`marketplace`&&a.length>0?(0,P.jsxs)(`div`,{className:`relative w-full sm:max-w-xs`,children:[(0,P.jsx)(A,{className:`pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-fg-muted`,"aria-hidden":!0}),(0,P.jsx)(`input`,{type:`search`,value:u,onChange:e=>d(e.target.value),placeholder:t.appsPage.searchPlaceholder,className:`w-full rounded-lg border border-edge bg-surface-base py-2 pl-9 pr-3 text-sm text-fg placeholder:text-fg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent`,autoComplete:`off`})]}):null]}),c===`marketplace`?(0,P.jsx)(F,{}):a.length===0?(0,P.jsx)(G,{message:t.appsPage.empty}):h.length===0?(0,P.jsx)(`p`,{className:`rounded-xl border border-dashed border-edge-subtle bg-surface-hover/30 px-4 py-8 text-center text-sm text-fg-muted dark:bg-surface-hover/15`,children:t.appsPage.noSearchResults}):(0,P.jsx)(`div`,{className:`grid gap-4 sm:grid-cols-2 lg:grid-cols-3`,children:h.map(e=>(0,P.jsx)(V,{extension:e,copy:t.appsPage,onOpen:()=>m(e)},e.id))})]}),p?(0,P.jsx)(H,{extension:p,copy:t.appsPage,onClose:()=>m(null),onAfterToggle:async()=>{await s(`gateway-extensions-list`)}},p.id):null]})}function L({active:e,onClick:t,label:n}){return(0,P.jsx)(`button`,{type:`button`,onClick:t,className:a(`rounded-full border px-3 py-1.5 text-xs font-medium transition-colors`,`focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent`,e?`border-accent/40 bg-accent-soft text-accent-fg`:`border-edge bg-surface-base text-fg-muted hover:bg-surface-hover hover:text-fg`),children:n})}function R(e){return e.activationEligible??e.active}function z(e,t){return e.source===`bundled`?t.providerBundled:e.source===`global`?t.providerGlobal:e.source===`workspace`?t.providerWorkspace:t.providerOther}function B(e,t){let n=R(e);return n&&e.active?t.runStateLive:n&&!e.active?t.runStatePendingOn:!n&&e.active?t.runStatePendingOff:t.runStateOff}function V({extension:e,copy:t,onOpen:n}){let r=R(e);return(0,P.jsx)(`button`,{type:`button`,onClick:n,className:a(`group flex w-full flex-col rounded-xl border border-edge bg-surface-base p-4 text-left shadow-sm transition-colors`,`hover:border-edge-subtle hover:bg-surface-hover/40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent`,`dark:hover:bg-surface-hover/25`),children:(0,P.jsxs)(`div`,{className:`flex gap-3`,children:[(0,P.jsx)(`div`,{className:`flex size-12 shrink-0 items-center justify-center rounded-xl bg-accent-soft text-base font-semibold text-accent-fg`,"aria-hidden":!0,children:(e.name||e.id).charAt(0).toUpperCase()}),(0,P.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,P.jsxs)(`div`,{className:`flex items-start justify-between gap-2`,children:[(0,P.jsxs)(`div`,{className:`min-w-0`,children:[(0,P.jsx)(`h2`,{className:`truncate text-sm font-semibold text-fg`,children:e.name}),e.version?(0,P.jsxs)(`span`,{className:`text-[11px] text-fg-muted`,children:[`v`,e.version]}):null]}),r?(0,P.jsxs)(`span`,{className:`inline-flex shrink-0 items-center gap-1 rounded-full bg-surface-hover px-2 py-0.5 text-[11px] font-medium text-fg-muted`,children:[(0,P.jsx)(j,{className:`size-3`,strokeWidth:2.5,"aria-hidden":!0}),t.statusEnabled]}):(0,P.jsx)(`span`,{className:`flex size-8 shrink-0 items-center justify-center rounded-full border-2 border-accent text-accent`,"aria-hidden":!0,children:(0,P.jsx)(y,{className:`size-4`,strokeWidth:2.5})})]}),(0,P.jsx)(`p`,{className:`mt-2 line-clamp-2 text-xs leading-relaxed text-fg-muted`,children:e.description?.trim()||t.cardNoDescription}),(0,P.jsxs)(`div`,{className:`mt-2 flex flex-wrap gap-1.5`,children:[(0,P.jsx)(`span`,{className:`rounded-md bg-surface-hover px-1.5 py-0.5 text-[10px] font-medium uppercase tracking-wide text-fg-muted`,children:e.hasUi?t.badgeKindUi:t.badgeKindBackend}),e.source===`bundled`?(0,P.jsx)(`span`,{className:`rounded-md bg-surface-hover px-1.5 py-0.5 text-[10px] font-medium uppercase tracking-wide text-fg-muted`,children:t.badgeBundled}):null]})]})]})})}function H({extension:e,copy:t,onClose:n,onAfterToggle:r}){let[i,f]=(0,N.useState)(!1),[g,_]=(0,N.useState)(null),y=e.ui?.contributions?.pages??[],b=e.ui?.contributions?.settingsPanels??[],x=e.ui?.contributions?.chatWidgets??[],T=e.ui?.contributions?.sidebarPanels??[],E=y.find(e=>e.showInNav)??y[0],D=b[0],A=E?k(e.id,E):null,j=D?`/settings/ext/${e.id}/${D.id}`:e.hasConfigSchema?`/settings/ext/${e.id}`:null,F=R(e),I=e.source===`bundled`,L=async n=>{_(null),f(!0);try{await O(v(`/api/extensions/bundled/activation`),{method:`POST`,body:JSON.stringify({extensionId:e.id,enabled:n})}),await r()}catch(e){_(e instanceof Error?e.message:t.toggleError)}finally{f(!1)}};return(0,P.jsx)(C,{defaultOpen:!0,onOpenChange:e=>!e&&n(),children:(0,P.jsxs)(p,{children:[(0,P.jsx)(c,{className:`xopc-dialog-overlay fixed inset-0 z-[130] bg-scrim`}),(0,P.jsxs)(h,{className:`fixed left-1/2 top-1/2 z-[131] flex max-h-[min(90vh,44rem)] w-[min(42rem,calc(100vw-1.5rem))] -translate-x-1/2 -translate-y-1/2 flex-col overflow-hidden rounded-xl border border-edge bg-surface-panel shadow-elevated`,onOpenAutoFocus:e=>e.preventDefault(),children:[(0,P.jsxs)(`div`,{className:`flex shrink-0 items-center justify-between gap-2 border-b border-edge px-4 py-3`,children:[(0,P.jsx)(`button`,{type:`button`,onClick:n,className:`inline-flex size-9 items-center justify-center rounded-lg text-fg-muted hover:bg-surface-hover hover:text-fg focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent`,"aria-label":t.detailBack,children:(0,P.jsx)(w,{className:`size-5`})}),(0,P.jsx)(o,{className:`min-w-0 flex-1 truncate text-center text-sm font-semibold text-fg`,children:t.detailTitle}),(0,P.jsxs)(l,{className:`sr-only`,children:[e.name,` (`,e.id,`)`]}),(0,P.jsx)(`button`,{type:`button`,onClick:n,className:`inline-flex size-9 items-center justify-center rounded-lg text-fg-muted hover:bg-surface-hover hover:text-fg focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent`,"aria-label":t.detailClose,children:(0,P.jsx)(d,{className:`size-5`})})]}),(0,P.jsxs)(`div`,{className:`min-h-0 flex-1 overflow-y-auto px-5 py-5`,children:[(0,P.jsxs)(`div`,{className:`flex flex-wrap items-start gap-4`,children:[(0,P.jsx)(`div`,{className:`flex size-16 shrink-0 items-center justify-center rounded-2xl bg-accent-soft text-xl font-semibold text-accent-fg`,"aria-hidden":!0,children:(e.name||e.id).charAt(0).toUpperCase()}),(0,P.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,P.jsx)(`h3`,{className:`text-lg font-semibold text-fg`,children:e.name}),(0,P.jsxs)(`p`,{className:`mt-0.5 text-sm text-fg-muted`,children:[t.detailProviderPrefix,` `,z(e,t)]}),e.version?(0,P.jsxs)(`p`,{className:`mt-1 text-xs text-fg-muted`,children:[`v`,e.version]}):null]}),I?(0,P.jsx)(`div`,{className:`flex w-full flex-col items-stretch gap-2 sm:w-auto sm:items-end`,children:(0,P.jsxs)(`button`,{type:`button`,disabled:i,"aria-busy":i,onClick:()=>void L(!F),className:a(`relative inline-flex max-w-full rounded-full py-1.5 text-sm font-medium`,`transition-[color,background-color,border-color,opacity] duration-200 ease-out`,`focus-visible:outline-none focus-visible:ring-2 motion-reduce:transition-none`,F?`border-2 border-red-500/50 text-red-600 hover:bg-red-500/10 focus-visible:ring-red-500/40 dark:text-red-400`:`border-2 border-transparent bg-accent text-white hover:opacity-90 focus-visible:ring-accent`,i&&`cursor-wait opacity-80`),children:[(0,P.jsx)(`span`,{className:`block whitespace-nowrap px-4 text-center leading-none`,children:F?t.actionDisable:t.actionEnable}),(0,P.jsx)(s,{className:a(`pointer-events-none absolute right-2 top-1/2 size-3 -translate-y-1/2 text-current opacity-90`,i?`animate-spin`:`invisible`),"aria-hidden":!0})]})}):null]}),(0,P.jsx)(`p`,{className:`mt-5 text-sm leading-relaxed text-fg`,children:e.description?.trim()||t.detailNoDescription}),e.hasUi?null:(0,P.jsx)(`p`,{className:`mt-3 text-xs text-fg-muted`,children:t.backendOnlyHint}),(0,P.jsx)(`p`,{className:`mt-2 text-xs text-fg-muted`,children:B(e,t)}),g?(0,P.jsx)(`p`,{className:`mt-3 rounded-lg border border-red-500/30 bg-red-500/10 px-3 py-2 text-xs text-fg`,role:`alert`,children:g}):null,I?null:(0,P.jsx)(`p`,{className:`mt-4 rounded-lg border border-edge-subtle bg-surface-hover/40 px-3 py-2 text-xs text-fg-muted dark:bg-surface-hover/20`,children:t.cliManageHint}),e.hasUi&&(y.length>0||b.length>0||x.length>0)?(0,P.jsxs)(`section`,{className:`mt-8`,children:[(0,P.jsx)(`h4`,{className:`mb-3 text-sm font-semibold text-fg`,children:t.detailSectionFeatures}),(0,P.jsxs)(`div`,{className:`flex flex-wrap gap-1.5`,children:[(0,P.jsx)(U,{template:t.badgePages,count:y.length,hidden:y.length===0}),(0,P.jsx)(U,{template:t.badgeSettings,count:b.length,hidden:b.length===0}),(0,P.jsx)(U,{template:t.badgeWidgets,count:x.length,hidden:x.length===0}),(0,P.jsx)(U,{template:t.badgeSidebar,count:T.length,hidden:T.length===0})]})]}):null,S(e)&&(A||j)?(0,P.jsxs)(`div`,{className:`mt-6 flex flex-wrap gap-2 border-t border-edge-subtle pt-4`,children:[A?(0,P.jsxs)(M,{to:A,onClick:n,className:a(`inline-flex items-center gap-1.5 rounded-lg border border-edge px-3 py-2 text-sm font-medium text-fg`,`hover:bg-surface-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent`),children:[(0,P.jsx)(u,{className:`size-4 shrink-0 opacity-80`,"aria-hidden":!0}),t.open]}):null,j?(0,P.jsxs)(M,{to:j,onClick:n,className:a(`inline-flex items-center gap-1.5 rounded-lg border border-edge px-3 py-2 text-sm font-medium text-fg`,`hover:bg-surface-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent`),children:[(0,P.jsx)(m,{className:`size-4 shrink-0 opacity-80`,"aria-hidden":!0}),t.openSettings]}):null]}):null,(0,P.jsx)(`p`,{className:`mt-6 text-[11px] leading-relaxed text-fg-muted`,children:t.restartNote})]})]})]})})}function U({template:e,count:t,hidden:n}){return n||t===0?null:(0,P.jsx)(`span`,{className:`inline-flex items-center rounded-md bg-surface-hover px-2 py-0.5 text-[11px] font-medium text-fg-muted`,children:e.replace(/\{\{count\}\}/g,String(t))})}function W(){return(0,P.jsx)(`div`,{className:`flex min-h-0 flex-1 flex-col overflow-y-auto bg-surface-panel`,children:(0,P.jsxs)(`div`,{className:`mx-auto w-full max-w-app-main px-4 py-8`,children:[(0,P.jsx)(`div`,{className:`mb-6 h-8 w-40 max-w-full animate-pulse rounded-md bg-surface-hover`}),(0,P.jsx)(`div`,{className:`mb-2 h-4 w-full max-w-md animate-pulse rounded bg-surface-hover`}),(0,P.jsx)(`div`,{className:`mb-5 h-9 w-full max-w-lg animate-pulse rounded-full bg-surface-hover`}),(0,P.jsx)(`div`,{className:`mt-6 grid gap-4 sm:grid-cols-2 lg:grid-cols-3`,children:[0,1,2,3,4,5].map(e=>(0,P.jsx)(`div`,{className:`h-36 animate-pulse rounded-xl border border-edge bg-surface-base`},e))})]})})}function G({message:e}){return(0,P.jsx)(`div`,{className:`flex min-h-[min(40vh,16rem)] flex-col items-center justify-center rounded-xl border border-dashed border-edge-subtle bg-surface-hover/40 px-4 py-12 text-center dark:bg-surface-hover/20`,children:(0,P.jsx)(`p`,{className:`text-sm text-fg-muted`,children:e})})}export{I as AppsPage};
|
|
2
|
+
//# sourceMappingURL=apps-page-Dh89sZVt.js.map
|
package/dist/gateway/static/root/assets/{apps-page-C8S_3XR3.js.map → apps-page-Dh89sZVt.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apps-page-C8S_3XR3.js","names":[],"sources":["../../../../../web/src/features/extensions/extension-marketplace.tsx","../../../../../web/src/pages/apps-page.tsx"],"sourcesContent":["import { CheckCircle, ExternalLink, Package, Search } from 'lucide-react';\nimport { useEffect, useState } from 'react';\nimport useSWR from 'swr';\n\nimport { useGatewayStore } from '@/stores/gateway-store';\nimport { fetchJson } from '@/lib/fetch';\nimport { apiUrl } from '@/lib/url';\nimport { cn } from '@/lib/cn';\n\ntype RegistryEntry = {\n id: string;\n name: string;\n description?: string;\n npmPackage: string;\n version?: string;\n categories?: string[];\n tags?: string[];\n verified?: boolean;\n homepage?: string;\n author?: string;\n};\n\ntype MarketplaceResponse = { ok: boolean; extensions: RegistryEntry[] };\n\nexport function ExtensionMarketplacePanel({ className }: { className?: string }) {\n const hasToken = useGatewayStore((s) => Boolean(s.token));\n const [q, setQ] = useState('');\n const [debounced, setDebounced] = useState('');\n const key = hasToken ? `marketplace-${debounced}` : null;\n\n useEffect(() => {\n const t = window.setTimeout(() => setDebounced(q.trim()), 300);\n return () => window.clearTimeout(t);\n }, [q]);\n\n const { data, isLoading, error } = useSWR(\n key,\n async () => {\n const url =\n debounced.length > 0\n ? apiUrl(`/api/marketplace?q=${encodeURIComponent(debounced)}`)\n : apiUrl('/api/marketplace');\n return fetchJson<MarketplaceResponse>(url);\n },\n { revalidateOnFocus: false },\n );\n\n const extensions = data?.extensions ?? [];\n\n return (\n <div className={cn('flex flex-col gap-4', className)}>\n <div className=\"relative\">\n <Search\n className=\"pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-fg-muted\"\n strokeWidth={1.75}\n aria-hidden\n />\n <input\n type=\"search\"\n value={q}\n onChange={(e) => setQ(e.target.value)}\n placeholder=\"Search extensions…\"\n className=\"ui-input h-10 w-full rounded-lg border border-edge bg-surface-base pl-9 pr-3 text-sm text-fg placeholder:text-fg-muted\"\n />\n </div>\n\n {error ? (\n <p className=\"text-sm text-fg-muted\">\n {error instanceof Error ? error.message : 'Failed to load marketplace'}\n </p>\n ) : null}\n\n {isLoading && !data ? (\n <p className=\"text-sm text-fg-muted\">Loading…</p>\n ) : (\n <ul className=\"flex flex-col gap-3\">\n {extensions.length === 0 ? (\n <li className=\"text-sm text-fg-muted\">No extensions in registry.</li>\n ) : (\n extensions.map((e) => (\n <li\n key={e.id}\n className=\"rounded-xl border border-edge bg-surface-base p-4 shadow-surface\"\n >\n <div className=\"flex flex-wrap items-start justify-between gap-2\">\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <h3 className=\"font-semibold text-fg\">{e.name}</h3>\n {e.verified ? (\n <CheckCircle\n className=\"size-4 shrink-0 text-emerald-600 dark:text-emerald-400\"\n strokeWidth={1.75}\n aria-label=\"Verified\"\n />\n ) : null}\n {e.version ? (\n <span className=\"text-xs text-fg-muted\">{e.version}</span>\n ) : null}\n </div>\n {e.description ? (\n <p className=\"mt-1 text-sm text-fg-muted\">{e.description}</p>\n ) : null}\n <div className=\"mt-2 flex flex-wrap gap-1.5\">\n {(e.categories ?? []).map((c) => (\n <span\n key={c}\n className=\"rounded-md border border-edge bg-surface-panel px-2 py-0.5 text-[11px] text-fg-muted\"\n >\n {c}\n </span>\n ))}\n </div>\n <p className=\"mt-2 flex items-center gap-1.5 text-xs text-fg-muted\">\n <Package className=\"size-3.5 shrink-0\" strokeWidth={1.75} aria-hidden />\n <code className=\"rounded bg-surface-panel px-1 py-0.5\">{e.npmPackage}</code>\n </p>\n {e.homepage ? (\n <a\n href={e.homepage}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"mt-2 inline-flex items-center gap-1 text-xs text-accent hover:underline\"\n >\n <ExternalLink className=\"size-3.5\" strokeWidth={1.75} aria-hidden />\n Homepage\n </a>\n ) : null}\n </div>\n </div>\n <p className=\"mt-3 text-[11px] text-fg-muted\">\n npm package:{' '}\n <code className=\"rounded bg-surface-panel px-1 py-0.5\">{e.npmPackage}</code>\n </p>\n </li>\n ))\n )}\n </ul>\n )}\n </div>\n );\n}\n","import * as Dialog from '@radix-ui/react-dialog';\nimport {\n ArrowLeft,\n Check,\n ExternalLink,\n Loader2,\n Plus,\n Search,\n Settings,\n X,\n} from 'lucide-react';\nimport { useEffect, useLayoutEffect, useMemo, useState } from 'react';\nimport { Link } from 'react-router-dom';\nimport { useSWRConfig } from 'swr';\n\nimport {\n extensionExposesGatewayShellUi,\n useExtensions,\n useExtensionsLoading,\n} from '@/features/extensions/extension-provider';\nimport { ExtensionMarketplacePanel } from '@/features/extensions/extension-marketplace';\nimport { extensionPagePath } from '@/features/extensions/extension-paths';\nimport type { ExtensionApiRow, PageContribution } from '@/features/extensions/types';\nimport { messages } from '@/i18n/messages';\nimport type { MessageBundle } from '@/i18n/messages';\nimport { cn } from '@/lib/cn';\nimport { fetchJson } from '@/lib/fetch';\nimport { apiUrl } from '@/lib/url';\nimport { usePageHeaderStore } from '@/stores/page-header-store';\nimport { useLocaleStore } from '@/stores/locale-store';\n\ntype AppsPageCopy = MessageBundle['appsPage'];\ntype AppsTab = 'all' | 'ui' | 'backend' | 'marketplace';\n\nexport function AppsPage() {\n const language = useLocaleStore((s) => s.language);\n const m = messages(language);\n const setPageHeader = usePageHeaderStore((s) => s.setPageHeader);\n const clearPageHeader = usePageHeaderStore((s) => s.clearPageHeader);\n const extensions = useExtensions();\n const loading = useExtensionsLoading();\n const { mutate } = useSWRConfig();\n const [tab, setTab] = useState<AppsTab>('all');\n const [search, setSearch] = useState('');\n const [detail, setDetail] = useState<ExtensionApiRow | null>(null);\n\n const filtered = useMemo(() => {\n let list = extensions;\n if (tab === 'ui') list = list.filter((e) => e.hasUi);\n if (tab === 'backend') list = list.filter((e) => !e.hasUi);\n const q = search.trim().toLowerCase();\n if (q) {\n list = list.filter(\n (e) =>\n (e.name ?? '').toLowerCase().includes(q) ||\n e.id.toLowerCase().includes(q) ||\n (e.description ?? '').toLowerCase().includes(q),\n );\n }\n return [...list].sort((a, b) => {\n if (a.hasUi !== b.hasUi) return a.hasUi ? -1 : 1;\n return (a.name || a.id).localeCompare(b.name || b.id, language);\n });\n }, [extensions, tab, search, language]);\n\n /** Keep dialog + cards in sync after SWR refetch (detail was a stale row reference). */\n useEffect(() => {\n setDetail((prev) => {\n if (!prev) return prev;\n const next = extensions.find((e) => e.id === prev.id);\n if (!next) return null;\n const eligPrev = activationEligibleFor(prev);\n const eligNext = activationEligibleFor(next);\n if (eligPrev === eligNext && prev.active === next.active) return prev;\n return next;\n });\n }, [extensions]);\n\n useLayoutEffect(() => {\n setPageHeader({\n startExtra: null,\n main: (\n <div className=\"w-full min-w-0 px-3 sm:px-5 xl:px-6\">\n <h1 className=\"min-w-0 truncate text-base font-semibold tracking-tight text-fg\">{m.appsPage.title}</h1>\n </div>\n ),\n end: null,\n });\n return () => clearPageHeader();\n }, [clearPageHeader, m.appsPage.title, setPageHeader]);\n\n if (loading && tab !== 'marketplace') {\n return <AppsPageSkeleton />;\n }\n\n return (\n <div className=\"flex min-h-0 flex-1 flex-col overflow-y-auto bg-surface-panel\">\n <div className=\"mx-auto w-full max-w-app-main px-4 py-8\">\n <header className=\"mb-6\">\n <h1 className=\"text-xl font-semibold text-fg\">{m.appsPage.title}</h1>\n <p className=\"mt-1 text-sm text-fg-muted\">{m.appsPage.subtitle}</p>\n </header>\n\n <div className=\"mb-5 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"flex flex-wrap gap-2\">\n <TabChip active={tab === 'all'} onClick={() => setTab('all')} label={m.appsPage.tabAll} />\n <TabChip\n active={tab === 'ui'}\n onClick={() => setTab('ui')}\n label={m.appsPage.tabWithUi}\n />\n <TabChip\n active={tab === 'backend'}\n onClick={() => setTab('backend')}\n label={m.appsPage.tabBackend}\n />\n <TabChip\n active={tab === 'marketplace'}\n onClick={() => setTab('marketplace')}\n label={m.appsPage.tabMarketplace}\n />\n </div>\n {tab !== 'marketplace' && extensions.length > 0 ? (\n <div className=\"relative w-full sm:max-w-xs\">\n <Search\n className=\"pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-fg-muted\"\n aria-hidden\n />\n <input\n type=\"search\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n placeholder={m.appsPage.searchPlaceholder}\n className=\"w-full rounded-lg border border-edge bg-surface-base py-2 pl-9 pr-3 text-sm text-fg placeholder:text-fg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent\"\n autoComplete=\"off\"\n />\n </div>\n ) : null}\n </div>\n\n {tab === 'marketplace' ? (\n <ExtensionMarketplacePanel />\n ) : extensions.length === 0 ? (\n <EmptyAppsState message={m.appsPage.empty} />\n ) : filtered.length === 0 ? (\n <p className=\"rounded-xl border border-dashed border-edge-subtle bg-surface-hover/30 px-4 py-8 text-center text-sm text-fg-muted dark:bg-surface-hover/15\">\n {m.appsPage.noSearchResults}\n </p>\n ) : (\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {filtered.map((ext) => (\n <ExtensionAppCard\n key={ext.id}\n extension={ext}\n copy={m.appsPage}\n onOpen={() => setDetail(ext)}\n />\n ))}\n </div>\n )}\n </div>\n\n {detail ? (\n <ExtensionDetailDialog\n key={detail.id}\n extension={detail}\n copy={m.appsPage}\n onClose={() => setDetail(null)}\n onAfterToggle={async () => {\n await mutate('gateway-extensions-list');\n }}\n />\n ) : null}\n </div>\n );\n}\n\nfunction TabChip({\n active,\n onClick,\n label,\n}: {\n active: boolean;\n onClick: () => void;\n label: string;\n}) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n className={cn(\n 'rounded-full border px-3 py-1.5 text-xs font-medium transition-colors',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent',\n active\n ? 'border-accent/40 bg-accent-soft text-accent-fg'\n : 'border-edge bg-surface-base text-fg-muted hover:bg-surface-hover hover:text-fg',\n )}\n >\n {label}\n </button>\n );\n}\n\nfunction activationEligibleFor(ext: ExtensionApiRow): boolean {\n return ext.activationEligible ?? ext.active;\n}\n\nfunction providerLabel(ext: ExtensionApiRow, copy: AppsPageCopy): string {\n if (ext.source === 'bundled') return copy.providerBundled;\n if (ext.source === 'global') return copy.providerGlobal;\n if (ext.source === 'workspace') return copy.providerWorkspace;\n return copy.providerOther;\n}\n\nfunction bundledRunCaption(ext: ExtensionApiRow, copy: AppsPageCopy): string {\n const eligible = activationEligibleFor(ext);\n if (eligible && ext.active) return copy.runStateLive;\n if (eligible && !ext.active) return copy.runStatePendingOn;\n if (!eligible && ext.active) return copy.runStatePendingOff;\n return copy.runStateOff;\n}\n\nfunction ExtensionAppCard({\n extension: ext,\n copy,\n onOpen,\n}: {\n extension: ExtensionApiRow;\n copy: AppsPageCopy;\n onOpen: () => void;\n}) {\n const eligible = activationEligibleFor(ext);\n\n return (\n <button\n type=\"button\"\n onClick={onOpen}\n className={cn(\n 'group flex w-full flex-col rounded-xl border border-edge bg-surface-base p-4 text-left shadow-sm transition-colors',\n 'hover:border-edge-subtle hover:bg-surface-hover/40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent',\n 'dark:hover:bg-surface-hover/25',\n )}\n >\n <div className=\"flex gap-3\">\n <div\n className=\"flex size-12 shrink-0 items-center justify-center rounded-xl bg-accent-soft text-base font-semibold text-accent-fg\"\n aria-hidden\n >\n {(ext.name || ext.id).charAt(0).toUpperCase()}\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"min-w-0\">\n <h2 className=\"truncate text-sm font-semibold text-fg\">{ext.name}</h2>\n {ext.version ? (\n <span className=\"text-[11px] text-fg-muted\">v{ext.version}</span>\n ) : null}\n </div>\n {eligible ? (\n <span className=\"inline-flex shrink-0 items-center gap-1 rounded-full bg-surface-hover px-2 py-0.5 text-[11px] font-medium text-fg-muted\">\n <Check className=\"size-3\" strokeWidth={2.5} aria-hidden />\n {copy.statusEnabled}\n </span>\n ) : (\n <span\n className=\"flex size-8 shrink-0 items-center justify-center rounded-full border-2 border-accent text-accent\"\n aria-hidden\n >\n <Plus className=\"size-4\" strokeWidth={2.5} />\n </span>\n )}\n </div>\n <p className=\"mt-2 line-clamp-2 text-xs leading-relaxed text-fg-muted\">\n {ext.description?.trim() || copy.cardNoDescription}\n </p>\n <div className=\"mt-2 flex flex-wrap gap-1.5\">\n <span className=\"rounded-md bg-surface-hover px-1.5 py-0.5 text-[10px] font-medium uppercase tracking-wide text-fg-muted\">\n {ext.hasUi ? copy.badgeKindUi : copy.badgeKindBackend}\n </span>\n {ext.source === 'bundled' ? (\n <span className=\"rounded-md bg-surface-hover px-1.5 py-0.5 text-[10px] font-medium uppercase tracking-wide text-fg-muted\">\n {copy.badgeBundled}\n </span>\n ) : null}\n </div>\n </div>\n </div>\n </button>\n );\n}\n\nfunction ExtensionDetailDialog({\n extension: ext,\n copy,\n onClose,\n onAfterToggle,\n}: {\n extension: ExtensionApiRow;\n copy: AppsPageCopy;\n onClose: () => void;\n onAfterToggle: () => void | Promise<void>;\n}) {\n const [saving, setSaving] = useState(false);\n const [errorMessage, setErrorMessage] = useState<string | null>(null);\n\n const pages = ext.ui?.contributions?.pages ?? [];\n const settingsPanels = ext.ui?.contributions?.settingsPanels ?? [];\n const chatWidgets = ext.ui?.contributions?.chatWidgets ?? [];\n const sidebarPanels = ext.ui?.contributions?.sidebarPanels ?? [];\n const primaryPage: PageContribution | undefined = pages.find((p) => p.showInNav) ?? pages[0];\n const primarySettingsPanel = settingsPanels[0];\n const openPath = primaryPage ? extensionPagePath(ext.id, primaryPage) : null;\n const settingsPath = primarySettingsPanel\n ? `/settings/ext/${ext.id}/${primarySettingsPanel.id}`\n : ext.hasConfigSchema\n ? `/settings/ext/${ext.id}`\n : null;\n\n const eligible = activationEligibleFor(ext);\n const isBundled = ext.source === 'bundled';\n\n const toggleBundled = async (next: boolean) => {\n setErrorMessage(null);\n setSaving(true);\n try {\n await fetchJson<{ ok: true; payload: { requiresGatewayRestart: boolean } }>(\n apiUrl('/api/extensions/bundled/activation'),\n { method: 'POST', body: JSON.stringify({ extensionId: ext.id, enabled: next }) },\n );\n await onAfterToggle();\n } catch (e) {\n setErrorMessage(e instanceof Error ? e.message : copy.toggleError);\n } finally {\n setSaving(false);\n }\n };\n\n return (\n <Dialog.Root defaultOpen onOpenChange={(o) => !o && onClose()}>\n <Dialog.Portal>\n <Dialog.Overlay className=\"xopc-dialog-overlay fixed inset-0 z-[130] bg-scrim\" />\n <Dialog.Content\n className=\"fixed left-1/2 top-1/2 z-[131] flex max-h-[min(90vh,44rem)] w-[min(42rem,calc(100vw-1.5rem))] -translate-x-1/2 -translate-y-1/2 flex-col overflow-hidden rounded-xl border border-edge bg-surface-panel shadow-elevated\"\n onOpenAutoFocus={(e) => e.preventDefault()}\n >\n <div className=\"flex shrink-0 items-center justify-between gap-2 border-b border-edge px-4 py-3\">\n <button\n type=\"button\"\n onClick={onClose}\n className=\"inline-flex size-9 items-center justify-center rounded-lg text-fg-muted hover:bg-surface-hover hover:text-fg focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent\"\n aria-label={copy.detailBack}\n >\n <ArrowLeft className=\"size-5\" />\n </button>\n <Dialog.Title className=\"min-w-0 flex-1 truncate text-center text-sm font-semibold text-fg\">\n {copy.detailTitle}\n </Dialog.Title>\n <Dialog.Description className=\"sr-only\">\n {ext.name} ({ext.id})\n </Dialog.Description>\n <button\n type=\"button\"\n onClick={onClose}\n className=\"inline-flex size-9 items-center justify-center rounded-lg text-fg-muted hover:bg-surface-hover hover:text-fg focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent\"\n aria-label={copy.detailClose}\n >\n <X className=\"size-5\" />\n </button>\n </div>\n\n <div className=\"min-h-0 flex-1 overflow-y-auto px-5 py-5\">\n <div className=\"flex flex-wrap items-start gap-4\">\n <div\n className=\"flex size-16 shrink-0 items-center justify-center rounded-2xl bg-accent-soft text-xl font-semibold text-accent-fg\"\n aria-hidden\n >\n {(ext.name || ext.id).charAt(0).toUpperCase()}\n </div>\n <div className=\"min-w-0 flex-1\">\n <h3 className=\"text-lg font-semibold text-fg\">{ext.name}</h3>\n <p className=\"mt-0.5 text-sm text-fg-muted\">\n {copy.detailProviderPrefix} {providerLabel(ext, copy)}\n </p>\n {ext.version ? (\n <p className=\"mt-1 text-xs text-fg-muted\">v{ext.version}</p>\n ) : null}\n </div>\n {isBundled ? (\n <div className=\"flex w-full flex-col items-stretch gap-2 sm:w-auto sm:items-end\">\n <button\n type=\"button\"\n disabled={saving}\n aria-busy={saving}\n onClick={() => void toggleBundled(!eligible)}\n className={cn(\n 'relative inline-flex max-w-full rounded-full py-1.5 text-sm font-medium',\n 'transition-[color,background-color,border-color,opacity] duration-200 ease-out',\n 'focus-visible:outline-none focus-visible:ring-2 motion-reduce:transition-none',\n eligible\n ? 'border-2 border-red-500/50 text-red-600 hover:bg-red-500/10 focus-visible:ring-red-500/40 dark:text-red-400'\n : 'border-2 border-transparent bg-accent text-white hover:opacity-90 focus-visible:ring-accent',\n saving && 'cursor-wait opacity-80',\n )}\n >\n <span className=\"block whitespace-nowrap px-4 text-center leading-none\">\n {eligible ? copy.actionDisable : copy.actionEnable}\n </span>\n <Loader2\n className={cn(\n 'pointer-events-none absolute right-2 top-1/2 size-3 -translate-y-1/2 text-current opacity-90',\n saving ? 'animate-spin' : 'invisible',\n )}\n aria-hidden\n />\n </button>\n </div>\n ) : null}\n </div>\n\n <p className=\"mt-5 text-sm leading-relaxed text-fg\">\n {ext.description?.trim() || copy.detailNoDescription}\n </p>\n\n {!ext.hasUi ? (\n <p className=\"mt-3 text-xs text-fg-muted\">{copy.backendOnlyHint}</p>\n ) : null}\n\n <p className=\"mt-2 text-xs text-fg-muted\">{bundledRunCaption(ext, copy)}</p>\n\n {errorMessage ? (\n <p className=\"mt-3 rounded-lg border border-red-500/30 bg-red-500/10 px-3 py-2 text-xs text-fg\" role=\"alert\">\n {errorMessage}\n </p>\n ) : null}\n\n {!isBundled ? (\n <p className=\"mt-4 rounded-lg border border-edge-subtle bg-surface-hover/40 px-3 py-2 text-xs text-fg-muted dark:bg-surface-hover/20\">\n {copy.cliManageHint}\n </p>\n ) : null}\n\n {ext.hasUi && (pages.length > 0 || settingsPanels.length > 0 || chatWidgets.length > 0) ? (\n <section className=\"mt-8\">\n <h4 className=\"mb-3 text-sm font-semibold text-fg\">{copy.detailSectionFeatures}</h4>\n <div className=\"flex flex-wrap gap-1.5\">\n <ContributionBadge\n template={copy.badgePages}\n count={pages.length}\n hidden={pages.length === 0}\n />\n <ContributionBadge\n template={copy.badgeSettings}\n count={settingsPanels.length}\n hidden={settingsPanels.length === 0}\n />\n <ContributionBadge\n template={copy.badgeWidgets}\n count={chatWidgets.length}\n hidden={chatWidgets.length === 0}\n />\n <ContributionBadge\n template={copy.badgeSidebar}\n count={sidebarPanels.length}\n hidden={sidebarPanels.length === 0}\n />\n </div>\n </section>\n ) : null}\n\n {extensionExposesGatewayShellUi(ext) && (openPath || settingsPath) ? (\n <div className=\"mt-6 flex flex-wrap gap-2 border-t border-edge-subtle pt-4\">\n {openPath ? (\n <Link\n to={openPath}\n onClick={onClose}\n className={cn(\n 'inline-flex items-center gap-1.5 rounded-lg border border-edge px-3 py-2 text-sm font-medium text-fg',\n 'hover:bg-surface-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent',\n )}\n >\n <ExternalLink className=\"size-4 shrink-0 opacity-80\" aria-hidden />\n {copy.open}\n </Link>\n ) : null}\n {settingsPath ? (\n <Link\n to={settingsPath}\n onClick={onClose}\n className={cn(\n 'inline-flex items-center gap-1.5 rounded-lg border border-edge px-3 py-2 text-sm font-medium text-fg',\n 'hover:bg-surface-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent',\n )}\n >\n <Settings className=\"size-4 shrink-0 opacity-80\" aria-hidden />\n {copy.openSettings}\n </Link>\n ) : null}\n </div>\n ) : null}\n\n <p className=\"mt-6 text-[11px] leading-relaxed text-fg-muted\">{copy.restartNote}</p>\n </div>\n </Dialog.Content>\n </Dialog.Portal>\n </Dialog.Root>\n );\n}\n\nfunction ContributionBadge({\n template,\n count,\n hidden,\n}: {\n template: string;\n count: number;\n hidden: boolean;\n}) {\n if (hidden || count === 0) return null;\n return (\n <span className=\"inline-flex items-center rounded-md bg-surface-hover px-2 py-0.5 text-[11px] font-medium text-fg-muted\">\n {template.replace(/\\{\\{count\\}\\}/g, String(count))}\n </span>\n );\n}\n\nfunction AppsPageSkeleton() {\n return (\n <div className=\"flex min-h-0 flex-1 flex-col overflow-y-auto bg-surface-panel\">\n <div className=\"mx-auto w-full max-w-app-main px-4 py-8\">\n <div className=\"mb-6 h-8 w-40 max-w-full animate-pulse rounded-md bg-surface-hover\" />\n <div className=\"mb-2 h-4 w-full max-w-md animate-pulse rounded bg-surface-hover\" />\n <div className=\"mb-5 h-9 w-full max-w-lg animate-pulse rounded-full bg-surface-hover\" />\n <div className=\"mt-6 grid gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {[0, 1, 2, 3, 4, 5].map((i) => (\n <div key={i} className=\"h-36 animate-pulse rounded-xl border border-edge bg-surface-base\" />\n ))}\n </div>\n </div>\n </div>\n );\n}\n\nfunction EmptyAppsState({ message }: { message: string }) {\n return (\n <div className=\"flex min-h-[min(40vh,16rem)] flex-col items-center justify-center rounded-xl border border-dashed border-edge-subtle bg-surface-hover/40 px-4 py-12 text-center dark:bg-surface-hover/20\">\n <p className=\"text-sm text-fg-muted\">{message}</p>\n </div>\n );\n}\n"],"mappings":"2cAwBA,SAAgB,EAA0B,CAAE,aAAqC,CAC/E,IAAM,EAAW,EAAiB,GAAM,EAAQ,EAAE,MAAO,CACnD,CAAC,EAAG,IAAA,EAAA,EAAA,UAAiB,GAAG,CACxB,CAAC,EAAW,IAAA,EAAA,EAAA,UAAyB,GAAG,CACxC,EAAM,EAAW,eAAe,IAAc,MAEpD,EAAA,EAAA,eAAgB,CACd,IAAM,EAAI,OAAO,eAAiB,EAAa,EAAE,MAAM,CAAC,CAAE,IAAI,CAC9D,UAAa,OAAO,aAAa,EAAE,EAClC,CAAC,EAAE,CAAC,CAEP,GAAM,CAAE,OAAM,YAAW,SAAU,EACjC,EACA,SAKS,EAHL,EAAU,OAAS,EACf,EAAO,sBAAsB,mBAAmB,EAAU,GAAG,CAC7D,EAAO,mBAAmB,CACU,CAE5C,CAAE,kBAAmB,GAAO,CAC7B,CAEK,EAAa,GAAM,YAAc,EAAE,CAEzC,OACE,EAAA,EAAA,MAAC,MAAD,CAAK,UAAW,EAAG,sBAAuB,EAAU,UAApD,EACE,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,oBAAf,EACE,EAAA,EAAA,KAAC,EAAD,CACE,UAAU,oFACV,YAAa,KACb,cAAA,GACA,CAAA,EACF,EAAA,EAAA,KAAC,QAAD,CACE,KAAK,SACL,MAAO,EACP,SAAW,GAAM,EAAK,EAAE,OAAO,MAAM,CACrC,YAAY,qBACZ,UAAU,yHACV,CAAA,CACE,GAEL,GACC,EAAA,EAAA,KAAC,IAAD,CAAG,UAAU,iCACV,aAAiB,MAAQ,EAAM,QAAU,6BACxC,CAAA,CACF,KAEH,GAAa,CAAC,GACb,EAAA,EAAA,KAAC,IAAD,CAAG,UAAU,iCAAwB,WAAY,CAAA,EAEjD,EAAA,EAAA,KAAC,KAAD,CAAI,UAAU,+BACX,EAAW,SAAW,GACrB,EAAA,EAAA,KAAC,KAAD,CAAI,UAAU,iCAAwB,6BAA+B,CAAA,CAErE,EAAW,IAAK,IACd,EAAA,EAAA,MAAC,KAAD,CAEE,UAAU,4EAFZ,EAIE,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,6DACb,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,0BAAf,EACE,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,6CAAf,EACE,EAAA,EAAA,KAAC,KAAD,CAAI,UAAU,iCAAyB,EAAE,KAAU,CAAA,CAClD,EAAE,UACD,EAAA,EAAA,KAAC,EAAD,CACE,UAAU,yDACV,YAAa,KACb,aAAW,WACX,CAAA,CACA,KACH,EAAE,SACD,EAAA,EAAA,KAAC,OAAD,CAAM,UAAU,iCAAyB,EAAE,QAAe,CAAA,CACxD,KACA,GACL,EAAE,aACD,EAAA,EAAA,KAAC,IAAD,CAAG,UAAU,sCAA8B,EAAE,YAAgB,CAAA,CAC3D,MACJ,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,wCACX,EAAE,YAAc,EAAE,EAAE,IAAK,IACzB,EAAA,EAAA,KAAC,OAAD,CAEE,UAAU,gGAET,EACI,CAJA,EAIA,CACP,CACE,CAAA,EACN,EAAA,EAAA,MAAC,IAAD,CAAG,UAAU,gEAAb,EACE,EAAA,EAAA,KAAC,EAAD,CAAS,UAAU,oBAAoB,YAAa,KAAM,cAAA,GAAc,CAAA,EACxE,EAAA,EAAA,KAAC,OAAD,CAAM,UAAU,gDAAwC,EAAE,WAAkB,CAAA,CAC1E,GACH,EAAE,UACD,EAAA,EAAA,MAAC,IAAD,CACE,KAAM,EAAE,SACR,OAAO,SACP,IAAI,aACJ,UAAU,mFAJZ,EAME,EAAA,EAAA,KAAC,EAAD,CAAc,UAAU,WAAW,YAAa,KAAM,cAAA,GAAc,CAAA,CAAA,WAElE,GACF,KACA,GACF,CAAA,EACN,EAAA,EAAA,MAAC,IAAD,CAAG,UAAU,0CAAb,CAA8C,eAC/B,KACb,EAAA,EAAA,KAAC,OAAD,CAAM,UAAU,gDAAwC,EAAE,WAAkB,CAAA,CAC1E,GACD,EApDE,EAAE,GAoDJ,CACL,CAED,CAAA,CAEH,GCxGV,SAAgB,GAAW,CACzB,IAAM,EAAW,EAAgB,GAAM,EAAE,SAAS,CAC5C,EAAI,EAAS,EAAS,CACtB,EAAgB,EAAoB,GAAM,EAAE,cAAc,CAC1D,EAAkB,EAAoB,GAAM,EAAE,gBAAgB,CAC9D,EAAa,GAAe,CAC5B,EAAU,GAAsB,CAChC,CAAE,UAAW,GAAc,CAC3B,CAAC,EAAK,IAAA,EAAA,EAAA,UAA4B,MAAM,CACxC,CAAC,EAAQ,IAAA,EAAA,EAAA,UAAsB,GAAG,CAClC,CAAC,EAAQ,IAAA,EAAA,EAAA,UAA8C,KAAK,CAE5D,GAAA,EAAA,EAAA,aAAyB,CAC7B,IAAI,EAAO,EACP,IAAQ,OAAM,EAAO,EAAK,OAAQ,GAAM,EAAE,MAAM,EAChD,IAAQ,YAAW,EAAO,EAAK,OAAQ,GAAM,CAAC,EAAE,MAAM,EAC1D,IAAM,EAAI,EAAO,MAAM,CAAC,aAAa,CASrC,OARI,IACF,EAAO,EAAK,OACT,IACE,EAAE,MAAQ,IAAI,aAAa,CAAC,SAAS,EAAE,EACxC,EAAE,GAAG,aAAa,CAAC,SAAS,EAAE,GAC7B,EAAE,aAAe,IAAI,aAAa,CAAC,SAAS,EAAE,CAClD,EAEI,CAAC,GAAG,EAAK,CAAC,MAAM,EAAG,IACpB,EAAE,QAAU,EAAE,OACV,EAAE,MAAQ,EAAE,IAAI,cAAc,EAAE,MAAQ,EAAE,GAAI,EAAS,CAD/B,EAAE,MAAQ,GAAK,EAE/C,EACD,CAAC,EAAY,EAAK,EAAQ,EAAS,CAAC,CAgCvC,OA7BA,EAAA,EAAA,eAAgB,CACd,EAAW,GAAS,CAClB,GAAI,CAAC,EAAM,OAAO,EAClB,IAAM,EAAO,EAAW,KAAM,GAAM,EAAE,KAAO,EAAK,GAAG,CAKrD,OAJK,EACY,EAAsB,EAEnC,GADa,EAAsB,EACtB,EAAY,EAAK,SAAW,EAAK,OAAe,EAC1D,EAJW,MAKlB,EACD,CAAC,EAAW,CAAC,EAEhB,EAAA,EAAA,sBACE,EAAc,CACZ,WAAY,KACZ,MACE,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,gDACb,EAAA,EAAA,KAAC,KAAD,CAAI,UAAU,2EAAmE,EAAE,SAAS,MAAW,CAAA,CACnG,CAAA,CAER,IAAK,KACN,CAAC,KACW,GAAiB,EAC7B,CAAC,EAAiB,EAAE,SAAS,MAAO,EAAc,CAAC,CAElD,GAAW,IAAQ,eACd,EAAA,EAAA,KAAC,EAAD,EAAoB,CAAA,EAI3B,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,yEAAf,EACE,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,mDAAf,EACE,EAAA,EAAA,MAAC,SAAD,CAAQ,UAAU,gBAAlB,EACE,EAAA,EAAA,KAAC,KAAD,CAAI,UAAU,yCAAiC,EAAE,SAAS,MAAW,CAAA,EACrE,EAAA,EAAA,KAAC,IAAD,CAAG,UAAU,sCAA8B,EAAE,SAAS,SAAa,CAAA,CAC5D,IAET,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,mFAAf,EACE,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,gCAAf,EACE,EAAA,EAAA,KAAC,EAAD,CAAS,OAAQ,IAAQ,MAAO,YAAe,EAAO,MAAM,CAAE,MAAO,EAAE,SAAS,OAAU,CAAA,EAC1F,EAAA,EAAA,KAAC,EAAD,CACE,OAAQ,IAAQ,KAChB,YAAe,EAAO,KAAK,CAC3B,MAAO,EAAE,SAAS,UAClB,CAAA,EACF,EAAA,EAAA,KAAC,EAAD,CACE,OAAQ,IAAQ,UAChB,YAAe,EAAO,UAAU,CAChC,MAAO,EAAE,SAAS,WAClB,CAAA,EACF,EAAA,EAAA,KAAC,EAAD,CACE,OAAQ,IAAQ,cAChB,YAAe,EAAO,cAAc,CACpC,MAAO,EAAE,SAAS,eAClB,CAAA,CACE,GACL,IAAQ,eAAiB,EAAW,OAAS,GAC5C,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,uCAAf,EACE,EAAA,EAAA,KAAC,EAAD,CACE,UAAU,oFACV,cAAA,GACA,CAAA,EACF,EAAA,EAAA,KAAC,QAAD,CACE,KAAK,SACL,MAAO,EACP,SAAW,GAAM,EAAU,EAAE,OAAO,MAAM,CAC1C,YAAa,EAAE,SAAS,kBACxB,UAAU,0LACV,aAAa,MACb,CAAA,CACE,GACJ,KACA,GAEL,IAAQ,eACP,EAAA,EAAA,KAAC,EAAD,EAA6B,CAAA,CAC3B,EAAW,SAAW,GACxB,EAAA,EAAA,KAAC,EAAD,CAAgB,QAAS,EAAE,SAAS,MAAS,CAAA,CAC3C,EAAS,SAAW,GACtB,EAAA,EAAA,KAAC,IAAD,CAAG,UAAU,uJACV,EAAE,SAAS,gBACV,CAAA,EAEJ,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,oDACZ,EAAS,IAAK,IACb,EAAA,EAAA,KAAC,EAAD,CAEE,UAAW,EACX,KAAM,EAAE,SACR,WAAc,EAAU,EAAI,CAC5B,CAJK,EAAI,GAIT,CACF,CACE,CAAA,CAEJ,GAEL,GACC,EAAA,EAAA,KAAC,EAAD,CAEE,UAAW,EACX,KAAM,EAAE,SACR,YAAe,EAAU,KAAK,CAC9B,cAAe,SAAY,CACzB,MAAM,EAAO,0BAA0B,EAEzC,CAPK,EAAO,GAOZ,CACA,KACA,GAIV,SAAS,EAAQ,CACf,SACA,UACA,SAKC,CACD,OACE,EAAA,EAAA,KAAC,SAAD,CACE,KAAK,SACI,UACT,UAAW,EACT,wEACA,4EACA,EACI,iDACA,iFACL,UAEA,EACM,CAAA,CAIb,SAAS,EAAsB,EAA+B,CAC5D,OAAO,EAAI,oBAAsB,EAAI,OAGvC,SAAS,EAAc,EAAsB,EAA4B,CAIvE,OAHI,EAAI,SAAW,UAAkB,EAAK,gBACtC,EAAI,SAAW,SAAiB,EAAK,eACrC,EAAI,SAAW,YAAoB,EAAK,kBACrC,EAAK,cAGd,SAAS,EAAkB,EAAsB,EAA4B,CAC3E,IAAM,EAAW,EAAsB,EAAI,CAI3C,OAHI,GAAY,EAAI,OAAe,EAAK,aACpC,GAAY,CAAC,EAAI,OAAe,EAAK,kBACrC,CAAC,GAAY,EAAI,OAAe,EAAK,mBAClC,EAAK,YAGd,SAAS,EAAiB,CACxB,UAAW,EACX,OACA,UAKC,CACD,IAAM,EAAW,EAAsB,EAAI,CAE3C,OACE,EAAA,EAAA,KAAC,SAAD,CACE,KAAK,SACL,QAAS,EACT,UAAW,EACT,qHACA,+HACA,iCACD,WAED,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,sBAAf,EACE,EAAA,EAAA,KAAC,MAAD,CACE,UAAU,qHACV,cAAA,aAEE,EAAI,MAAQ,EAAI,IAAI,OAAO,EAAE,CAAC,aAAa,CACzC,CAAA,EACN,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,0BAAf,EACE,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,kDAAf,EACE,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,mBAAf,EACE,EAAA,EAAA,KAAC,KAAD,CAAI,UAAU,kDAA0C,EAAI,KAAU,CAAA,CACrE,EAAI,SACH,EAAA,EAAA,MAAC,OAAD,CAAM,UAAU,qCAAhB,CAA4C,IAAE,EAAI,QAAe,GAC/D,KACA,GACL,GACC,EAAA,EAAA,MAAC,OAAD,CAAM,UAAU,mIAAhB,EACE,EAAA,EAAA,KAAC,EAAD,CAAO,UAAU,SAAS,YAAa,IAAK,cAAA,GAAc,CAAA,CACzD,EAAK,cACD,IAEP,EAAA,EAAA,KAAC,OAAD,CACE,UAAU,mGACV,cAAA,aAEA,EAAA,EAAA,KAAC,EAAD,CAAM,UAAU,SAAS,YAAa,IAAO,CAAA,CACxC,CAAA,CAEL,IACN,EAAA,EAAA,KAAC,IAAD,CAAG,UAAU,mEACV,EAAI,aAAa,MAAM,EAAI,EAAK,kBAC/B,CAAA,EACJ,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,uCAAf,EACE,EAAA,EAAA,KAAC,OAAD,CAAM,UAAU,mHACb,EAAI,MAAQ,EAAK,YAAc,EAAK,iBAChC,CAAA,CACN,EAAI,SAAW,WACd,EAAA,EAAA,KAAC,OAAD,CAAM,UAAU,mHACb,EAAK,aACD,CAAA,CACL,KACA,GACF,GACF,GACC,CAAA,CAIb,SAAS,EAAsB,CAC7B,UAAW,EACX,OACA,UACA,iBAMC,CACD,GAAM,CAAC,EAAQ,IAAA,EAAA,EAAA,UAAsB,GAAM,CACrC,CAAC,EAAc,IAAA,EAAA,EAAA,UAA2C,KAAK,CAE/D,EAAQ,EAAI,IAAI,eAAe,OAAS,EAAE,CAC1C,EAAiB,EAAI,IAAI,eAAe,gBAAkB,EAAE,CAC5D,EAAc,EAAI,IAAI,eAAe,aAAe,EAAE,CACtD,EAAgB,EAAI,IAAI,eAAe,eAAiB,EAAE,CAC1D,EAA4C,EAAM,KAAM,GAAM,EAAE,UAAU,EAAI,EAAM,GACpF,EAAuB,EAAe,GACtC,EAAW,EAAc,EAAkB,EAAI,GAAI,EAAY,CAAG,KAClE,EAAe,EACjB,iBAAiB,EAAI,GAAG,GAAG,EAAqB,KAChD,EAAI,gBACF,iBAAiB,EAAI,KACrB,KAEA,EAAW,EAAsB,EAAI,CACrC,EAAY,EAAI,SAAW,UAE3B,EAAgB,KAAO,IAAkB,CAC7C,EAAgB,KAAK,CACrB,EAAU,GAAK,CACf,GAAI,CACF,MAAM,EACJ,EAAO,qCAAqC,CAC5C,CAAE,OAAQ,OAAQ,KAAM,KAAK,UAAU,CAAE,YAAa,EAAI,GAAI,QAAS,EAAM,CAAC,CAAE,CACjF,CACD,MAAM,GAAe,OACd,EAAG,CACV,EAAgB,aAAa,MAAQ,EAAE,QAAU,EAAK,YAAY,QAC1D,CACR,EAAU,GAAM,GAIpB,OACE,EAAA,EAAA,KAAC,EAAD,CAAa,YAAA,GAAY,aAAe,GAAM,CAAC,GAAK,GAAS,WAC3D,EAAA,EAAA,MAAC,EAAD,CAAA,SAAA,EACE,EAAA,EAAA,KAAC,EAAD,CAAgB,UAAU,qDAAuD,CAAA,EACjF,EAAA,EAAA,MAAC,EAAD,CACE,UAAU,0NACV,gBAAkB,GAAM,EAAE,gBAAgB,UAF5C,EAIE,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,2FAAf,EACE,EAAA,EAAA,KAAC,SAAD,CACE,KAAK,SACL,QAAS,EACT,UAAU,yLACV,aAAY,EAAK,qBAEjB,EAAA,EAAA,KAAC,EAAD,CAAW,UAAU,SAAW,CAAA,CACzB,CAAA,EACT,EAAA,EAAA,KAAC,EAAD,CAAc,UAAU,6EACrB,EAAK,YACO,CAAA,EACf,EAAA,EAAA,MAAC,EAAD,CAAoB,UAAU,mBAA9B,CACG,EAAI,KAAK,KAAG,EAAI,GAAG,IACD,IACrB,EAAA,EAAA,KAAC,SAAD,CACE,KAAK,SACL,QAAS,EACT,UAAU,yLACV,aAAY,EAAK,sBAEjB,EAAA,EAAA,KAAC,EAAD,CAAG,UAAU,SAAW,CAAA,CACjB,CAAA,CACL,IAEN,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,oDAAf,EACE,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,4CAAf,EACE,EAAA,EAAA,KAAC,MAAD,CACE,UAAU,oHACV,cAAA,aAEE,EAAI,MAAQ,EAAI,IAAI,OAAO,EAAE,CAAC,aAAa,CACzC,CAAA,EACN,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,0BAAf,EACE,EAAA,EAAA,KAAC,KAAD,CAAI,UAAU,yCAAiC,EAAI,KAAU,CAAA,EAC7D,EAAA,EAAA,MAAC,IAAD,CAAG,UAAU,wCAAb,CACG,EAAK,qBAAqB,IAAE,EAAc,EAAK,EAAK,CACnD,GACH,EAAI,SACH,EAAA,EAAA,MAAC,IAAD,CAAG,UAAU,sCAAb,CAA0C,IAAE,EAAI,QAAY,GAC1D,KACA,GACL,GACC,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,4EACb,EAAA,EAAA,MAAC,SAAD,CACE,KAAK,SACL,SAAU,EACV,YAAW,EACX,YAAe,KAAK,EAAc,CAAC,EAAS,CAC5C,UAAW,EACT,0EACA,iFACA,gFACA,EACI,8GACA,8FACJ,GAAU,yBACX,UAbH,EAeE,EAAA,EAAA,KAAC,OAAD,CAAM,UAAU,iEACb,EAAW,EAAK,cAAgB,EAAK,aACjC,CAAA,EACP,EAAA,EAAA,KAAC,EAAD,CACE,UAAW,EACT,+FACA,EAAS,eAAiB,YAC3B,CACD,cAAA,GACA,CAAA,CACK,GACL,CAAA,CACJ,KACA,IAEN,EAAA,EAAA,KAAC,IAAD,CAAG,UAAU,gDACV,EAAI,aAAa,MAAM,EAAI,EAAK,oBAC/B,CAAA,CAEF,EAAI,MAEF,MADF,EAAA,EAAA,KAAC,IAAD,CAAG,UAAU,sCAA8B,EAAK,gBAAoB,CAAA,EAGtE,EAAA,EAAA,KAAC,IAAD,CAAG,UAAU,sCAA8B,EAAkB,EAAK,EAAK,CAAK,CAAA,CAE3E,GACC,EAAA,EAAA,KAAC,IAAD,CAAG,UAAU,mFAAmF,KAAK,iBAClG,EACC,CAAA,CACF,KAEF,EAIE,MAHF,EAAA,EAAA,KAAC,IAAD,CAAG,UAAU,kIACV,EAAK,cACJ,CAAA,CAGL,EAAI,QAAU,EAAM,OAAS,GAAK,EAAe,OAAS,GAAK,EAAY,OAAS,IACnF,EAAA,EAAA,MAAC,UAAD,CAAS,UAAU,gBAAnB,EACE,EAAA,EAAA,KAAC,KAAD,CAAI,UAAU,8CAAsC,EAAK,sBAA2B,CAAA,EACpF,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,kCAAf,EACE,EAAA,EAAA,KAAC,EAAD,CACE,SAAU,EAAK,WACf,MAAO,EAAM,OACb,OAAQ,EAAM,SAAW,EACzB,CAAA,EACF,EAAA,EAAA,KAAC,EAAD,CACE,SAAU,EAAK,cACf,MAAO,EAAe,OACtB,OAAQ,EAAe,SAAW,EAClC,CAAA,EACF,EAAA,EAAA,KAAC,EAAD,CACE,SAAU,EAAK,aACf,MAAO,EAAY,OACnB,OAAQ,EAAY,SAAW,EAC/B,CAAA,EACF,EAAA,EAAA,KAAC,EAAD,CACE,SAAU,EAAK,aACf,MAAO,EAAc,OACrB,OAAQ,EAAc,SAAW,EACjC,CAAA,CACE,GACE,GACR,KAEH,EAA+B,EAAI,GAAK,GAAY,IACnD,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,sEAAf,CACG,GACC,EAAA,EAAA,MAAC,EAAD,CACE,GAAI,EACJ,QAAS,EACT,UAAW,EACT,uGACA,mGACD,UANH,EAQE,EAAA,EAAA,KAAC,EAAD,CAAc,UAAU,6BAA6B,cAAA,GAAc,CAAA,CAClE,EAAK,KACD,GACL,KACH,GACC,EAAA,EAAA,MAAC,EAAD,CACE,GAAI,EACJ,QAAS,EACT,UAAW,EACT,uGACA,mGACD,UANH,EAQE,EAAA,EAAA,KAAC,EAAD,CAAU,UAAU,6BAA6B,cAAA,GAAc,CAAA,CAC9D,EAAK,aACD,GACL,KACA,GACJ,MAEJ,EAAA,EAAA,KAAC,IAAD,CAAG,UAAU,0DAAkD,EAAK,YAAgB,CAAA,CAChF,GACS,GACH,CAAA,CAAA,CACJ,CAAA,CAIlB,SAAS,EAAkB,CACzB,WACA,QACA,UAKC,CAED,OADI,GAAU,IAAU,EAAU,MAEhC,EAAA,EAAA,KAAC,OAAD,CAAM,UAAU,kHACb,EAAS,QAAQ,iBAAkB,OAAO,EAAM,CAAC,CAC7C,CAAA,CAIX,SAAS,GAAmB,CAC1B,OACE,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,0EACb,EAAA,EAAA,MAAC,MAAD,CAAK,UAAU,mDAAf,EACE,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,qEAAuE,CAAA,EACtF,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,kEAAoE,CAAA,EACnF,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,uEAAyE,CAAA,EACxF,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,yDACZ,CAAC,EAAG,EAAG,EAAG,EAAG,EAAG,EAAE,CAAC,IAAK,IACvB,EAAA,EAAA,KAAC,MAAD,CAAa,UAAU,mEAAqE,CAAlF,EAAkF,CAC5F,CACE,CAAA,CACF,GACF,CAAA,CAIV,SAAS,EAAe,CAAE,WAAgC,CACxD,OACE,EAAA,EAAA,KAAC,MAAD,CAAK,UAAU,qMACb,EAAA,EAAA,KAAC,IAAD,CAAG,UAAU,iCAAyB,EAAY,CAAA,CAC9C,CAAA"}
|
|
1
|
+
{"version":3,"file":"apps-page-Dh89sZVt.js","names":[],"sources":["../../../../../web/src/features/extensions/extension-marketplace.tsx","../../../../../web/src/pages/apps-page.tsx"],"sourcesContent":["import { CheckCircle, ExternalLink, Package, Search } from 'lucide-react';\nimport { useEffect, useState } from 'react';\nimport useSWR from 'swr';\n\nimport { useGatewayStore } from '@/stores/gateway-store';\nimport { fetchJson } from '@/lib/fetch';\nimport { apiUrl } from '@/lib/url';\nimport { cn } from '@/lib/cn';\n\ntype RegistryEntry = {\n id: string;\n name: string;\n description?: string;\n npmPackage: string;\n version?: string;\n categories?: string[];\n tags?: string[];\n verified?: boolean;\n homepage?: string;\n author?: string;\n};\n\ntype MarketplaceResponse = { ok: boolean; extensions: RegistryEntry[] };\n\nexport function ExtensionMarketplacePanel({ className }: { className?: string }) {\n const hasToken = useGatewayStore((s) => Boolean(s.token));\n const [q, setQ] = useState('');\n const [debounced, setDebounced] = useState('');\n const key = hasToken ? `marketplace-${debounced}` : null;\n\n useEffect(() => {\n const t = window.setTimeout(() => setDebounced(q.trim()), 300);\n return () => window.clearTimeout(t);\n }, [q]);\n\n const { data, isLoading, error } = useSWR(\n key,\n async () => {\n const url =\n debounced.length > 0\n ? apiUrl(`/api/marketplace?q=${encodeURIComponent(debounced)}`)\n : apiUrl('/api/marketplace');\n return fetchJson<MarketplaceResponse>(url);\n },\n { revalidateOnFocus: false },\n );\n\n const extensions = data?.extensions ?? [];\n\n return (\n <div className={cn('flex flex-col gap-4', className)}>\n <div className=\"relative\">\n <Search\n className=\"pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-fg-muted\"\n strokeWidth={1.75}\n aria-hidden\n />\n <input\n type=\"search\"\n value={q}\n onChange={(e) => setQ(e.target.value)}\n placeholder=\"Search extensions…\"\n className=\"ui-input h-10 w-full rounded-lg border border-edge bg-surface-base pl-9 pr-3 text-sm text-fg placeholder:text-fg-muted\"\n />\n </div>\n\n {error ? (\n <p className=\"text-sm text-fg-muted\">\n {error instanceof Error ? error.message : 'Failed to load marketplace'}\n </p>\n ) : null}\n\n {isLoading && !data ? (\n <p className=\"text-sm text-fg-muted\">Loading…</p>\n ) : (\n <ul className=\"flex flex-col gap-3\">\n {extensions.length === 0 ? (\n <li className=\"text-sm text-fg-muted\">No extensions in registry.</li>\n ) : (\n extensions.map((e) => (\n <li\n key={e.id}\n className=\"rounded-xl border border-edge bg-surface-base p-4 shadow-surface\"\n >\n <div className=\"flex flex-wrap items-start justify-between gap-2\">\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <h3 className=\"font-semibold text-fg\">{e.name}</h3>\n {e.verified ? (\n <CheckCircle\n className=\"size-4 shrink-0 text-emerald-600 dark:text-emerald-400\"\n strokeWidth={1.75}\n aria-label=\"Verified\"\n />\n ) : null}\n {e.version ? (\n <span className=\"text-xs text-fg-muted\">{e.version}</span>\n ) : null}\n </div>\n {e.description ? (\n <p className=\"mt-1 text-sm text-fg-muted\">{e.description}</p>\n ) : null}\n <div className=\"mt-2 flex flex-wrap gap-1.5\">\n {(e.categories ?? []).map((c) => (\n <span\n key={c}\n className=\"rounded-md border border-edge bg-surface-panel px-2 py-0.5 text-[11px] text-fg-muted\"\n >\n {c}\n </span>\n ))}\n </div>\n <p className=\"mt-2 flex items-center gap-1.5 text-xs text-fg-muted\">\n <Package className=\"size-3.5 shrink-0\" strokeWidth={1.75} aria-hidden />\n <code className=\"rounded bg-surface-panel px-1 py-0.5\">{e.npmPackage}</code>\n </p>\n {e.homepage ? (\n <a\n href={e.homepage}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"mt-2 inline-flex items-center gap-1 text-xs text-accent hover:underline\"\n >\n <ExternalLink className=\"size-3.5\" strokeWidth={1.75} aria-hidden />\n Homepage\n </a>\n ) : null}\n </div>\n </div>\n <p className=\"mt-3 text-[11px] text-fg-muted\">\n npm package:{' '}\n <code className=\"rounded bg-surface-panel px-1 py-0.5\">{e.npmPackage}</code>\n </p>\n </li>\n ))\n )}\n </ul>\n )}\n </div>\n );\n}\n","import * as Dialog from '@radix-ui/react-dialog';\nimport {\n ArrowLeft,\n Check,\n ExternalLink,\n Loader2,\n Plus,\n Search,\n Settings,\n X,\n} from 'lucide-react';\nimport { useEffect, useLayoutEffect, useMemo, useState } from 'react';\nimport { Link } from 'react-router-dom';\nimport { useSWRConfig } from 'swr';\n\nimport {\n extensionExposesGatewayShellUi,\n useExtensions,\n useExtensionsLoading,\n} from '@/features/extensions/extension-provider';\nimport { ExtensionMarketplacePanel } from '@/features/extensions/extension-marketplace';\nimport { extensionPagePath } from '@/features/extensions/extension-paths';\nimport type { ExtensionApiRow, PageContribution } from '@/features/extensions/types';\nimport { messages } from '@/i18n/messages';\nimport type { MessageBundle } from '@/i18n/messages';\nimport { cn } from '@/lib/cn';\nimport { fetchJson } from '@/lib/fetch';\nimport { apiUrl } from '@/lib/url';\nimport { usePageHeaderStore } from '@/stores/page-header-store';\nimport { useLocaleStore } from '@/stores/locale-store';\n\ntype AppsPageCopy = MessageBundle['appsPage'];\ntype AppsTab = 'all' | 'ui' | 'backend' | 'marketplace';\n\nexport function AppsPage() {\n const language = useLocaleStore((s) => s.language);\n const m = messages(language);\n const setPageHeader = usePageHeaderStore((s) => s.setPageHeader);\n const clearPageHeader = usePageHeaderStore((s) => s.clearPageHeader);\n const extensions = useExtensions();\n const loading = useExtensionsLoading();\n const { mutate } = useSWRConfig();\n const [tab, setTab] = useState<AppsTab>('all');\n const [search, setSearch] = useState('');\n const [detail, setDetail] = useState<ExtensionApiRow | null>(null);\n\n const filtered = useMemo(() => {\n let list = extensions;\n if (tab === 'ui') list = list.filter((e) => e.hasUi);\n if (tab === 'backend') list = list.filter((e) => !e.hasUi);\n const q = search.trim().toLowerCase();\n if (q) {\n list = list.filter(\n (e) =>\n (e.name ?? '').toLowerCase().includes(q) ||\n e.id.toLowerCase().includes(q) ||\n (e.description ?? '').toLowerCase().includes(q),\n );\n }\n return [...list].sort((a, b) => {\n if (a.hasUi !== b.hasUi) return a.hasUi ? -1 : 1;\n return (a.name || a.id).localeCompare(b.name || b.id, language);\n });\n }, [extensions, tab, search, language]);\n\n /** Keep dialog + cards in sync after SWR refetch (detail was a stale row reference). */\n useEffect(() => {\n setDetail((prev) => {\n if (!prev) return prev;\n const next = extensions.find((e) => e.id === prev.id);\n if (!next) return null;\n const eligPrev = activationEligibleFor(prev);\n const eligNext = activationEligibleFor(next);\n if (eligPrev === eligNext && prev.active === next.active) return prev;\n return next;\n });\n }, [extensions]);\n\n useLayoutEffect(() => {\n setPageHeader({\n startExtra: null,\n main: (\n <div className=\"w-full min-w-0 px-3 sm:px-5 xl:px-6\">\n <h1 className=\"min-w-0 truncate text-base font-semibold tracking-tight text-fg\">{m.appsPage.title}</h1>\n </div>\n ),\n end: null,\n });\n return () => clearPageHeader();\n }, [clearPageHeader, m.appsPage.title, setPageHeader]);\n\n if (loading && tab !== 'marketplace') {\n return <AppsPageSkeleton />;\n }\n\n return (\n <div className=\"flex min-h-0 flex-1 flex-col overflow-y-auto bg-surface-panel\">\n <div className=\"mx-auto w-full max-w-app-main px-4 py-8\">\n <header className=\"mb-6\">\n <h1 className=\"text-xl font-semibold text-fg\">{m.appsPage.title}</h1>\n <p className=\"mt-1 text-sm text-fg-muted\">{m.appsPage.subtitle}</p>\n </header>\n\n <div className=\"mb-5 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"flex flex-wrap gap-2\">\n <TabChip active={tab === 'all'} onClick={() => setTab('all')} label={m.appsPage.tabAll} />\n <TabChip\n active={tab === 'ui'}\n onClick={() => setTab('ui')}\n label={m.appsPage.tabWithUi}\n />\n <TabChip\n active={tab === 'backend'}\n onClick={() => setTab('backend')}\n label={m.appsPage.tabBackend}\n />\n <TabChip\n active={tab === 'marketplace'}\n onClick={() => setTab('marketplace')}\n label={m.appsPage.tabMarketplace}\n />\n </div>\n {tab !== 'marketplace' && extensions.length > 0 ? (\n <div className=\"relative w-full sm:max-w-xs\">\n <Search\n className=\"pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-fg-muted\"\n aria-hidden\n />\n <input\n type=\"search\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n placeholder={m.appsPage.searchPlaceholder}\n className=\"w-full rounded-lg border border-edge bg-surface-base py-2 pl-9 pr-3 text-sm text-fg placeholder:text-fg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent\"\n autoComplete=\"off\"\n />\n </div>\n ) : null}\n </div>\n\n {tab === 'marketplace' ? (\n <ExtensionMarketplacePanel />\n ) : extensions.length === 0 ? (\n <EmptyAppsState message={m.appsPage.empty} />\n ) : filtered.length === 0 ? (\n <p className=\"rounded-xl border border-dashed border-edge-subtle bg-surface-hover/30 px-4 py-8 text-center text-sm text-fg-muted dark:bg-surface-hover/15\">\n {m.appsPage.noSearchResults}\n </p>\n ) : (\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {filtered.map((ext) => (\n <ExtensionAppCard\n key={ext.id}\n extension={ext}\n copy={m.appsPage}\n onOpen={() => setDetail(ext)}\n />\n ))}\n </div>\n )}\n </div>\n\n {detail ? (\n <ExtensionDetailDialog\n key={detail.id}\n extension={detail}\n copy={m.appsPage}\n onClose={() => setDetail(null)}\n onAfterToggle={async () => {\n await mutate('gateway-extensions-list');\n }}\n />\n ) : null}\n </div>\n );\n}\n\nfunction TabChip({\n active,\n onClick,\n label,\n}: {\n active: boolean;\n onClick: () => void;\n label: string;\n}) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n className={cn(\n 'rounded-full border px-3 py-1.5 text-xs font-medium transition-colors',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent',\n active\n ? 'border-accent/40 bg-accent-soft text-accent-fg'\n : 'border-edge bg-surface-base text-fg-muted hover:bg-surface-hover hover:text-fg',\n )}\n >\n {label}\n </button>\n );\n}\n\nfunction activationEligibleFor(ext: ExtensionApiRow): boolean {\n return ext.activationEligible ?? ext.active;\n}\n\nfunction providerLabel(ext: ExtensionApiRow, copy: AppsPageCopy): string {\n if (ext.source === 'bundled') return copy.providerBundled;\n if (ext.source === 'global') return copy.providerGlobal;\n if (ext.source === 'workspace') return copy.providerWorkspace;\n return copy.providerOther;\n}\n\nfunction bundledRunCaption(ext: ExtensionApiRow, copy: AppsPageCopy): string {\n const eligible = activationEligibleFor(ext);\n if (eligible && ext.active) return copy.runStateLive;\n if (eligible && !ext.active) return copy.runStatePendingOn;\n if (!eligible && ext.active) return copy.runStatePendingOff;\n return copy.runStateOff;\n}\n\nfunction ExtensionAppCard({\n extension: ext,\n copy,\n onOpen,\n}: {\n extension: ExtensionApiRow;\n copy: AppsPageCopy;\n onOpen: () => void;\n}) {\n const eligible = activationEligibleFor(ext);\n\n return (\n <button\n type=\"button\"\n onClick={onOpen}\n className={cn(\n 'group flex w-full flex-col rounded-xl border border-edge bg-surface-base p-4 text-left shadow-sm transition-colors',\n 'hover:border-edge-subtle hover:bg-surface-hover/40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent',\n 'dark:hover:bg-surface-hover/25',\n )}\n >\n <div className=\"flex gap-3\">\n <div\n className=\"flex size-12 shrink-0 items-center justify-center rounded-xl bg-accent-soft text-base font-semibold text-accent-fg\"\n aria-hidden\n >\n {(ext.name || ext.id).charAt(0).toUpperCase()}\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"min-w-0\">\n <h2 className=\"truncate text-sm font-semibold text-fg\">{ext.name}</h2>\n {ext.version ? (\n <span className=\"text-[11px] text-fg-muted\">v{ext.version}</span>\n ) : null}\n </div>\n {eligible ? (\n <span className=\"inline-flex shrink-0 items-center gap-1 rounded-full bg-surface-hover px-2 py-0.5 text-[11px] font-medium text-fg-muted\">\n <Check className=\"size-3\" strokeWidth={2.5} aria-hidden />\n {copy.statusEnabled}\n </span>\n ) : (\n <span\n className=\"flex size-8 shrink-0 items-center justify-center rounded-full border-2 border-accent text-accent\"\n aria-hidden\n >\n <Plus className=\"size-4\" strokeWidth={2.5} />\n </span>\n )}\n </div>\n <p className=\"mt-2 line-clamp-2 text-xs leading-relaxed text-fg-muted\">\n {ext.description?.trim() || copy.cardNoDescription}\n </p>\n <div className=\"mt-2 flex flex-wrap gap-1.5\">\n <span className=\"rounded-md bg-surface-hover px-1.5 py-0.5 text-[10px] font-medium uppercase tracking-wide text-fg-muted\">\n {ext.hasUi ? copy.badgeKindUi : copy.badgeKindBackend}\n </span>\n {ext.source === 'bundled' ? (\n <span className=\"rounded-md bg-surface-hover px-1.5 py-0.5 text-[10px] font-medium uppercase tracking-wide text-fg-muted\">\n {copy.badgeBundled}\n </span>\n ) : null}\n </div>\n </div>\n </div>\n </button>\n );\n}\n\nfunction ExtensionDetailDialog({\n extension: ext,\n copy,\n onClose,\n onAfterToggle,\n}: {\n extension: ExtensionApiRow;\n copy: AppsPageCopy;\n onClose: () => void;\n onAfterToggle: () => void | Promise<void>;\n}) {\n const [saving, setSaving] = useState(false);\n const [errorMessage, setErrorMessage] = useState<string | null>(null);\n\n const pages = ext.ui?.contributions?.pages ?? [];\n const settingsPanels = ext.ui?.contributions?.settingsPanels ?? [];\n const chatWidgets = ext.ui?.contributions?.chatWidgets ?? [];\n const sidebarPanels = ext.ui?.contributions?.sidebarPanels ?? [];\n const primaryPage: PageContribution | undefined = pages.find((p) => p.showInNav) ?? pages[0];\n const primarySettingsPanel = settingsPanels[0];\n const openPath = primaryPage ? extensionPagePath(ext.id, primaryPage) : null;\n const settingsPath = primarySettingsPanel\n ? `/settings/ext/${ext.id}/${primarySettingsPanel.id}`\n : ext.hasConfigSchema\n ? `/settings/ext/${ext.id}`\n : null;\n\n const eligible = activationEligibleFor(ext);\n const isBundled = ext.source === 'bundled';\n\n const toggleBundled = async (next: boolean) => {\n setErrorMessage(null);\n setSaving(true);\n try {\n await fetchJson<{ ok: true; payload: { requiresGatewayRestart: boolean } }>(\n apiUrl('/api/extensions/bundled/activation'),\n { method: 'POST', body: JSON.stringify({ extensionId: ext.id, enabled: next }) },\n );\n await onAfterToggle();\n } catch (e) {\n setErrorMessage(e instanceof Error ? e.message : copy.toggleError);\n } finally {\n setSaving(false);\n }\n };\n\n return (\n <Dialog.Root defaultOpen onOpenChange={(o) => !o && onClose()}>\n <Dialog.Portal>\n <Dialog.Overlay className=\"xopc-dialog-overlay fixed inset-0 z-[130] bg-scrim\" />\n <Dialog.Content\n className=\"fixed left-1/2 top-1/2 z-[131] flex max-h-[min(90vh,44rem)] w-[min(42rem,calc(100vw-1.5rem))] -translate-x-1/2 -translate-y-1/2 flex-col overflow-hidden rounded-xl border border-edge bg-surface-panel shadow-elevated\"\n onOpenAutoFocus={(e) => e.preventDefault()}\n >\n <div className=\"flex shrink-0 items-center justify-between gap-2 border-b border-edge px-4 py-3\">\n <button\n type=\"button\"\n onClick={onClose}\n className=\"inline-flex size-9 items-center justify-center rounded-lg text-fg-muted hover:bg-surface-hover hover:text-fg focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent\"\n aria-label={copy.detailBack}\n >\n <ArrowLeft className=\"size-5\" />\n </button>\n <Dialog.Title className=\"min-w-0 flex-1 truncate text-center text-sm font-semibold text-fg\">\n {copy.detailTitle}\n </Dialog.Title>\n <Dialog.Description className=\"sr-only\">\n {ext.name} ({ext.id})\n </Dialog.Description>\n <button\n type=\"button\"\n onClick={onClose}\n className=\"inline-flex size-9 items-center justify-center rounded-lg text-fg-muted hover:bg-surface-hover hover:text-fg focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent\"\n aria-label={copy.detailClose}\n >\n <X className=\"size-5\" />\n </button>\n </div>\n\n <div className=\"min-h-0 flex-1 overflow-y-auto px-5 py-5\">\n <div className=\"flex flex-wrap items-start gap-4\">\n <div\n className=\"flex size-16 shrink-0 items-center justify-center rounded-2xl bg-accent-soft text-xl font-semibold text-accent-fg\"\n aria-hidden\n >\n {(ext.name || ext.id).charAt(0).toUpperCase()}\n </div>\n <div className=\"min-w-0 flex-1\">\n <h3 className=\"text-lg font-semibold text-fg\">{ext.name}</h3>\n <p className=\"mt-0.5 text-sm text-fg-muted\">\n {copy.detailProviderPrefix} {providerLabel(ext, copy)}\n </p>\n {ext.version ? (\n <p className=\"mt-1 text-xs text-fg-muted\">v{ext.version}</p>\n ) : null}\n </div>\n {isBundled ? (\n <div className=\"flex w-full flex-col items-stretch gap-2 sm:w-auto sm:items-end\">\n <button\n type=\"button\"\n disabled={saving}\n aria-busy={saving}\n onClick={() => void toggleBundled(!eligible)}\n className={cn(\n 'relative inline-flex max-w-full rounded-full py-1.5 text-sm font-medium',\n 'transition-[color,background-color,border-color,opacity] duration-200 ease-out',\n 'focus-visible:outline-none focus-visible:ring-2 motion-reduce:transition-none',\n eligible\n ? 'border-2 border-red-500/50 text-red-600 hover:bg-red-500/10 focus-visible:ring-red-500/40 dark:text-red-400'\n : 'border-2 border-transparent bg-accent text-white hover:opacity-90 focus-visible:ring-accent',\n saving && 'cursor-wait opacity-80',\n )}\n >\n <span className=\"block whitespace-nowrap px-4 text-center leading-none\">\n {eligible ? copy.actionDisable : copy.actionEnable}\n </span>\n <Loader2\n className={cn(\n 'pointer-events-none absolute right-2 top-1/2 size-3 -translate-y-1/2 text-current opacity-90',\n saving ? 'animate-spin' : 'invisible',\n )}\n aria-hidden\n />\n </button>\n </div>\n ) : null}\n </div>\n\n <p className=\"mt-5 text-sm leading-relaxed text-fg\">\n {ext.description?.trim() || copy.detailNoDescription}\n </p>\n\n {!ext.hasUi ? (\n <p className=\"mt-3 text-xs text-fg-muted\">{copy.backendOnlyHint}</p>\n ) : null}\n\n <p className=\"mt-2 text-xs text-fg-muted\">{bundledRunCaption(ext, copy)}</p>\n\n {errorMessage ? (\n <p className=\"mt-3 rounded-lg border border-red-500/30 bg-red-500/10 px-3 py-2 text-xs text-fg\" role=\"alert\">\n {errorMessage}\n </p>\n ) : null}\n\n {!isBundled ? (\n <p className=\"mt-4 rounded-lg border border-edge-subtle bg-surface-hover/40 px-3 py-2 text-xs text-fg-muted dark:bg-surface-hover/20\">\n {copy.cliManageHint}\n </p>\n ) : null}\n\n {ext.hasUi && (pages.length > 0 || settingsPanels.length > 0 || chatWidgets.length > 0) ? (\n <section className=\"mt-8\">\n <h4 className=\"mb-3 text-sm font-semibold text-fg\">{copy.detailSectionFeatures}</h4>\n <div className=\"flex flex-wrap gap-1.5\">\n <ContributionBadge\n template={copy.badgePages}\n count={pages.length}\n hidden={pages.length === 0}\n />\n <ContributionBadge\n template={copy.badgeSettings}\n count={settingsPanels.length}\n hidden={settingsPanels.length === 0}\n />\n <ContributionBadge\n template={copy.badgeWidgets}\n count={chatWidgets.length}\n hidden={chatWidgets.length === 0}\n />\n <ContributionBadge\n template={copy.badgeSidebar}\n count={sidebarPanels.length}\n hidden={sidebarPanels.length === 0}\n />\n </div>\n </section>\n ) : null}\n\n {extensionExposesGatewayShellUi(ext) && (openPath || settingsPath) ? (\n <div className=\"mt-6 flex flex-wrap gap-2 border-t border-edge-subtle pt-4\">\n {openPath ? (\n <Link\n to={openPath}\n onClick={onClose}\n className={cn(\n 'inline-flex items-center gap-1.5 rounded-lg border border-edge px-3 py-2 text-sm font-medium text-fg',\n 'hover:bg-surface-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent',\n )}\n >\n <ExternalLink className=\"size-4 shrink-0 opacity-80\" aria-hidden />\n {copy.open}\n </Link>\n ) : null}\n {settingsPath ? (\n <Link\n to={settingsPath}\n onClick={onClose}\n className={cn(\n 'inline-flex items-center gap-1.5 rounded-lg border border-edge px-3 py-2 text-sm font-medium text-fg',\n 'hover:bg-surface-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent',\n )}\n >\n <Settings className=\"size-4 shrink-0 opacity-80\" aria-hidden />\n {copy.openSettings}\n </Link>\n ) : null}\n </div>\n ) : null}\n\n <p className=\"mt-6 text-[11px] leading-relaxed text-fg-muted\">{copy.restartNote}</p>\n </div>\n </Dialog.Content>\n </Dialog.Portal>\n </Dialog.Root>\n );\n}\n\nfunction ContributionBadge({\n template,\n count,\n hidden,\n}: {\n template: string;\n count: number;\n hidden: boolean;\n}) {\n if (hidden || count === 0) return null;\n return (\n <span className=\"inline-flex items-center rounded-md bg-surface-hover px-2 py-0.5 text-[11px] font-medium text-fg-muted\">\n {template.replace(/\\{\\{count\\}\\}/g, String(count))}\n </span>\n );\n}\n\nfunction AppsPageSkeleton() {\n return (\n <div className=\"flex min-h-0 flex-1 flex-col overflow-y-auto bg-surface-panel\">\n <div className=\"mx-auto w-full max-w-app-main px-4 py-8\">\n <div className=\"mb-6 h-8 w-40 max-w-full animate-pulse rounded-md bg-surface-hover\" />\n <div className=\"mb-2 h-4 w-full max-w-md animate-pulse rounded bg-surface-hover\" />\n <div className=\"mb-5 h-9 w-full max-w-lg animate-pulse rounded-full bg-surface-hover\" />\n <div className=\"mt-6 grid gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {[0, 1, 2, 3, 4, 5].map((i) => (\n <div key={i} className=\"h-36 animate-pulse rounded-xl border border-edge bg-surface-base\" />\n ))}\n </div>\n </div>\n </div>\n );\n}\n\nfunction EmptyAppsState({ message }: { message: string }) {\n return (\n <div className=\"flex min-h-[min(40vh,16rem)] flex-col items-center justify-center rounded-xl border border-dashed border-edge-subtle bg-surface-hover/40 px-4 py-12 text-center dark:bg-surface-hover/20\">\n <p className=\"text-sm text-fg-muted\">{message}</p>\n </div>\n );\n}\n"],"mappings":"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"}
|