@oodarun/cli 0.1.16 → 0.1.18
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/README.md +5 -4
- package/dashboard-dist/assets/AdminApp-DzKKN2IA.js +6 -0
- package/dashboard-dist/assets/{AdminLogin-DPuKez-W.js → AdminLogin-BYZ4BJQb.js} +1 -1
- package/dashboard-dist/assets/{App-Dc5SAGN3.js → App-BLInVSOO.js} +1 -1
- package/dashboard-dist/assets/InternalDashboard-BOnJXxi7.js +1 -0
- package/dashboard-dist/assets/{SiteAuth-zqMzPUk6.js → SiteAuth-COKQhwhP.js} +1 -1
- package/dashboard-dist/assets/api-nNV-WJu1.js +1 -0
- package/dashboard-dist/assets/index-D6_514CX.css +1 -0
- package/dashboard-dist/assets/{index-e3u3oOC5.js → index-j26_mgI3.js} +2 -2
- package/dashboard-dist/assets/router-BvUnq6R0.js +1 -0
- package/dashboard-dist/index.html +2 -2
- package/dist/cli.js +94 -14
- package/package.json +1 -1
- package/dashboard-dist/assets/AdminApp-eGVdfeZo.js +0 -6
- package/dashboard-dist/assets/InternalDashboard-oJnYMgak.js +0 -1
- package/dashboard-dist/assets/api--5oZGh0X.js +0 -1
- package/dashboard-dist/assets/index-CrjhrzUZ.css +0 -1
package/README.md
CHANGED
|
@@ -78,15 +78,16 @@ Publish a built static site to a permanent shareable URL at `{slug}-p.ooda.run`.
|
|
|
78
78
|
From the CLI — fully non-interactive, so agents and CI can drive it:
|
|
79
79
|
|
|
80
80
|
```bash
|
|
81
|
-
ooda publish
|
|
82
|
-
ooda publish
|
|
81
|
+
ooda publish # run in the project root (auto-detects the build dir)
|
|
82
|
+
ooda publish --slug my-app # choose the slug
|
|
83
83
|
ooda sites list # list published sites
|
|
84
84
|
ooda sites access my-app --mode password --password s3cret # gate access
|
|
85
85
|
ooda sites delete my-app # unpublish
|
|
86
86
|
```
|
|
87
87
|
|
|
88
|
-
`publish`
|
|
89
|
-
`build`, `out`, `.output/public`, or `.next/static`)
|
|
88
|
+
Run `publish` from your **project root** — it auto-detects the build output
|
|
89
|
+
(`dist`, `build`, `out`, `.output/public`, or `.next/static`) inside it. Don't
|
|
90
|
+
pass the build folder itself (`ooda publish ./dist` is wrong). Build first.
|
|
90
91
|
Add `--json` to any command for machine-readable output, and set
|
|
91
92
|
`OODA_ACCESS_TOKEN` + `OODA_ORG_ID` to run without an interactive login.
|
|
92
93
|
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import{r as n,j as e}from"./index-j26_mgI3.js";import{m as G,a as X,b as Z,A as ee}from"./AdminLogin-BYZ4BJQb.js";import{e as D,f as U,h as te,j as se,g as ne,a as ae,c as q,s as re}from"./api-nNV-WJu1.js";import{u as ie,s as oe,D as le,a as ce}from"./router-BvUnq6R0.js";function de(s){return s.status==="pending"&&s.expiresAt&&new Date(s.expiresAt).getTime()<Date.now()?"expired":s.status}function xe(s){switch(s){case"pending":return"bg-yellow-100 text-yellow-800";case"expired":return"bg-orange-100 text-orange-800";default:return"bg-border text-ink-muted"}}function me({orgId:s,role:i="admin"}){const[o,l]=n.useState([]),[x,j]=n.useState([]),[k,f]=n.useState(!0),[p,b]=n.useState(null),m=i==="admin",[v,a]=n.useState(!1),[g,h]=n.useState(""),[t,u]=n.useState("member"),[y,d]=n.useState(!1),[C,R]=n.useState(null),N=async()=>{f(!0);try{const r=m?await D(s,"/users"):await U(s,"/members");if(!r.ok){b("Failed to load members");return}const P=await r.json();if(l(P.users||[]),m){const L=await D(s,"/invites");if(L.ok){const I=await L.json();j(I.invites||[])}}}catch{b("Could not reach the server")}finally{f(!1)}};n.useEffect(()=>{N()},[s]);const T=async r=>{r.preventDefault(),R(null);const P=g.trim().toLowerCase();if(!P||!P.includes("@")){R("Enter a valid email address");return}d(!0);try{const L=await D(s,"/invites",{method:"POST",body:JSON.stringify({emails:[P],role:t})});if(!L.ok){const I=await L.json().catch(()=>({}));R(I.error||"Failed to add member");return}h(""),u("member"),a(!1),N()}catch{R("Could not reach the server")}finally{d(!1)}},$=async r=>{if(!confirm(`Remove ${r} from this organization?`))return;(await D(s,`/users/${encodeURIComponent(r)}`,{method:"DELETE"})).ok&&l(L=>L.filter(I=>I.email!==r))},M=async r=>{if(!confirm(`Revoke invite for ${r}?`))return;(await D(s,`/invites/${encodeURIComponent(r)}`,{method:"DELETE"})).ok&&N()},_=async r=>{(await D(s,"/invites",{method:"POST",body:JSON.stringify({emails:[r],role:"member"})})).ok&&N()};if(k)return e.jsx("p",{className:"text-sm text-ink-muted",children:"Loading team..."});if(p)return e.jsx("p",{className:"text-sm text-red-600",children:p});const O=x.map(r=>({...r,display:de(r)})).filter(r=>r.display==="pending"||r.display==="expired");return e.jsxs("div",{className:"space-y-8",children:[e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between mb-4",children:[e.jsxs("h2",{className:"text-lg font-medium text-ink",children:["Team",e.jsx("span",{className:"text-ink-faint font-normal ml-2",children:o.length})]}),m&&e.jsx("button",{onClick:()=>a(r=>!r),className:"px-3 py-1.5 bg-ink text-surface text-xs font-medium hover:bg-ink/80 transition-colors",children:v?"Cancel":"Add member"})]}),m&&v&&e.jsxs("form",{onSubmit:T,className:"border border-border p-4 mb-4 bg-white",children:[e.jsx("p",{className:"text-xs text-ink-faint mb-2",children:"We'll email an invitation. They join once they accept and sign up."}),e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx("input",{type:"email",value:g,onChange:r=>h(r.target.value),placeholder:"person@example.com",autoFocus:!0,className:"flex-1 min-w-[14rem] px-3 py-2 border border-border text-sm bg-white focus:outline-none focus:ring-2 focus:ring-ink focus:border-transparent"}),e.jsxs("select",{value:t,onChange:r=>u(r.target.value),className:"px-3 py-2 border border-border text-sm bg-white focus:outline-none focus:ring-2 focus:ring-ink",children:[e.jsx("option",{value:"member",children:"Member"}),e.jsx("option",{value:"admin",children:"Admin"})]}),e.jsx("button",{type:"submit",disabled:y,className:"px-4 py-2 bg-ink text-surface text-sm font-medium hover:bg-ink/80 transition-colors disabled:opacity-50",children:y?"Sending...":"Send invite"})]}),C&&e.jsx("p",{className:"text-sm text-red-600 mt-2",children:C})]}),o.length===0?e.jsx("p",{className:"text-sm text-ink-muted",children:"No members yet."}):e.jsx("div",{className:"border border-border divide-y divide-border",children:o.map(r=>e.jsxs("div",{className:"flex items-center justify-between px-4 py-3",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-sm font-medium text-ink",children:r.name||r.email}),e.jsx("p",{className:"text-xs text-ink-faint",children:r.email})]}),r.role&&e.jsx("span",{className:`text-xs px-2 py-0.5 ${r.role==="admin"?"bg-ink text-surface":"bg-border text-ink-muted"}`,children:r.role})]}),e.jsxs("div",{className:"flex items-center gap-4",children:[e.jsx("span",{className:"text-xs text-ink-faint",children:new Date(r.joinedAt).toLocaleDateString()}),m&&e.jsx("button",{onClick:()=>$(r.email),className:"text-xs text-red-500 hover:text-red-700 transition-colors",children:"Remove"})]})]},r.email))})]}),m&&O.length>0&&e.jsxs("div",{children:[e.jsxs("h3",{className:"text-sm font-medium text-ink mb-3",children:["Pending invites",e.jsx("span",{className:"text-ink-faint font-normal ml-2",children:O.length})]}),e.jsx("div",{className:"border border-border divide-y divide-border",children:O.map(r=>e.jsxs("div",{className:"flex items-center justify-between px-4 py-3",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-sm font-medium text-ink",children:r.email}),e.jsxs("p",{className:"text-xs text-ink-faint",children:["invited ",new Date(r.createdAt).toLocaleDateString()]})]}),e.jsx("span",{className:`text-xs px-2 py-0.5 ${xe(r.display)}`,children:r.display}),e.jsx("span",{className:`text-xs px-2 py-0.5 ${r.role==="admin"?"bg-ink text-surface":"bg-border text-ink-muted"}`,children:r.role})]}),e.jsxs("div",{className:"flex items-center gap-3",children:[r.display==="expired"&&e.jsx("button",{onClick:()=>_(r.email),className:"text-xs text-ink hover:text-ink/70 transition-colors",children:"Re-send"}),e.jsx("button",{onClick:()=>M(r.email),className:"text-xs text-red-500 hover:text-red-700 transition-colors",children:"Revoke"})]})]},r.id))})]})]})}function ue(s){const i=Math.max(0,Math.floor(Date.now()/1e3-s));return i<60?`${i}s ago`:i<3600?`${Math.floor(i/60)}m ago`:i<86400?`${Math.floor(i/3600)}h ago`:`${Math.floor(i/86400)}d ago`}function he(s){try{return atob(s.logTailBase64)}catch{return""}}function z(s){const i=he(s).trim();if(!i)return"";const o=i.split(`
|
|
2
|
+
`).filter(l=>l.trim());return o[o.length-1]||""}function H(s){const i=Date.now()-new Date(s).getTime(),o=Math.floor(i/6e4);if(o<1)return"just now";if(o<60)return`${o}m ago`;const l=Math.floor(o/60);return l<24?`${l}h ago`:`${Math.floor(l/24)}d ago`}function fe(s){const i=s.toLowerCase();return["running","started","ready"].includes(i)?"bg-green-100 text-green-800":["stopped","suspended"].includes(i)?"bg-red-100 text-red-800":i==="sleeping"?"bg-gray-100 text-gray-600":"bg-yellow-100 text-yellow-800"}function pe({orgId:s,role:i="admin"}){const[o,l]=n.useState([]),[x,j]=n.useState([]),[k,f]=n.useState(!0),[p,b]=n.useState(null),m=i==="admin",v=m?D:U,a=async()=>{f(!0);try{const[t,u]=await Promise.all([v(s,"/projects"),U(s,"/sites")]);if(!t.ok){b("Failed to load projects");return}const y=await t.json();if(l(y.projects||[]),u.ok){const d=await u.json();j(d.sites||[])}else j([])}catch{b("Could not reach the server")}finally{f(!1)}};n.useEffect(()=>{a()},[s]);const g=async t=>{(await v(s,`/projects/${encodeURIComponent(t)}/stop`,{method:"POST"})).ok&&l(y=>y.map(d=>d.name===t?{...d,status:"stopped"}:d))},h=async t=>{if(!confirm(`Delete project "${t}"? This will destroy the running environment.`))return;(await v(s,`/projects/${encodeURIComponent(t)}`,{method:"DELETE"})).ok&&l(y=>y.filter(d=>d.name!==t))};return k?e.jsx("p",{className:"text-sm text-ink-muted",children:"Loading projects..."}):p?e.jsx("p",{className:"text-sm text-red-600",children:p}):e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between mb-4",children:[e.jsxs("h2",{className:"text-lg font-medium text-ink",children:["Projects",e.jsx("span",{className:"text-ink-faint font-normal ml-2",children:o.length})]}),e.jsx("button",{onClick:a,className:"text-xs text-ink-muted hover:text-ink transition-colors",children:"Refresh"})]}),o.length===0?e.jsxs("div",{className:"border border-border py-12 text-center",children:[e.jsx("p",{className:"text-sm text-ink-muted",children:"No projects created yet"}),e.jsx("p",{className:"text-xs text-ink-faint mt-1",children:"Projects will appear here when members deploy"})]}):e.jsx("div",{className:"border border-border divide-y divide-border",children:o.map(t=>{const u=m||t.isOwn,y=t.status&&["running","started","ready"].includes(t.status.toLowerCase()),d=x.filter(C=>C.projectName===t.name);return e.jsxs("div",{className:"px-4 py-3",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{className:"flex items-center gap-4",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-sm font-medium text-ink",children:t.name}),t.createdByName&&e.jsxs("p",{className:"text-xs text-ink-faint",children:[t.createdByName,t.isOwn&&!m&&e.jsx("span",{className:"text-ink-muted ml-1",children:"(you)"})]})]}),t.status&&e.jsx("span",{className:`text-xs px-2 py-0.5 ${fe(t.status)}`,children:t.status}),t.devServerStatus&&e.jsx("span",{className:"text-xs px-2 py-0.5 bg-red-100 text-red-800 cursor-help",title:`Dev server auto-disabled ${ue(t.devServerStatus.disabledAt)} after ${t.devServerStatus.fails} rapid crashes.${z(t.devServerStatus)?`
|
|
3
|
+
|
|
4
|
+
Last error: ${z(t.devServerStatus).slice(0,300)}`:""}
|
|
5
|
+
|
|
6
|
+
The owner needs to reconnect with npx @oodarun/cli and run /start-server after fixing the underlying error.`,children:"dev server disabled"})]}),e.jsxs("div",{className:"flex items-center gap-4",children:[t.lastActiveAt?e.jsxs("span",{className:"text-xs text-ink-muted",title:`Last active: ${t.lastActiveAt}`,children:["active ",H(t.lastActiveAt)]}):e.jsxs("span",{className:"text-xs text-ink-faint",title:t.createdAt,children:["created ",H(t.createdAt)]}),u&&y&&e.jsx("button",{onClick:()=>g(t.name),className:"text-xs text-amber-600 hover:text-amber-800 transition-colors",children:"Stop"}),u&&e.jsx("button",{onClick:()=>h(t.name),className:"text-xs text-red-500 hover:text-red-700 transition-colors",children:"Delete"})]})]}),d.length>0&&e.jsx("div",{className:"mt-2 pl-3 border-l-2 border-border space-y-1",children:d.map(C=>e.jsxs("div",{className:"flex items-center justify-between gap-3",children:[e.jsxs("div",{className:"flex items-center gap-2 min-w-0",children:[e.jsx("span",{className:"text-xs text-ink-faint shrink-0",children:"published site"}),e.jsx("a",{href:C.url,target:"_blank",rel:"noopener noreferrer",className:"text-xs text-ink-muted hover:text-ink truncate",children:C.slug})]}),e.jsx("span",{className:"text-xs text-ink-faint shrink-0",title:C.publishedAt,children:H(C.publishedAt)})]},C.slug))})]},t.name)})})]})}function be({orgId:s,site:i,apiFetch:o,onSaved:l}){const[x,j]=n.useState(i.accessMode??"inherit"),[k,f]=n.useState(!1),[p,b]=n.useState(""),[m,v]=n.useState(null),[a,g]=n.useState(!1),[h,t]=n.useState(null),u=x==="password"||x==="inherit"&&i.effectiveMode==="password",y=x!==(i.accessMode??"inherit")||k,d=async()=>{t(null);const N=await o(s,`/sites/${encodeURIComponent(i.slug)}/password`);if(!N.ok){t("Could not reveal password");return}const T=await N.json();v(T.password??"(none set)")},C=async()=>{m&&m!=="(none set)"&&(await navigator.clipboard.writeText(m),t("Copied"))},R=async()=>{g(!0),t(null);try{const N=Z({mode:x,setPassword:k,password:p});if(!(await o(s,`/sites/${encodeURIComponent(i.slug)}`,{method:"PATCH",body:JSON.stringify(N)})).ok){t("Save failed");return}f(!1),b(""),v(null),t("Saved"),l()}finally{g(!1)}};return e.jsxs("div",{className:"mt-2 flex flex-wrap items-center gap-2",children:[e.jsx("select",{value:x,onChange:N=>j(N.target.value),className:"text-xs border border-border bg-surface px-2 py-1 text-ink",children:X.map(N=>e.jsx("option",{value:N.value,children:N.value==="inherit"?`Inherit (${G(i.effectiveMode)})`:N.label},N.value))}),u&&e.jsx(e.Fragment,{children:k?e.jsx("input",{type:"text",value:p,onChange:N=>b(N.target.value),placeholder:"New password (blank to clear)",className:"text-xs border border-border bg-surface px-2 py-1 text-ink"}):e.jsxs(e.Fragment,{children:[e.jsx("button",{onClick:d,className:"text-xs text-ink-muted hover:text-ink border border-border px-2 py-1",children:"Reveal"}),m&&e.jsxs(e.Fragment,{children:[e.jsx("code",{className:"text-xs text-ink bg-surface-muted px-2 py-1",children:m}),e.jsx("button",{onClick:C,className:"text-xs text-ink-muted hover:text-ink",children:"Copy"})]}),e.jsx("button",{onClick:()=>f(!0),className:"text-xs text-ink-muted hover:text-ink",children:"Change"})]})}),y&&e.jsx("button",{onClick:R,disabled:a,className:"text-xs bg-ink text-surface px-2 py-1 disabled:opacity-50",children:a?"Saving…":"Save"}),h&&e.jsx("span",{className:"text-xs text-ink-faint",children:h})]})}function ge(s){const i=Date.now()-new Date(s).getTime(),o=Math.floor(i/6e4);if(o<1)return"just now";if(o<60)return`${o}m ago`;const l=Math.floor(o/60);return l<24?`${l}h ago`:`${Math.floor(l/24)}d ago`}function je({orgId:s,role:i="admin"}){const[o,l]=n.useState([]),[x,j]=n.useState(!0),[k,f]=n.useState(null),p=i==="admin",b=U,m=async()=>{j(!0);try{const a=await b(s,"/sites");if(!a.ok){f("Failed to load sites");return}const g=await a.json();l(g.sites||[])}catch{f("Could not reach the server")}finally{j(!1)}};n.useEffect(()=>{m()},[s]);const v=async a=>{if(!confirm(`Unpublish "${a}"? This will remove the site from ooda.run.`))return;(await b(s,`/sites/${encodeURIComponent(a)}`,{method:"DELETE"})).ok&&l(h=>h.filter(t=>t.slug!==a))};return x?e.jsx("p",{className:"text-sm text-ink-muted",children:"Loading sites..."}):k?e.jsx("p",{className:"text-sm text-red-600",children:k}):e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between mb-4",children:[e.jsxs("h2",{className:"text-lg font-medium text-ink",children:["Published Sites",e.jsx("span",{className:"text-ink-faint font-normal ml-2",children:o.length})]}),e.jsx("button",{onClick:m,className:"text-xs text-ink-muted hover:text-ink transition-colors",children:"Refresh"})]}),o.length===0?e.jsxs("div",{className:"border border-border py-12 text-center",children:[e.jsx("p",{className:"text-sm text-ink-muted",children:"No sites published yet"}),e.jsx("p",{className:"text-xs text-ink-faint mt-1",children:"Published sites will appear here"})]}):e.jsx("div",{className:"border border-border divide-y divide-border",children:o.map(a=>{const g=p||a.isOwn;return e.jsxs("div",{className:"flex items-start justify-between px-4 py-3",children:[e.jsxs("div",{children:[e.jsxs("p",{className:"text-sm font-medium text-ink",children:[a.slug,e.jsxs("span",{className:"ml-2 text-xs font-normal text-ink-faint border border-border px-1.5 py-0.5",children:[G(a.effectiveMode),a.accessMode===null&&" · inherited"]}),a.projectName?e.jsxs("span",{className:"ml-2 text-xs font-normal text-ink-muted border border-border px-1.5 py-0.5",title:`Linked to project ${a.projectName}`,children:["project: ",a.projectName]}):e.jsx("span",{className:"ml-2 text-xs font-normal text-ink-faint border border-border border-dashed px-1.5 py-0.5",title:"Published directly from a local folder, not linked to a cloud project",children:"deployed from local"})]}),e.jsx("p",{className:"text-xs text-ink-faint",children:a.url}),a.publishedByName&&e.jsxs("p",{className:"text-xs text-ink-faint mt-0.5",children:["by ",a.publishedByName,a.isOwn&&!p&&e.jsx("span",{className:"text-ink-muted ml-1",children:"(you)"})]}),g&&e.jsx(be,{orgId:s,site:a,apiFetch:b,onSaved:m})]}),e.jsxs("div",{className:"flex items-center gap-4",children:[e.jsx("span",{className:"text-xs text-ink-faint",title:a.publishedAt,children:ge(a.publishedAt)}),e.jsx("a",{href:a.url,target:"_blank",rel:"noopener noreferrer",className:"text-xs text-ink-muted hover:text-ink border border-border px-2 py-1 transition-colors",children:"Open"}),g&&e.jsx("button",{onClick:()=>v(a.slug),className:"text-xs text-red-500 hover:text-red-700 transition-colors",children:"Unpublish"})]})]},a.slug)})})]})}const Y=[{id:"models",label:"Models"},{id:"anthropic",label:"Anthropic"},{id:"env",label:"Environment variables"},{id:"sites",label:"Published sites"}],ve=[{value:"public",label:"Public — anyone with the link"},{value:"password",label:"Password — shared password"},{value:"login",label:"Ooda login — members of this org"}];function ke({orgId:s,onActiveSectionChange:i}){const[o,l]=n.useState(null),[x,j]=n.useState(!0),[k,f]=n.useState(!1),[p,b]=n.useState(null),[m,v]=n.useState(null),[a,g]=n.useState(""),[h,t]=n.useState(""),[u,y]=n.useState(""),[d,C]=n.useState(60),[R,N]=n.useState([]),[T,$]=n.useState("public"),[M,_]=n.useState(""),[O,r]=n.useState(!1);n.useEffect(()=>{if(x||!i)return;const c=new IntersectionObserver(S=>{const w=S.filter(A=>A.isIntersecting).sort((A,E)=>A.boundingClientRect.top-E.boundingClientRect.top);w[0]&&i(w[0].target.id)},{rootMargin:"-20% 0px -70% 0px"});return Y.forEach(S=>{const w=document.getElementById(S.id);w&&c.observe(w)}),()=>c.disconnect()},[x,i]);const P=async()=>{var c,S;j(!0),b(null);try{const w=await D(s,"/settings");if(!w.ok){b("Failed to load settings");return}const A=await w.json();l(A);const E=A.claude;if(E){g(((c=E.env)==null?void 0:c.ANTHROPIC_API_KEY)||""),t(((S=E.env)==null?void 0:S.ANTHROPIC_BASE_URL)||""),y(E.apiKeyHelper||""),C(Math.round((E.apiKeyHelperTtlMs||36e5)/6e4));const F=new Set(["ANTHROPIC_API_KEY","ANTHROPIC_BASE_URL"]),W=Object.entries(E.env||{}).filter(([K])=>!F.has(K)).map(([K,Q])=>({key:K,value:Q}));N(W)}A.siteAccess&&($(A.siteAccess.defaultMode),_(A.siteAccess.defaultPassword??"")),r(!1)}catch{b("Could not reach the server")}finally{j(!1)}};n.useEffect(()=>{P()},[s]);const L=async()=>{f(!0),b(null),v(null);const c={};a&&(c.ANTHROPIC_API_KEY=a),h&&(c.ANTHROPIC_BASE_URL=h);for(const w of R)w.key.trim()&&(c[w.key.trim()]=w.value);const S={};Object.keys(c).length>0&&(S.env=c),u.trim()&&(S.apiKeyHelper=u.trim(),S.apiKeyHelperTtlMs=d*6e4);try{const w={claude:Object.keys(S).length>0?S:null};if(O&&(w.siteAccess={defaultMode:T,defaultPassword:T==="password"&&M?M:null}),!(await D(s,"/settings",{method:"PUT",body:JSON.stringify(w)})).ok){b("Failed to save settings");return}v("Settings saved"),setTimeout(()=>v(null),3e3)}catch{b("Could not reach the server")}finally{f(!1)}},I=()=>{N(c=>[...c,{key:"",value:""}])},V=c=>{N(S=>S.filter((w,A)=>A!==c))},J=(c,S,w)=>{N(A=>A.map((E,F)=>F===c?{...E,[S]:w}:E))};return x?e.jsx("p",{className:"text-sm text-ink-muted",children:"Loading settings..."}):p&&!o?e.jsx("p",{className:"text-sm text-red-600",children:p}):e.jsx("div",{children:e.jsxs("div",{className:"space-y-12",children:[e.jsxs("section",{id:"models",className:"scroll-mt-6",children:[e.jsx("h2",{className:"text-lg font-medium text-ink mb-1",children:"Models"}),e.jsx("p",{className:"text-xs text-ink-faint mb-6",children:"Configure how Claude Code authenticates on cloud sandboxes in this organization."}),e.jsxs("div",{id:"anthropic",className:"scroll-mt-6",children:[e.jsx("h3",{className:"text-sm font-medium text-ink mb-2",children:"Anthropic"}),e.jsxs("div",{className:"border border-border divide-y divide-border",children:[e.jsxs("div",{className:"px-4 py-3",children:[e.jsx("label",{className:"block text-sm font-medium text-ink mb-1",children:"Anthropic API Key"}),e.jsx("p",{className:"text-xs text-ink-faint mb-2",children:"Encrypted at rest. Consider using an API key helper for automatic rotation."}),e.jsx("input",{type:"password",value:a,onChange:c=>g(c.target.value),placeholder:"sk-ant-api03-...",className:"w-full text-sm px-3 py-1.5 border border-border bg-surface text-ink placeholder:text-ink-faint focus:outline-none focus:border-ink"})]}),e.jsxs("div",{className:"px-4 py-3",children:[e.jsx("label",{className:"block text-sm font-medium text-ink mb-1",children:"Base URL"}),e.jsx("p",{className:"text-xs text-ink-faint mb-2",children:"Custom Anthropic API endpoint (leave blank for default)."}),e.jsx("input",{type:"text",value:h,onChange:c=>t(c.target.value),placeholder:"https://api.anthropic.com",className:"w-full text-sm px-3 py-1.5 border border-border bg-surface text-ink placeholder:text-ink-faint focus:outline-none focus:border-ink"})]}),e.jsxs("div",{className:"px-4 py-3",children:[e.jsx("label",{className:"block text-sm font-medium text-ink mb-1",children:"API Key Helper"}),e.jsx("p",{className:"text-xs text-ink-faint mb-2",children:"Path to a script that prints a valid API key to stdout. Used for token rotation."}),e.jsx("input",{type:"text",value:u,onChange:c=>y(c.target.value),placeholder:"/usr/local/bin/token-helper.sh",className:"w-full text-sm px-3 py-1.5 border border-border bg-surface text-ink placeholder:text-ink-faint focus:outline-none focus:border-ink"}),u&&e.jsxs("div",{className:"mt-2",children:[e.jsx("label",{className:"block text-xs text-ink-muted mb-1",children:"Refresh interval (minutes)"}),e.jsx("input",{type:"number",value:d,onChange:c=>C(parseInt(c.target.value,10)||60),min:1,className:"w-24 text-sm px-3 py-1.5 border border-border bg-surface text-ink focus:outline-none focus:border-ink"})]})]})]})]})]}),e.jsxs("section",{id:"env",className:"scroll-mt-6",children:[e.jsx("h2",{className:"text-lg font-medium text-ink mb-1",children:"Environment variables"}),e.jsx("p",{className:"text-xs text-ink-faint mb-4",children:"Additional env vars injected into project sessions."}),e.jsxs("div",{className:"border border-border px-4 py-3",children:[R.map((c,S)=>e.jsxs("div",{className:"flex gap-2 mb-2",children:[e.jsx("input",{type:"text",value:c.key,onChange:w=>J(S,"key",w.target.value),placeholder:"KEY",className:"flex-1 text-sm px-3 py-1.5 border border-border bg-surface text-ink placeholder:text-ink-faint focus:outline-none focus:border-ink font-mono"}),e.jsx("input",{type:"text",value:c.value,onChange:w=>J(S,"value",w.target.value),placeholder:"value",className:"flex-[2] text-sm px-3 py-1.5 border border-border bg-surface text-ink placeholder:text-ink-faint focus:outline-none focus:border-ink font-mono"}),e.jsx("button",{onClick:()=>V(S),className:"text-xs text-red-500 hover:text-red-700 px-2",children:"Remove"})]},S)),e.jsx("button",{onClick:I,className:"text-xs text-ink-muted hover:text-ink transition-colors",children:"+ Add variable"})]})]}),e.jsxs("section",{id:"sites",className:"scroll-mt-6",children:[e.jsx("h2",{className:"text-lg font-medium text-ink mb-1",children:"Published sites"}),e.jsx("p",{className:"text-xs text-ink-faint mb-4",children:"Default access policy for this org's published sites. Each site can override this. The password is encrypted at rest."}),e.jsxs("div",{className:"border border-border divide-y divide-border",children:[e.jsxs("div",{className:"px-4 py-3",children:[e.jsx("label",{className:"block text-sm font-medium text-ink mb-1",children:"Default access"}),e.jsx("select",{value:T,onChange:c=>{$(c.target.value),r(!0)},className:"w-full text-sm px-3 py-1.5 border border-border bg-surface text-ink focus:outline-none focus:border-ink",children:ve.map(c=>e.jsx("option",{value:c.value,children:c.label},c.value))})]}),T==="password"&&e.jsxs("div",{className:"px-4 py-3",children:[e.jsx("label",{className:"block text-sm font-medium text-ink mb-1",children:"Default password"}),e.jsx("p",{className:"text-xs text-ink-faint mb-2",children:"Shared by every site that inherits the org default. Sites can set their own."}),e.jsx("input",{type:"text",value:M,onChange:c=>{_(c.target.value),r(!0)},placeholder:"Set a default password",className:"w-full text-sm px-3 py-1.5 border border-border bg-surface text-ink placeholder:text-ink-faint focus:outline-none focus:border-ink"})]})]})]}),e.jsxs("div",{className:"flex items-center gap-3 sticky bottom-0 bg-surface py-3 border-t border-border",children:[e.jsx("button",{onClick:L,disabled:k,className:"text-sm font-medium px-4 py-1.5 bg-ink text-surface hover:opacity-90 transition-opacity disabled:opacity-50",children:k?"Saving...":"Save changes"}),m&&e.jsx("span",{className:"text-xs text-green-600",children:m}),p&&e.jsx("span",{className:"text-xs text-red-600",children:p})]})]})})}function ye({user:s,orgName:i,role:o,onLogout:l}){const[x,j]=n.useState(!1),[k,f]=n.useState(!1),p=async()=>{f(!0);try{await te(s.email),j(!0)}finally{f(!1)}};return e.jsxs("div",{children:[e.jsx("h2",{className:"text-lg font-medium text-ink mb-4",children:"Account"}),e.jsxs("div",{className:"border border-border divide-y divide-border",children:[e.jsxs("div",{className:"px-4 py-3",children:[e.jsx("p",{className:"text-xs text-ink-faint mb-0.5",children:"Name"}),e.jsx("p",{className:"text-sm text-ink",children:s.name||"—"})]}),e.jsxs("div",{className:"px-4 py-3",children:[e.jsx("p",{className:"text-xs text-ink-faint mb-0.5",children:"Email"}),e.jsx("p",{className:"text-sm text-ink",children:s.email})]}),e.jsxs("div",{className:"px-4 py-3",children:[e.jsx("p",{className:"text-xs text-ink-faint mb-0.5",children:"Organisation"}),e.jsxs("p",{className:"text-sm text-ink",children:[i,e.jsx("span",{className:"ml-2 text-xs text-ink-muted border border-border px-1.5 py-0.5",children:o})]})]})]}),e.jsxs("div",{className:"mt-6 flex items-center gap-4",children:[e.jsx("button",{onClick:p,disabled:k||x,className:"text-sm font-medium px-4 py-1.5 border border-border text-ink hover:bg-border/50 transition-colors disabled:opacity-50",children:x?"Reset link sent":k?"Sending…":"Reset password"}),e.jsx("button",{onClick:l,className:"text-sm text-red-500 hover:text-red-700 transition-colors",children:"Sign out"})]}),x&&e.jsxs("p",{className:"text-xs text-ink-faint mt-2",children:["If an account exists for ",s.email,", a password reset link is on its way."]})]})}const Ne=["projects","sites","team","settings","account"],B=s=>{var i;return((i=Y.find(o=>o.id===s))==null?void 0:i.label)??s},we=[{key:"models",label:"Models",children:[{key:"anthropic",label:B("anthropic")}]},{key:"env",label:B("env")},{key:"sites",label:B("sites")}];function Se({orgId:s,orgName:i,user:o,role:l,onLogout:x}){const j=l==="admin",{path:k,navigate:f}=ie(),p=ce(),[b,m]=n.useState(Y[0].id),v=oe(k,p);let a=Ne.includes(v)?v:"projects";!j&&a==="settings"&&(a="projects");const g=u=>f(`${p}/${u}`),h=[{key:"projects",label:"Projects"},{key:"sites",label:"Sites"},{key:"team",label:"Team"},...j?[{key:"settings",label:"Settings",children:we}]:[]],t=u=>{var y;(y=document.getElementById(u))==null||y.scrollIntoView({behavior:"smooth",block:"start"}),m(u)};return e.jsxs(le,{brand:i,brandAvatar:!0,nav:h,activeKey:a==="account"?"":a,onNavigate:g,activeChildKey:a==="settings"?b:void 0,onChildNavigate:t,user:o,onAccount:()=>g("account"),onLogout:x,children:[a==="projects"&&e.jsx(pe,{orgId:s,role:l}),a==="sites"&&e.jsx(je,{orgId:s,role:l}),a==="team"&&e.jsx(me,{orgId:s,role:l}),a==="settings"&&j&&e.jsx(ke,{orgId:s,onActiveSectionChange:m}),a==="account"&&e.jsx(ye,{user:o,orgName:i,role:l,onLogout:x})]})}function Ce({token:s,onDone:i}){const[o,l]=n.useState(""),[x,j]=n.useState(""),[k,f]=n.useState(null),[p,b]=n.useState([]),[m,v]=n.useState(!1),[a,g]=n.useState(!1),h=async t=>{if(t.preventDefault(),f(null),b([]),o!==x){f("Passwords do not match");return}v(!0);try{const u=await se(s,o);if(!u.ok){f(u.error||"Reset failed"),b(u.errors||[]);return}g(!0)}catch{f("Could not reach the server")}finally{v(!1)}};return e.jsx("div",{className:"min-h-screen bg-surface flex items-center justify-center",children:e.jsxs("div",{className:"w-full max-w-sm p-8",children:[e.jsxs("div",{className:"text-center mb-8",children:[e.jsx("img",{src:"/logo.svg",alt:"ooda",className:"h-6 mx-auto mb-2"}),e.jsx("p",{className:"text-sm text-ink-muted",children:"Choose a new password"})]}),a?e.jsxs("div",{className:"space-y-4 text-center",children:[e.jsx("p",{className:"text-sm text-ink",children:"Your password has been reset."}),e.jsx("button",{onClick:i,className:"w-full px-4 py-2 bg-ink text-surface text-sm font-medium hover:bg-ink/80 transition-colors",children:"Sign in"})]}):e.jsxs("form",{onSubmit:h,className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx("label",{htmlFor:"password",className:"block text-sm font-medium text-ink-muted mb-1",children:"New password"}),e.jsx("input",{id:"password",type:"password",value:o,onChange:t=>l(t.target.value),required:!0,autoComplete:"new-password",autoFocus:!0,className:"w-full px-3 py-2 border border-border text-sm bg-white focus:outline-none focus:ring-2 focus:ring-ink focus:border-transparent"})]}),e.jsxs("div",{children:[e.jsx("label",{htmlFor:"confirm",className:"block text-sm font-medium text-ink-muted mb-1",children:"Confirm password"}),e.jsx("input",{id:"confirm",type:"password",value:x,onChange:t=>j(t.target.value),required:!0,autoComplete:"new-password",className:"w-full px-3 py-2 border border-border text-sm bg-white focus:outline-none focus:ring-2 focus:ring-ink focus:border-transparent"})]}),k&&e.jsxs("div",{className:"text-sm text-red-600",children:[e.jsx("p",{children:k}),p.length>0&&e.jsx("ul",{className:"mt-1 list-disc list-inside text-xs text-red-500",children:p.map(t=>e.jsx("li",{children:t},t))})]}),e.jsx("button",{type:"submit",disabled:m,className:"w-full px-4 py-2 bg-ink text-surface text-sm font-medium hover:bg-ink/80 transition-colors disabled:opacity-50",children:m?"...":"Reset password"})]})]})})}function Te(){const[s,i]=n.useState(null),[o,l]=n.useState([]),[x,j]=n.useState(null),[k,f]=n.useState(!0);n.useEffect(()=>{(async()=>{if(!ne()){f(!1);return}const h=await ae();if(h){i(h.user);const t=localStorage.getItem("ooda-selected-org"),u=localStorage.getItem("ooda-selected-org-name"),y=h.orgs.find(d=>d.orgId===t);if(y)l(h.orgs.map(d=>({...d,orgName:d.orgId===t&&u||d.orgId}))),j({...y,orgName:u||y.orgId});else if(h.orgs.length>0){const d=h.orgs.map(C=>({...C,orgName:C.orgId}));l(d),j(d[0]),localStorage.setItem("ooda-selected-org",d[0].orgId),localStorage.setItem("ooda-selected-org-name",d[0].orgName)}}else q();f(!1)})()},[]);const p=(g,h,t,u)=>{re(t,u),i(g),l(h);const d=h.find(C=>C.role==="admin")||h[0];d&&(j(d),localStorage.setItem("ooda-selected-org",d.orgId),localStorage.setItem("ooda-selected-org-name",d.orgName))},b=()=>{q(),localStorage.removeItem("ooda-selected-org"),localStorage.removeItem("ooda-selected-org-name"),i(null),l([]),j(null)},m=window.location.pathname!=="/reset-password"?null:new URLSearchParams(window.location.search).get("token");if(m)return e.jsx(Ce,{token:m,onDone:()=>{window.location.href="/"}});if(k)return e.jsx("div",{className:"min-h-screen bg-surface flex items-center justify-center",children:e.jsx("p",{className:"text-sm text-ink-muted",children:"Loading..."})});if(!s||!x)return e.jsx(ee,{onLogin:p});const v=o.find(g=>g.orgId===x.orgId),a=(v==null?void 0:v.role)||"member";return e.jsx(Se,{orgId:x.orgId,orgName:x.orgName,user:s,role:a,onLogout:b})}export{Te as AdminApp};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{r as i,j as e}from"./index-
|
|
1
|
+
import{r as i,j as e}from"./index-j26_mgI3.js";import{h as E}from"./api-nNV-WJu1.js";const L=[{value:"inherit",label:"Inherit org default"},{value:"public",label:"Public"},{value:"password",label:"Password"},{value:"login",label:"Ooda login"}];function D(s){switch(s){case"public":return"Public";case"password":return"Password";case"login":return"Ooda login"}}function q(s){const n={accessMode:s.mode==="inherit"?null:s.mode};return s.setPassword&&(n.password=s.password?s.password:null),n}function F(s){try{const n=new URL(s);return n.protocol==="https:"&&/^[a-z0-9-]+-p\.ooda\.run$/.test(n.hostname)}catch{return!1}}function $(s){const n=new URLSearchParams(s).get("return");return n&&F(n)?n:null}function A(){const n=new URLSearchParams(window.location.search).get("email");return window.location.pathname==="/signup"&&n?{mode:"invite",email:n}:{mode:"login",email:""}}function B({onLogin:s}){const[n]=i.useState(A),[r]=i.useState(n.mode),[k,f]=i.useState("login"),[o,b]=i.useState(n.email),[d,N]=i.useState(""),[w,S]=i.useState(""),[m,a]=i.useState(null),[v,x]=i.useState([]),[h,c]=i.useState(!1),[C,j]=i.useState(!1),g="https://api.ooda.run",P=async t=>{t.preventDefault(),a(null),x([]),c(!0);try{const u=await fetch(`${g}/auth/login`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({email:o,password:d})});if(!u.ok){a("Invalid email or password");return}const l=await u.json();s(l.user,l.orgs,l.accessToken,l.refreshToken)}catch{a("Could not reach the server")}finally{c(!1)}},T=async t=>{t.preventDefault(),a(null),c(!0);try{await E(o),j(!0)}catch{a("Could not reach the server")}finally{c(!1)}},O=async t=>{t.preventDefault(),a(null),x([]),c(!0);try{const u=await fetch(`${g}/auth/signup`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({email:o,password:d,name:w})}),l=await u.json();if(!u.ok){a(l.error||"Signup failed"),x(l.errors||[]);return}const y=await fetch(`${g}/auth/login`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({email:o,password:d})});if(!y.ok){a("Account created but login failed. Try logging in.");return}const p=await y.json();s(p.user,p.orgs,p.accessToken,p.refreshToken)}catch{a("Could not reach the server")}finally{c(!1)}};return k==="forgot"?e.jsx("div",{className:"min-h-screen bg-surface flex items-center justify-center",children:e.jsxs("div",{className:"w-full max-w-sm p-8",children:[e.jsxs("div",{className:"text-center mb-8",children:[e.jsx("img",{src:"/logo.svg",alt:"ooda",className:"h-6 mx-auto mb-2"}),e.jsx("p",{className:"text-sm text-ink-muted",children:"Reset your password"})]}),C?e.jsxs("div",{className:"space-y-4 text-center",children:[e.jsxs("p",{className:"text-sm text-ink",children:["If an account exists for ",e.jsx("strong",{children:o}),", we've sent a reset link. Check your inbox."]}),e.jsx("button",{onClick:()=>{f("login"),j(!1)},className:"text-sm text-ink-muted underline hover:text-ink",children:"Back to sign in"})]}):e.jsxs("form",{onSubmit:T,className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx("label",{htmlFor:"email",className:"block text-sm font-medium text-ink-muted mb-1",children:"Email"}),e.jsx("input",{id:"email",type:"email",value:o,onChange:t=>b(t.target.value),required:!0,autoComplete:"email",autoFocus:!0,className:"w-full px-3 py-2 border border-border text-sm bg-white focus:outline-none focus:ring-2 focus:ring-ink focus:border-transparent"})]}),m&&e.jsx("p",{className:"text-sm text-red-600",children:m}),e.jsx("button",{type:"submit",disabled:h,className:"w-full px-4 py-2 bg-ink text-surface text-sm font-medium hover:bg-ink/80 transition-colors disabled:opacity-50",children:h?"...":"Send reset link"}),e.jsx("button",{type:"button",onClick:()=>{f("login"),a(null)},className:"w-full text-sm text-ink-muted hover:text-ink",children:"Back to sign in"})]})]})}):e.jsx("div",{className:"min-h-screen bg-surface flex items-center justify-center",children:e.jsxs("div",{className:"w-full max-w-sm p-8",children:[e.jsxs("div",{className:"text-center mb-8",children:[e.jsx("img",{src:"/logo.svg",alt:"ooda",className:"h-6 mx-auto mb-2"}),e.jsx("p",{className:"text-sm text-ink-muted",children:r==="invite"?"Accept your invite":"Sign in to your account"})]}),e.jsxs("form",{onSubmit:r==="invite"?O:P,className:"space-y-4",children:[r==="invite"&&e.jsxs("div",{children:[e.jsx("label",{htmlFor:"name",className:"block text-sm font-medium text-ink-muted mb-1",children:"Name"}),e.jsx("input",{id:"name",type:"text",value:w,onChange:t=>S(t.target.value),required:!0,autoComplete:"name",autoFocus:!0,className:"w-full px-3 py-2 border border-border text-sm bg-white focus:outline-none focus:ring-2 focus:ring-ink focus:border-transparent"})]}),e.jsxs("div",{children:[e.jsx("label",{htmlFor:"email",className:"block text-sm font-medium text-ink-muted mb-1",children:"Email"}),e.jsx("input",{id:"email",type:"email",value:o,onChange:t=>b(t.target.value),required:!0,autoComplete:"email",autoFocus:r==="login",disabled:r==="invite",className:"w-full px-3 py-2 border border-border text-sm bg-white focus:outline-none focus:ring-2 focus:ring-ink focus:border-transparent disabled:bg-gray-50 disabled:text-ink-muted"})]}),e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between mb-1",children:[e.jsx("label",{htmlFor:"password",className:"block text-sm font-medium text-ink-muted",children:r==="invite"?"Choose a password":"Password"}),r==="login"&&e.jsx("button",{type:"button",onClick:()=>{f("forgot"),a(null),x([])},className:"text-xs text-ink-muted hover:text-ink",children:"Forgot password?"})]}),e.jsx("input",{id:"password",type:"password",value:d,onChange:t=>N(t.target.value),required:!0,autoComplete:r==="invite"?"new-password":"current-password",className:"w-full px-3 py-2 border border-border text-sm bg-white focus:outline-none focus:ring-2 focus:ring-ink focus:border-transparent"})]}),m&&e.jsxs("div",{className:"text-sm text-red-600",children:[e.jsx("p",{children:m}),v.length>0&&e.jsx("ul",{className:"mt-1 list-disc list-inside text-xs text-red-500",children:v.map(t=>e.jsx("li",{children:t},t))})]}),e.jsx("button",{type:"submit",disabled:h,className:"w-full px-4 py-2 bg-ink text-surface text-sm font-medium hover:bg-ink/80 transition-colors disabled:opacity-50",children:h?"...":r==="invite"?"Accept invite":"Sign in"})]})]})})}export{B as A,L as a,q as b,D as m,$ as p};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{r as s,j as e}from"./index-e3u3oOC5.js";function I({onOpen:b}){const[d,a]=s.useState([]),[N,i]=s.useState(!0),[k,l]=s.useState(null),[u,v]=s.useState({}),t=async()=>{i(!0);try{const j=(await(await fetch("/api/projects")).json()).projects||[];a(j);const m={};await Promise.all(j.map(async c=>{try{const g=await fetch(`https://ooda.run/api/publish/${c.name}`);g.ok&&(m[c.name]=await g.json())}catch{}})),v(m)}catch{a([])}finally{i(!1)}};s.useEffect(()=>{t()},[]);const y=async o=>{if(confirm(`Delete project "${o}"? This cannot be undone.`)){l(o);try{const p=await fetch(`/api/projects/${o}`,{method:"DELETE"});if(!p.ok){const j=await p.json().catch(()=>({error:"Unknown error"}));alert(`Failed to delete project: ${j.error||p.statusText}`);return}a(j=>j.filter(m=>m.name!==o))}finally{l(null)}}};return N?e.jsx("div",{className:"text-center py-12 text-sm text-ink-faint",children:"Loading projects..."}):d.length===0?e.jsxs("div",{className:"text-center py-12",children:[e.jsx("p",{className:"text-ink-muted text-sm mb-1",children:"No projects yet"}),e.jsx("p",{className:"text-ink-faint text-xs",children:"Create a new project or deploy a local folder to get started."})]}):e.jsxs("div",{children:[e.jsx("h2",{className:"text-xs font-semibold text-ink uppercase tracking-widest mb-4",children:"Projects"}),e.jsx("div",{className:"space-y-2",children:d.map(o=>{const p=o.isOwn!==!1;return e.jsxs("div",{className:"flex items-center justify-between p-4 border border-border hover:border-ink-faint transition-colors",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("div",{className:`w-2 h-2 rounded-full ${o.status==="running"?"bg-green-500":o.status==="stopped"?"bg-border":"bg-yellow-500"}`}),e.jsxs("div",{children:[e.jsx("p",{className:"text-sm font-medium text-ink",children:o.name}),e.jsxs("p",{className:"text-xs text-ink-faint font-mono mt-0.5",children:[o.owner&&e.jsxs("span",{children:[o.owner,o.isOwn&&e.jsx("span",{className:"text-ink-muted ml-1",children:"(you)"}),o.url&&e.jsx("span",{className:"mx-1",children:"·"})]}),o.url&&o.url]})]})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[u[o.name]&&e.jsx("a",{href:u[o.name].latestUrl,target:"_blank",rel:"noopener noreferrer",className:"px-3 py-1.5 text-sm font-medium text-green-700 bg-green-50 hover:bg-green-100 transition-colors",children:"Published"}),p&&o.url&&e.jsx("button",{onClick:()=>b({name:o.name,url:o.url}),className:"px-3 py-1.5 text-sm font-medium text-ink-muted bg-border/50 hover:bg-border transition-colors",children:"Open"}),p&&e.jsx("button",{onClick:()=>y(o.name),disabled:k===o.name,className:"px-3 py-1.5 text-sm text-ink-faint hover:text-ink transition-colors disabled:opacity-50",children:k===o.name?"...":"Delete"})]})]},o.name)})})]})}function G({onCreate:b,deploying:d}){const[a,N]=s.useState([]),[i,k]=s.useState(""),[l,u]=s.useState(null);s.useEffect(()=>{fetch("/api/templates").then(t=>t.json()).then(t=>{var y;N(t.templates||[]),((y=t.templates)==null?void 0:y.length)>0&&u(t.templates[0].id)})},[]);const v=t=>{t.preventDefault(),!(!i.trim()||!l)&&b(i.trim(),l)};return e.jsxs("div",{children:[e.jsx("h2",{className:"text-xs font-semibold text-ink uppercase tracking-widest mb-4",children:"Create new project"}),e.jsxs("form",{onSubmit:v,className:"max-w-lg space-y-6",children:[e.jsxs("div",{children:[e.jsx("label",{htmlFor:"project-name",className:"block text-sm font-medium text-ink-muted mb-1.5",children:"Project name"}),e.jsx("input",{id:"project-name",type:"text",value:i,onChange:t=>k(t.target.value),placeholder:"my-project",className:"w-full px-3 py-2 border border-border text-sm focus:outline-none focus:ring-2 focus:ring-ink focus:border-transparent"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-sm font-medium text-ink-muted mb-3",children:"Template"}),e.jsx("div",{className:"space-y-2",children:a.map(t=>e.jsxs("label",{className:`flex items-start gap-3 p-4 border cursor-pointer transition-colors ${l===t.id?"border-ink bg-surface":"border-border hover:border-border"}`,children:[e.jsx("input",{type:"radio",name:"template",value:t.id,checked:l===t.id,onChange:()=>u(t.id),className:"mt-0.5"}),e.jsxs("div",{children:[e.jsx("p",{className:"text-sm font-medium text-ink",children:t.name}),e.jsx("p",{className:"text-xs text-ink-muted mt-0.5",children:t.description})]})]},t.id))})]}),e.jsx("button",{type:"submit",disabled:!i.trim()||!l||d,className:"px-6 py-2 bg-ink text-surface text-sm font-medium hover:bg-ink/80 disabled:opacity-50 disabled:cursor-not-allowed transition-colors",children:d?"Creating...":"Create project"})]})]})}function H({onDeploy:b,deploying:d}){const[a,N]=s.useState(null),[i,k]=s.useState(null),[l,u]=s.useState(!0),[v,t]=s.useState(!1),[y,o]=s.useState(""),[p,j]=s.useState(""),m=s.useCallback(async c=>{u(!0);try{const g=c?`?path=${encodeURIComponent(c)}`:"",D=await fetch(`/api/browse${g}`);if(!D.ok)throw new Error;const P=await D.json();N(P),k(null),t(!1)}catch{t(!0)}finally{u(!1)}},[]);return s.useEffect(()=>{m()},[m]),v?e.jsxs("div",{children:[e.jsx("h2",{className:"text-xs font-semibold text-ink uppercase tracking-widest mb-4",children:"Deploy a folder"}),e.jsxs("div",{className:"max-w-lg space-y-4",children:[e.jsxs("div",{children:[e.jsx("label",{htmlFor:"project-name-fallback",className:"block text-sm font-medium text-ink-muted mb-1.5",children:"Project name"}),e.jsx("input",{id:"project-name-fallback",type:"text",value:p,onChange:c=>j(c.target.value),placeholder:"Defaults to folder name",className:"w-full px-3 py-2 border border-border text-sm focus:outline-none focus:ring-2 focus:ring-ink focus:border-transparent"})]}),e.jsxs("div",{children:[e.jsx("label",{htmlFor:"folder-path",className:"block text-sm font-medium text-ink-muted mb-1.5",children:"Folder path"}),e.jsx("input",{id:"folder-path",type:"text",value:y,onChange:c=>o(c.target.value),placeholder:"Leave empty to deploy the current directory",className:"w-full px-3 py-2 border border-border text-sm focus:outline-none focus:ring-2 focus:ring-ink focus:border-transparent"}),e.jsx("p",{className:"mt-1.5 text-xs text-ink-faint",children:"Absolute path to a project folder with a package.json."})]}),e.jsx("button",{onClick:()=>b(y.trim()||void 0,p.trim()||void 0),disabled:d,className:"px-6 py-2 bg-ink text-surface text-sm font-medium hover:bg-ink/80 disabled:opacity-50 disabled:cursor-not-allowed transition-colors",children:d?"Deploying...":"Deploy"})]})]}):e.jsxs("div",{children:[e.jsx("h2",{className:"text-xs font-semibold text-ink uppercase tracking-widest mb-4",children:"Deploy a folder"}),e.jsxs("div",{className:"max-w-lg space-y-3",children:[a&&e.jsxs("div",{className:"flex items-center gap-2 text-xs text-ink-muted",children:[a.parent&&e.jsx("button",{onClick:()=>m(a.parent),disabled:l,className:"px-2 py-0.5 font-medium text-ink-muted bg-border/50 border border-border hover:bg-border disabled:opacity-30 transition-colors",children:"←"}),e.jsx("span",{className:"font-mono truncate",children:a.current})]}),e.jsx("div",{className:"border border-border overflow-hidden",children:l&&!a?e.jsx("div",{className:"px-3 py-8 text-center text-sm text-ink-faint",children:"Loading..."}):e.jsxs("div",{className:"max-h-72 overflow-y-auto",children:[(a==null?void 0:a.entries.length)===0&&e.jsx("div",{className:"px-3 py-8 text-center text-sm text-ink-faint",children:"No subfolders"}),a==null?void 0:a.entries.map(c=>{const g=i===c.path;return e.jsxs("button",{type:"button",className:`w-full flex items-center gap-2.5 px-3 py-2 text-left border-b border-border/30 last:border-0 transition-colors ${g?"bg-ink text-surface":"hover:bg-border/30"}`,onClick:()=>k(g?null:c.path),onDoubleClick:()=>m(c.path),children:[e.jsx("span",{className:"text-sm flex-shrink-0",children:c.hasPackageJson?"📦":"📁"}),e.jsx("span",{className:`text-sm truncate ${g?"text-surface font-medium":"text-ink"}`,children:c.name}),c.hasPackageJson&&e.jsx("span",{className:`ml-auto text-[11px] flex-shrink-0 ${g?"text-ink-faint":"text-ink-muted"}`,children:"project"})]},c.path)})]})}),e.jsxs("div",{children:[e.jsx("label",{htmlFor:"project-name",className:"block text-sm font-medium text-ink-muted mb-1.5",children:"Project name"}),e.jsx("input",{id:"project-name",type:"text",value:p,onChange:c=>j(c.target.value),placeholder:"Defaults to folder name",className:"w-full px-3 py-2 border border-border text-sm focus:outline-none focus:ring-2 focus:ring-ink focus:border-transparent"})]}),e.jsxs("div",{className:"flex items-center gap-3 pt-1",children:[e.jsx("button",{onClick:()=>b(i||void 0,p.trim()||void 0),disabled:d||!i,className:"px-6 py-2 bg-ink text-surface text-sm font-medium hover:bg-ink/80 disabled:opacity-50 disabled:cursor-not-allowed transition-colors",children:d?"Deploying...":"Deploy"}),e.jsx("span",{className:"text-xs text-ink-faint",children:i?e.jsx("span",{className:"font-mono text-ink-muted",children:i}):"Click to select, double-click to open"})]})]})]})}function M({onDeploy:b,deploying:d}){const[a,N]=s.useState(""),[i,k]=s.useState(""),[l,u]=s.useState([]),[v,t]=s.useState(null),[y,o]=s.useState(null),[p,j]=s.useState(!0),[m,c]=s.useState("");s.useEffect(()=>{fetch("/api/github-repos").then(n=>n.json()).then(n=>{u(n.repos),t(n.authenticated),o(n.username||null)}).catch(()=>t(!1)).finally(()=>j(!1))},[]);const g=()=>{const n=a.trim();n&&b(n,i.trim()||void 0)},D=n=>{N(n.fullName),k("")},P=m?l.filter(n=>n.fullName.toLowerCase().includes(m.toLowerCase())||n.description&&n.description.toLowerCase().includes(m.toLowerCase())):l;return e.jsxs("div",{children:[e.jsxs("h2",{className:"text-xs font-semibold text-ink uppercase tracking-widest mb-4",children:["Clone from GitHub",y&&e.jsxs("span",{className:"text-ink-faint font-normal normal-case tracking-normal ml-2",children:["signed in as ",y]})]}),e.jsxs("div",{className:"max-w-lg space-y-4",children:[e.jsxs("div",{children:[e.jsx("label",{htmlFor:"github-url",className:"block text-sm font-medium text-ink-muted mb-1.5",children:"GitHub URL"}),e.jsx("input",{id:"github-url",type:"text",value:a,onChange:n=>N(n.target.value),onKeyDown:n=>n.key==="Enter"&&g(),placeholder:"owner/repo or https://github.com/owner/repo",className:"w-full px-3 py-2 border border-border text-sm focus:outline-none focus:ring-2 focus:ring-ink focus:border-transparent font-mono"}),e.jsx("p",{className:"mt-1.5 text-xs text-ink-faint",children:"Paste a URL, or pick from your repos below. Add #branch for a specific branch."})]}),v===!1&&e.jsxs("p",{className:"text-xs text-ink-muted",children:["No GitHub token detected. Run ",e.jsx("span",{className:"font-mono font-medium",children:"gh auth login"})," to see your repos here."]}),v&&e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between mb-1.5",children:[e.jsx("label",{className:"block text-sm font-medium text-ink-muted",children:"Your repos"}),l.length>5&&e.jsx("input",{type:"text",value:m,onChange:n=>c(n.target.value),placeholder:"Filter...",className:"px-2 py-1 border border-border text-xs focus:outline-none focus:ring-1 focus:ring-ink w-40"})]}),e.jsx("div",{className:"border border-border overflow-hidden",children:p?e.jsx("div",{className:"px-3 py-8 text-center text-sm text-ink-faint",children:"Loading repos..."}):P.length===0?e.jsx("div",{className:"px-3 py-8 text-center text-sm text-ink-faint",children:m?"No matching repos":"No repos found"}):e.jsx("div",{className:"max-h-64 overflow-y-auto",children:P.map(n=>{const $=a===n.fullName;return e.jsxs("button",{type:"button",className:`w-full flex items-center gap-2.5 px-3 py-2 text-left border-b border-border/30 last:border-0 transition-colors ${$?"bg-ink text-surface":"hover:bg-border/30"}`,onClick:()=>D(n),children:[e.jsx("span",{className:"text-sm flex-shrink-0",children:n.isPrivate?"🔒":"📦"}),e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsx("span",{className:`text-sm truncate block ${$?"text-surface font-medium":"text-ink"}`,children:n.fullName}),n.description&&e.jsx("span",{className:`text-xs truncate block ${$?"text-surface/60":"text-ink-faint"}`,children:n.description})]})]},n.fullName)})})})]}),e.jsxs("div",{children:[e.jsx("label",{htmlFor:"gh-project-name",className:"block text-sm font-medium text-ink-muted mb-1.5",children:"Project name"}),e.jsx("input",{id:"gh-project-name",type:"text",value:i,onChange:n=>k(n.target.value),onKeyDown:n=>n.key==="Enter"&&g(),placeholder:"Defaults to repo name",className:"w-full px-3 py-2 border border-border text-sm focus:outline-none focus:ring-2 focus:ring-ink focus:border-transparent"})]}),e.jsx("button",{onClick:g,disabled:d||!a.trim(),className:"px-6 py-2 bg-ink text-surface text-sm font-medium hover:bg-ink/80 disabled:opacity-50 disabled:cursor-not-allowed transition-colors",children:d?"Deploying...":"Clone & Deploy"})]})]})}function _({onLogin:b,authenticated:d}){const[a,N]=s.useState(""),[i,k]=s.useState(null),l=u=>{if(u.preventDefault(),!a.trim()){k("Please enter your Claude API key or OAuth token");return}k(null),b("",a.trim())};return e.jsx("div",{className:"min-h-screen bg-surface flex items-center justify-center",children:e.jsxs("div",{className:"w-full max-w-md p-8",children:[e.jsxs("div",{className:"text-center mb-8",children:[e.jsx("img",{src:"/logo.svg",alt:"ooda",className:"h-6 mx-auto mb-2"}),e.jsx("p",{className:"text-sm text-ink-muted",children:d?"Connect Claude to edit code on your cloud sandbox":"Sign in to manage cloud sandboxes"})]}),e.jsxs("form",{onSubmit:l,className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx("label",{htmlFor:"claude-token",className:"block text-sm font-medium text-ink-muted mb-1.5",children:"Claude API Key or OAuth Token"}),e.jsx("input",{id:"claude-token",type:"password",value:a,onChange:u=>N(u.target.value),placeholder:"sk-ant-... or oauth token",autoFocus:!0,className:"w-full px-3 py-2 border border-border text-sm focus:outline-none focus:ring-2 focus:ring-ink focus:border-transparent"}),e.jsxs("p",{className:"mt-1.5 text-xs text-ink-faint",children:[e.jsx("strong",{children:"API key"}),": get from"," ",e.jsx("a",{href:"https://console.anthropic.com/settings/keys",target:"_blank",rel:"noopener noreferrer",className:"text-ink-muted underline hover:text-ink",children:"console.anthropic.com"}),e.jsx("br",{}),e.jsx("strong",{children:"OAuth token"}),": run"," ",e.jsx("code",{className:"bg-border/50 px-1 text-xs font-mono",children:"claude setup-token"})," ","in your terminal (for Claude Pro/Teams)"]})]}),i&&e.jsx("p",{className:"text-sm text-red-600",children:i}),e.jsx("button",{type:"submit",className:"w-full px-4 py-2 bg-ink text-surface text-sm font-medium hover:bg-ink/80 transition-colors",children:"Sign in"})]})]})})}function B(){const d=new URLSearchParams(window.location.search).get("view");return d==="new"||d==="deploy"||d==="github"?d:"projects"}function V(){const[b,d]=s.useState(null),[a,N]=s.useState(null),[i,k]=s.useState(B),[l,u]=s.useState(!1),[v,t]=s.useState(null);s.useEffect(()=>{Promise.all([fetch("/api/auth").then(r=>r.json()),fetch("/api/detect").then(r=>r.json())]).then(([r,f])=>{d({authenticated:r.authenticated,claudeAuthenticated:r.claudeAuthenticated}),N(f)})},[]);const y=async(r,f)=>{(await fetch("/api/auth",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({claudeToken:f})})).ok&&d({authenticated:!0,claudeAuthenticated:!0})},o=async r=>{if(r.projectName&&r.projectUrl)try{await fetch("/api/project-opened",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({projectName:r.projectName,projectUrl:r.projectUrl,projectRoot:r.projectRoot||`/home/user/${r.projectName}`})})}catch{}},[p,j]=s.useState(null),[m,c]=s.useState([]),g=async(r,f)=>{u(!0),t(null),j(null),c([]);try{const x=await fetch("/api/deploy",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:r,name:f})});if(!x.ok||!x.body){const C=await x.json();t(C.error||"Deploy failed");return}const w=x.body.getReader(),A=new TextDecoder;let S="";for(;;){const{done:C,value:F}=await w.read();if(C)break;S+=A.decode(F,{stream:!0});const U=S.split(`
|
|
1
|
+
import{r as s,j as e}from"./index-j26_mgI3.js";function I({onOpen:b}){const[d,a]=s.useState([]),[N,i]=s.useState(!0),[k,l]=s.useState(null),[u,v]=s.useState({}),t=async()=>{i(!0);try{const j=(await(await fetch("/api/projects")).json()).projects||[];a(j);const m={};await Promise.all(j.map(async c=>{try{const g=await fetch(`https://ooda.run/api/publish/${c.name}`);g.ok&&(m[c.name]=await g.json())}catch{}})),v(m)}catch{a([])}finally{i(!1)}};s.useEffect(()=>{t()},[]);const y=async o=>{if(confirm(`Delete project "${o}"? This cannot be undone.`)){l(o);try{const p=await fetch(`/api/projects/${o}`,{method:"DELETE"});if(!p.ok){const j=await p.json().catch(()=>({error:"Unknown error"}));alert(`Failed to delete project: ${j.error||p.statusText}`);return}a(j=>j.filter(m=>m.name!==o))}finally{l(null)}}};return N?e.jsx("div",{className:"text-center py-12 text-sm text-ink-faint",children:"Loading projects..."}):d.length===0?e.jsxs("div",{className:"text-center py-12",children:[e.jsx("p",{className:"text-ink-muted text-sm mb-1",children:"No projects yet"}),e.jsx("p",{className:"text-ink-faint text-xs",children:"Create a new project or deploy a local folder to get started."})]}):e.jsxs("div",{children:[e.jsx("h2",{className:"text-xs font-semibold text-ink uppercase tracking-widest mb-4",children:"Projects"}),e.jsx("div",{className:"space-y-2",children:d.map(o=>{const p=o.isOwn!==!1;return e.jsxs("div",{className:"flex items-center justify-between p-4 border border-border hover:border-ink-faint transition-colors",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("div",{className:`w-2 h-2 rounded-full ${o.status==="running"?"bg-green-500":o.status==="stopped"?"bg-border":"bg-yellow-500"}`}),e.jsxs("div",{children:[e.jsx("p",{className:"text-sm font-medium text-ink",children:o.name}),e.jsxs("p",{className:"text-xs text-ink-faint font-mono mt-0.5",children:[o.owner&&e.jsxs("span",{children:[o.owner,o.isOwn&&e.jsx("span",{className:"text-ink-muted ml-1",children:"(you)"}),o.url&&e.jsx("span",{className:"mx-1",children:"·"})]}),o.url&&o.url]})]})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[u[o.name]&&e.jsx("a",{href:u[o.name].latestUrl,target:"_blank",rel:"noopener noreferrer",className:"px-3 py-1.5 text-sm font-medium text-green-700 bg-green-50 hover:bg-green-100 transition-colors",children:"Published"}),p&&o.url&&e.jsx("button",{onClick:()=>b({name:o.name,url:o.url}),className:"px-3 py-1.5 text-sm font-medium text-ink-muted bg-border/50 hover:bg-border transition-colors",children:"Open"}),p&&e.jsx("button",{onClick:()=>y(o.name),disabled:k===o.name,className:"px-3 py-1.5 text-sm text-ink-faint hover:text-ink transition-colors disabled:opacity-50",children:k===o.name?"...":"Delete"})]})]},o.name)})})]})}function G({onCreate:b,deploying:d}){const[a,N]=s.useState([]),[i,k]=s.useState(""),[l,u]=s.useState(null);s.useEffect(()=>{fetch("/api/templates").then(t=>t.json()).then(t=>{var y;N(t.templates||[]),((y=t.templates)==null?void 0:y.length)>0&&u(t.templates[0].id)})},[]);const v=t=>{t.preventDefault(),!(!i.trim()||!l)&&b(i.trim(),l)};return e.jsxs("div",{children:[e.jsx("h2",{className:"text-xs font-semibold text-ink uppercase tracking-widest mb-4",children:"Create new project"}),e.jsxs("form",{onSubmit:v,className:"max-w-lg space-y-6",children:[e.jsxs("div",{children:[e.jsx("label",{htmlFor:"project-name",className:"block text-sm font-medium text-ink-muted mb-1.5",children:"Project name"}),e.jsx("input",{id:"project-name",type:"text",value:i,onChange:t=>k(t.target.value),placeholder:"my-project",className:"w-full px-3 py-2 border border-border text-sm focus:outline-none focus:ring-2 focus:ring-ink focus:border-transparent"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-sm font-medium text-ink-muted mb-3",children:"Template"}),e.jsx("div",{className:"space-y-2",children:a.map(t=>e.jsxs("label",{className:`flex items-start gap-3 p-4 border cursor-pointer transition-colors ${l===t.id?"border-ink bg-surface":"border-border hover:border-border"}`,children:[e.jsx("input",{type:"radio",name:"template",value:t.id,checked:l===t.id,onChange:()=>u(t.id),className:"mt-0.5"}),e.jsxs("div",{children:[e.jsx("p",{className:"text-sm font-medium text-ink",children:t.name}),e.jsx("p",{className:"text-xs text-ink-muted mt-0.5",children:t.description})]})]},t.id))})]}),e.jsx("button",{type:"submit",disabled:!i.trim()||!l||d,className:"px-6 py-2 bg-ink text-surface text-sm font-medium hover:bg-ink/80 disabled:opacity-50 disabled:cursor-not-allowed transition-colors",children:d?"Creating...":"Create project"})]})]})}function H({onDeploy:b,deploying:d}){const[a,N]=s.useState(null),[i,k]=s.useState(null),[l,u]=s.useState(!0),[v,t]=s.useState(!1),[y,o]=s.useState(""),[p,j]=s.useState(""),m=s.useCallback(async c=>{u(!0);try{const g=c?`?path=${encodeURIComponent(c)}`:"",D=await fetch(`/api/browse${g}`);if(!D.ok)throw new Error;const P=await D.json();N(P),k(null),t(!1)}catch{t(!0)}finally{u(!1)}},[]);return s.useEffect(()=>{m()},[m]),v?e.jsxs("div",{children:[e.jsx("h2",{className:"text-xs font-semibold text-ink uppercase tracking-widest mb-4",children:"Deploy a folder"}),e.jsxs("div",{className:"max-w-lg space-y-4",children:[e.jsxs("div",{children:[e.jsx("label",{htmlFor:"project-name-fallback",className:"block text-sm font-medium text-ink-muted mb-1.5",children:"Project name"}),e.jsx("input",{id:"project-name-fallback",type:"text",value:p,onChange:c=>j(c.target.value),placeholder:"Defaults to folder name",className:"w-full px-3 py-2 border border-border text-sm focus:outline-none focus:ring-2 focus:ring-ink focus:border-transparent"})]}),e.jsxs("div",{children:[e.jsx("label",{htmlFor:"folder-path",className:"block text-sm font-medium text-ink-muted mb-1.5",children:"Folder path"}),e.jsx("input",{id:"folder-path",type:"text",value:y,onChange:c=>o(c.target.value),placeholder:"Leave empty to deploy the current directory",className:"w-full px-3 py-2 border border-border text-sm focus:outline-none focus:ring-2 focus:ring-ink focus:border-transparent"}),e.jsx("p",{className:"mt-1.5 text-xs text-ink-faint",children:"Absolute path to a project folder with a package.json."})]}),e.jsx("button",{onClick:()=>b(y.trim()||void 0,p.trim()||void 0),disabled:d,className:"px-6 py-2 bg-ink text-surface text-sm font-medium hover:bg-ink/80 disabled:opacity-50 disabled:cursor-not-allowed transition-colors",children:d?"Deploying...":"Deploy"})]})]}):e.jsxs("div",{children:[e.jsx("h2",{className:"text-xs font-semibold text-ink uppercase tracking-widest mb-4",children:"Deploy a folder"}),e.jsxs("div",{className:"max-w-lg space-y-3",children:[a&&e.jsxs("div",{className:"flex items-center gap-2 text-xs text-ink-muted",children:[a.parent&&e.jsx("button",{onClick:()=>m(a.parent),disabled:l,className:"px-2 py-0.5 font-medium text-ink-muted bg-border/50 border border-border hover:bg-border disabled:opacity-30 transition-colors",children:"←"}),e.jsx("span",{className:"font-mono truncate",children:a.current})]}),e.jsx("div",{className:"border border-border overflow-hidden",children:l&&!a?e.jsx("div",{className:"px-3 py-8 text-center text-sm text-ink-faint",children:"Loading..."}):e.jsxs("div",{className:"max-h-72 overflow-y-auto",children:[(a==null?void 0:a.entries.length)===0&&e.jsx("div",{className:"px-3 py-8 text-center text-sm text-ink-faint",children:"No subfolders"}),a==null?void 0:a.entries.map(c=>{const g=i===c.path;return e.jsxs("button",{type:"button",className:`w-full flex items-center gap-2.5 px-3 py-2 text-left border-b border-border/30 last:border-0 transition-colors ${g?"bg-ink text-surface":"hover:bg-border/30"}`,onClick:()=>k(g?null:c.path),onDoubleClick:()=>m(c.path),children:[e.jsx("span",{className:"text-sm flex-shrink-0",children:c.hasPackageJson?"📦":"📁"}),e.jsx("span",{className:`text-sm truncate ${g?"text-surface font-medium":"text-ink"}`,children:c.name}),c.hasPackageJson&&e.jsx("span",{className:`ml-auto text-[11px] flex-shrink-0 ${g?"text-ink-faint":"text-ink-muted"}`,children:"project"})]},c.path)})]})}),e.jsxs("div",{children:[e.jsx("label",{htmlFor:"project-name",className:"block text-sm font-medium text-ink-muted mb-1.5",children:"Project name"}),e.jsx("input",{id:"project-name",type:"text",value:p,onChange:c=>j(c.target.value),placeholder:"Defaults to folder name",className:"w-full px-3 py-2 border border-border text-sm focus:outline-none focus:ring-2 focus:ring-ink focus:border-transparent"})]}),e.jsxs("div",{className:"flex items-center gap-3 pt-1",children:[e.jsx("button",{onClick:()=>b(i||void 0,p.trim()||void 0),disabled:d||!i,className:"px-6 py-2 bg-ink text-surface text-sm font-medium hover:bg-ink/80 disabled:opacity-50 disabled:cursor-not-allowed transition-colors",children:d?"Deploying...":"Deploy"}),e.jsx("span",{className:"text-xs text-ink-faint",children:i?e.jsx("span",{className:"font-mono text-ink-muted",children:i}):"Click to select, double-click to open"})]})]})]})}function M({onDeploy:b,deploying:d}){const[a,N]=s.useState(""),[i,k]=s.useState(""),[l,u]=s.useState([]),[v,t]=s.useState(null),[y,o]=s.useState(null),[p,j]=s.useState(!0),[m,c]=s.useState("");s.useEffect(()=>{fetch("/api/github-repos").then(n=>n.json()).then(n=>{u(n.repos),t(n.authenticated),o(n.username||null)}).catch(()=>t(!1)).finally(()=>j(!1))},[]);const g=()=>{const n=a.trim();n&&b(n,i.trim()||void 0)},D=n=>{N(n.fullName),k("")},P=m?l.filter(n=>n.fullName.toLowerCase().includes(m.toLowerCase())||n.description&&n.description.toLowerCase().includes(m.toLowerCase())):l;return e.jsxs("div",{children:[e.jsxs("h2",{className:"text-xs font-semibold text-ink uppercase tracking-widest mb-4",children:["Clone from GitHub",y&&e.jsxs("span",{className:"text-ink-faint font-normal normal-case tracking-normal ml-2",children:["signed in as ",y]})]}),e.jsxs("div",{className:"max-w-lg space-y-4",children:[e.jsxs("div",{children:[e.jsx("label",{htmlFor:"github-url",className:"block text-sm font-medium text-ink-muted mb-1.5",children:"GitHub URL"}),e.jsx("input",{id:"github-url",type:"text",value:a,onChange:n=>N(n.target.value),onKeyDown:n=>n.key==="Enter"&&g(),placeholder:"owner/repo or https://github.com/owner/repo",className:"w-full px-3 py-2 border border-border text-sm focus:outline-none focus:ring-2 focus:ring-ink focus:border-transparent font-mono"}),e.jsx("p",{className:"mt-1.5 text-xs text-ink-faint",children:"Paste a URL, or pick from your repos below. Add #branch for a specific branch."})]}),v===!1&&e.jsxs("p",{className:"text-xs text-ink-muted",children:["No GitHub token detected. Run ",e.jsx("span",{className:"font-mono font-medium",children:"gh auth login"})," to see your repos here."]}),v&&e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between mb-1.5",children:[e.jsx("label",{className:"block text-sm font-medium text-ink-muted",children:"Your repos"}),l.length>5&&e.jsx("input",{type:"text",value:m,onChange:n=>c(n.target.value),placeholder:"Filter...",className:"px-2 py-1 border border-border text-xs focus:outline-none focus:ring-1 focus:ring-ink w-40"})]}),e.jsx("div",{className:"border border-border overflow-hidden",children:p?e.jsx("div",{className:"px-3 py-8 text-center text-sm text-ink-faint",children:"Loading repos..."}):P.length===0?e.jsx("div",{className:"px-3 py-8 text-center text-sm text-ink-faint",children:m?"No matching repos":"No repos found"}):e.jsx("div",{className:"max-h-64 overflow-y-auto",children:P.map(n=>{const $=a===n.fullName;return e.jsxs("button",{type:"button",className:`w-full flex items-center gap-2.5 px-3 py-2 text-left border-b border-border/30 last:border-0 transition-colors ${$?"bg-ink text-surface":"hover:bg-border/30"}`,onClick:()=>D(n),children:[e.jsx("span",{className:"text-sm flex-shrink-0",children:n.isPrivate?"🔒":"📦"}),e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsx("span",{className:`text-sm truncate block ${$?"text-surface font-medium":"text-ink"}`,children:n.fullName}),n.description&&e.jsx("span",{className:`text-xs truncate block ${$?"text-surface/60":"text-ink-faint"}`,children:n.description})]})]},n.fullName)})})})]}),e.jsxs("div",{children:[e.jsx("label",{htmlFor:"gh-project-name",className:"block text-sm font-medium text-ink-muted mb-1.5",children:"Project name"}),e.jsx("input",{id:"gh-project-name",type:"text",value:i,onChange:n=>k(n.target.value),onKeyDown:n=>n.key==="Enter"&&g(),placeholder:"Defaults to repo name",className:"w-full px-3 py-2 border border-border text-sm focus:outline-none focus:ring-2 focus:ring-ink focus:border-transparent"})]}),e.jsx("button",{onClick:g,disabled:d||!a.trim(),className:"px-6 py-2 bg-ink text-surface text-sm font-medium hover:bg-ink/80 disabled:opacity-50 disabled:cursor-not-allowed transition-colors",children:d?"Deploying...":"Clone & Deploy"})]})]})}function _({onLogin:b,authenticated:d}){const[a,N]=s.useState(""),[i,k]=s.useState(null),l=u=>{if(u.preventDefault(),!a.trim()){k("Please enter your Claude API key or OAuth token");return}k(null),b("",a.trim())};return e.jsx("div",{className:"min-h-screen bg-surface flex items-center justify-center",children:e.jsxs("div",{className:"w-full max-w-md p-8",children:[e.jsxs("div",{className:"text-center mb-8",children:[e.jsx("img",{src:"/logo.svg",alt:"ooda",className:"h-6 mx-auto mb-2"}),e.jsx("p",{className:"text-sm text-ink-muted",children:d?"Connect Claude to edit code on your cloud sandbox":"Sign in to manage cloud sandboxes"})]}),e.jsxs("form",{onSubmit:l,className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx("label",{htmlFor:"claude-token",className:"block text-sm font-medium text-ink-muted mb-1.5",children:"Claude API Key or OAuth Token"}),e.jsx("input",{id:"claude-token",type:"password",value:a,onChange:u=>N(u.target.value),placeholder:"sk-ant-... or oauth token",autoFocus:!0,className:"w-full px-3 py-2 border border-border text-sm focus:outline-none focus:ring-2 focus:ring-ink focus:border-transparent"}),e.jsxs("p",{className:"mt-1.5 text-xs text-ink-faint",children:[e.jsx("strong",{children:"API key"}),": get from"," ",e.jsx("a",{href:"https://console.anthropic.com/settings/keys",target:"_blank",rel:"noopener noreferrer",className:"text-ink-muted underline hover:text-ink",children:"console.anthropic.com"}),e.jsx("br",{}),e.jsx("strong",{children:"OAuth token"}),": run"," ",e.jsx("code",{className:"bg-border/50 px-1 text-xs font-mono",children:"claude setup-token"})," ","in your terminal (for Claude Pro/Teams)"]})]}),i&&e.jsx("p",{className:"text-sm text-red-600",children:i}),e.jsx("button",{type:"submit",className:"w-full px-4 py-2 bg-ink text-surface text-sm font-medium hover:bg-ink/80 transition-colors",children:"Sign in"})]})]})})}function B(){const d=new URLSearchParams(window.location.search).get("view");return d==="new"||d==="deploy"||d==="github"?d:"projects"}function V(){const[b,d]=s.useState(null),[a,N]=s.useState(null),[i,k]=s.useState(B),[l,u]=s.useState(!1),[v,t]=s.useState(null);s.useEffect(()=>{Promise.all([fetch("/api/auth").then(r=>r.json()),fetch("/api/detect").then(r=>r.json())]).then(([r,f])=>{d({authenticated:r.authenticated,claudeAuthenticated:r.claudeAuthenticated}),N(f)})},[]);const y=async(r,f)=>{(await fetch("/api/auth",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({claudeToken:f})})).ok&&d({authenticated:!0,claudeAuthenticated:!0})},o=async r=>{if(r.projectName&&r.projectUrl)try{await fetch("/api/project-opened",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({projectName:r.projectName,projectUrl:r.projectUrl,projectRoot:r.projectRoot||`/home/user/${r.projectName}`})})}catch{}},[p,j]=s.useState(null),[m,c]=s.useState([]),g=async(r,f)=>{u(!0),t(null),j(null),c([]);try{const x=await fetch("/api/deploy",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:r,name:f})});if(!x.ok||!x.body){const C=await x.json();t(C.error||"Deploy failed");return}const w=x.body.getReader(),A=new TextDecoder;let S="";for(;;){const{done:C,value:F}=await w.read();if(C)break;S+=A.decode(F,{stream:!0});const U=S.split(`
|
|
2
2
|
|
|
3
3
|
`);S=U.pop()||"";for(const T of U){const O=T.match(/^event: (.+)$/m),E=T.match(/^data: (.+)$/m);if(!O||!E)continue;const L=O[1],h=JSON.parse(E[1]);if(L==="progress"){const R=h.detail?`${h.step} (${h.detail})`:h.step;c(J=>[...J,R])}else L==="done"&&(h.success&&h.projectUrl?j({projectName:h.projectName,projectUrl:h.projectUrl}):t(h.error||"Deploy failed"))}}}catch(x){t(x instanceof Error?x.message:"Deploy failed")}finally{u(!1)}},D=async(r,f)=>{u(!0),t(null),j(null),c([]);try{const x=await fetch("/api/deploy-github",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({url:r,name:f})});if(!x.ok||!x.body){const C=await x.json();t(C.error||"Deploy failed");return}const w=x.body.getReader(),A=new TextDecoder;let S="";for(;;){const{done:C,value:F}=await w.read();if(C)break;S+=A.decode(F,{stream:!0});const U=S.split(`
|
|
4
4
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{r as i,j as e}from"./index-j26_mgI3.js";import{g as E,a as I,c as y,i as N,b as O,d as L}from"./api-nNV-WJu1.js";import{u as D,D as P}from"./router-BvUnq6R0.js";function g(x){const o=Date.now()-new Date(x).getTime(),n=Math.floor(o/6e4);if(n<1)return"just now";if(n<60)return`${n}m ago`;const m=Math.floor(n/60);return m<24?`${m}h ago`:`${Math.floor(m/24)}d ago`}function w({orgId:x,value:o,onSaved:n}){const[m,r]=i.useState(!1),[h,f]=i.useState(String(o)),[s,c]=i.useState(!1),[j,a]=i.useState(!1),u=async()=>{const t=parseInt(h,10);if(!Number.isInteger(t)||t<0){a(!0);return}c(!0),a(!1);try{(await L(x,{maxProjects:t})).ok?(n(t),r(!1)):a(!0)}catch{a(!0)}finally{c(!1)}};return m?e.jsxs("span",{className:"inline-flex items-center gap-1",children:[e.jsx("input",{type:"number",min:0,value:h,autoFocus:!0,onChange:t=>f(t.target.value),onKeyDown:t=>{t.key==="Enter"&&u(),t.key==="Escape"&&r(!1)},className:`w-16 text-sm px-2 py-1 border bg-surface text-ink focus:outline-none focus:border-ink ${j?"border-red-500":"border-border"}`}),e.jsx("button",{onClick:u,disabled:s,className:"text-xs bg-ink text-surface px-2 py-1 disabled:opacity-50",children:s?"…":"Save"}),e.jsx("button",{onClick:()=>r(!1),className:"text-xs text-ink-muted hover:text-ink px-1",children:"Cancel"})]}):e.jsxs("button",{onClick:()=>{f(String(o)),r(!0)},className:"text-sm text-ink-muted hover:text-ink transition-colors",title:"Edit project limit",children:[o," ",e.jsx("span",{className:"text-ink-faint",children:"✎"})]})}function $({onCreated:x,onCancel:o}){const[n,m]=i.useState(""),[r,h]=i.useState(""),[f,s]=i.useState(""),[c,j]=i.useState([]),[a,u]=i.useState(null),[t,d]=i.useState(!1),[b,S]=i.useState(null),k=()=>{const l=f.trim().toLowerCase();!l||!l.includes("@")||c.includes(l)||(j([...c,l]),s(""))},C=l=>{j(c.filter(p=>p!==l))},A=async l=>{if(l.preventDefault(),c.length===0){u("Add at least one admin email");return}u(null),d(!0);try{const p=await N("/orgs",{method:"POST",body:JSON.stringify({orgId:n,orgName:r||n,adminEmails:c})}),v=await p.json();if(!p.ok){u(v.error||"Failed to create org");return}S(v)}catch{u("Could not reach the server")}finally{d(!1)}};return b?e.jsxs("div",{className:"border border-border p-6 mb-6 bg-white",children:[e.jsx("h3",{className:"text-sm font-medium text-ink mb-4",children:"Organisation created"}),e.jsxs("p",{className:"text-sm text-ink-muted mb-3",children:[e.jsx("span",{className:"font-medium text-ink",children:r||n})," ",e.jsxs("span",{className:"text-ink-faint",children:["(",n,")"]})]}),e.jsx("div",{className:"space-y-1 mb-4",children:b.invites.map(l=>e.jsxs("p",{className:"text-sm text-ink-muted",children:[l.email," — ",l.emailSent?"invite sent":"invite created (email not sent)"]},l.email))}),e.jsx("button",{onClick:x,className:"px-4 py-2 bg-ink text-surface text-sm font-medium hover:bg-ink/80 transition-colors",children:"Done"})]}):e.jsxs("form",{onSubmit:A,className:"border border-border p-6 mb-6 bg-white",children:[e.jsxs("div",{className:"flex items-center justify-between mb-4",children:[e.jsx("h3",{className:"text-sm font-medium text-ink",children:"Create organisation"}),e.jsx("button",{type:"button",onClick:o,className:"text-xs text-ink-muted hover:text-ink transition-colors",children:"Cancel"})]}),e.jsxs("div",{className:"grid grid-cols-2 gap-4 mb-4",children:[e.jsxs("div",{children:[e.jsx("label",{htmlFor:"orgId",className:"block text-xs font-medium text-ink-muted mb-1",children:"Org ID (slug)"}),e.jsx("input",{id:"orgId",type:"text",value:n,onChange:l=>m(l.target.value.toLowerCase().replace(/[^a-z0-9-]/g,"-")),required:!0,placeholder:"wise-workshop",className:"w-full px-3 py-2 border border-border text-sm bg-white focus:outline-none focus:ring-2 focus:ring-ink focus:border-transparent"})]}),e.jsxs("div",{children:[e.jsx("label",{htmlFor:"orgName",className:"block text-xs font-medium text-ink-muted mb-1",children:"Display name"}),e.jsx("input",{id:"orgName",type:"text",value:r,onChange:l=>h(l.target.value),placeholder:n||"Wise Workshop",className:"w-full px-3 py-2 border border-border text-sm bg-white focus:outline-none focus:ring-2 focus:ring-ink focus:border-transparent"})]})]}),e.jsxs("div",{className:"mb-4",children:[e.jsx("label",{className:"block text-xs font-medium text-ink-muted mb-1",children:"Admin emails"}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx("input",{type:"email",value:f,onChange:l=>s(l.target.value),onKeyDown:l=>{l.key==="Enter"&&(l.preventDefault(),k())},placeholder:"admin@example.com",className:"flex-1 px-3 py-2 border border-border text-sm bg-white focus:outline-none focus:ring-2 focus:ring-ink focus:border-transparent"}),e.jsx("button",{type:"button",onClick:k,className:"px-3 py-2 border border-border text-sm text-ink-muted hover:text-ink hover:border-ink transition-colors",children:"Add"})]}),c.length>0&&e.jsx("div",{className:"flex flex-wrap gap-2 mt-2",children:c.map(l=>e.jsxs("span",{className:"inline-flex items-center gap-1 px-2 py-1 bg-surface-alt text-sm text-ink",children:[l,e.jsx("button",{type:"button",onClick:()=>C(l),className:"text-ink-faint hover:text-ink ml-1",children:"×"})]},l))})]}),a&&e.jsx("p",{className:"text-sm text-red-600 mb-4",children:a}),e.jsx("button",{type:"submit",disabled:t||!n||c.length===0,className:"px-4 py-2 bg-ink text-surface text-sm font-medium hover:bg-ink/80 transition-colors disabled:opacity-50",children:t?"Creating...":"Create organisation"})]})}function R({onOpenOrg:x}){const[o,n]=i.useState([]),[m,r]=i.useState(!0),[h,f]=i.useState(null),[s,c]=i.useState(!1),j=async()=>{r(!0);try{const a=await N("/orgs");if(!a.ok){f(a.status===401?"Not authorized (requires internal admin)":"Failed to load orgs");return}const u=await a.json();n(u.orgs||[])}catch{f("Could not reach the server")}finally{r(!1)}};return i.useEffect(()=>{j()},[]),m?e.jsx("p",{className:"text-sm text-ink-muted",children:"Loading orgs..."}):h?e.jsx("p",{className:"text-sm text-red-600",children:h}):e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between mb-4",children:[e.jsxs("h2",{className:"text-lg font-medium text-ink",children:["Organisations",e.jsx("span",{className:"text-ink-faint font-normal ml-2",children:o.length})]}),e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("button",{onClick:()=>c(!0),className:"px-3 py-1.5 bg-ink text-surface text-xs font-medium hover:bg-ink/80 transition-colors",children:"Create org"}),e.jsx("button",{onClick:j,className:"text-xs text-ink-muted hover:text-ink transition-colors",children:"Refresh"})]})]}),s&&e.jsx($,{onCreated:()=>{c(!1),j()},onCancel:()=>c(!1)}),o.length===0?e.jsx("div",{className:"border border-border py-12 text-center",children:e.jsx("p",{className:"text-sm text-ink-muted",children:"No organisations yet"})}):e.jsxs("div",{className:"border border-border divide-y divide-border",children:[e.jsxs("div",{className:"grid grid-cols-6 gap-4 px-4 py-2 text-xs font-medium text-ink-muted bg-surface-alt",children:[e.jsx("span",{className:"col-span-2",children:"Name"}),e.jsx("span",{children:"Projects"}),e.jsx("span",{children:"Members"}),e.jsx("span",{children:"Limit"}),e.jsx("span",{children:"Created"})]}),o.map(a=>e.jsxs("div",{className:"grid grid-cols-6 gap-4 px-4 py-3 items-center",children:[e.jsxs("button",{onClick:()=>x(a.id),className:"col-span-2 text-left group",children:[e.jsx("p",{className:"text-sm font-medium text-ink group-hover:underline",children:a.name}),e.jsx("p",{className:"text-xs text-ink-faint",children:a.id})]}),e.jsx("span",{className:"text-sm text-ink",children:a.projectCount}),e.jsx("span",{className:"text-sm text-ink",children:a.memberCount}),e.jsx("span",{className:"text-sm",children:e.jsx(w,{orgId:a.id,value:a.maxProjects,onSaved:u=>n(t=>t.map(d=>d.id===a.id?{...d,maxProjects:u}:d))})}),e.jsx("span",{className:"text-xs text-ink-faint",title:a.createdAt,children:g(a.createdAt)})]},a.id))]})]})}function F({orgId:x,subtab:o,onSubtab:n,onBack:m}){const[r,h]=i.useState(null),[f,s]=i.useState(!0),[c,j]=i.useState(null),a=async()=>{s(!0);try{const t=await O(x);if(!t.ok){j(t.status===404?"Org not found":"Failed to load org");return}h(await t.json())}catch{j("Could not reach the server")}finally{s(!1)}};if(i.useEffect(()=>{a()},[x]),f)return e.jsx("p",{className:"text-sm text-ink-muted",children:"Loading org..."});if(c)return e.jsx("p",{className:"text-sm text-red-600",children:c});if(!r)return null;const u=[["members","Members",r.members.length],["projects","Projects",r.projects.length],["sites","Published sites",r.sites.length]];return e.jsxs("div",{children:[e.jsxs("div",{children:[e.jsx("button",{onClick:m,className:"text-xs text-ink-muted hover:text-ink transition-colors mb-3",children:"← All organisations"}),e.jsxs("div",{className:"flex items-end justify-between",children:[e.jsxs("div",{children:[e.jsx("h2",{className:"text-lg font-medium text-ink",children:r.org.name}),e.jsx("p",{className:"text-xs text-ink-faint",children:r.org.id})]}),e.jsxs("div",{className:"text-right",children:[e.jsx("p",{className:"text-xs text-ink-faint mb-0.5",children:"Project limit"}),e.jsx(w,{orgId:r.org.id,value:r.org.maxProjects,onSaved:t=>h(d=>d&&{...d,org:{...d.org,maxProjects:t}})})]})]})]}),e.jsx("div",{className:"border-b border-border mt-5 mb-5",children:e.jsx("nav",{className:"flex gap-6",children:u.map(([t,d,b])=>e.jsxs("button",{onClick:()=>n(t),className:`py-2 text-sm font-medium border-b-2 transition-colors ${o===t?"border-ink text-ink":"border-transparent text-ink-muted hover:text-ink"}`,children:[d,e.jsx("span",{className:"text-ink-faint font-normal ml-1.5",children:b})]},t))})}),o==="members"&&(r.members.length===0?e.jsx("p",{className:"text-sm text-ink-muted",children:"No members."}):e.jsx("div",{className:"border border-border divide-y divide-border",children:r.members.map(t=>e.jsxs("div",{className:"flex items-center justify-between px-4 py-2",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-sm text-ink",children:t.name||t.email}),e.jsx("p",{className:"text-xs text-ink-faint",children:t.email})]}),e.jsx("span",{className:`text-xs px-2 py-0.5 ${t.role==="admin"?"bg-ink text-surface":"bg-border text-ink-muted"}`,children:t.role})]}),e.jsx("span",{className:"text-xs text-ink-faint",children:new Date(t.joinedAt).toLocaleDateString()})]},t.email))})),o==="projects"&&(r.projects.length===0?e.jsx("p",{className:"text-sm text-ink-muted",children:"No projects."}):e.jsx("div",{className:"border border-border divide-y divide-border",children:r.projects.map(t=>e.jsxs("div",{className:"flex items-center justify-between px-4 py-2",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("p",{className:"text-sm text-ink",children:t.name}),e.jsx("p",{className:"text-xs text-ink-faint truncate",children:t.ownerEmail||"—"})]}),e.jsx("span",{className:"text-xs text-ink-faint shrink-0",title:t.lastActiveAt||t.createdAt,children:t.lastActiveAt?`active ${g(t.lastActiveAt)}`:`created ${g(t.createdAt)}`})]},t.name))})),o==="sites"&&(r.sites.length===0?e.jsx("p",{className:"text-sm text-ink-muted",children:"No published sites."}):e.jsx("div",{className:"border border-border divide-y divide-border",children:r.sites.map(t=>e.jsxs("div",{className:"flex items-center justify-between px-4 py-2",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsxs("p",{className:"text-sm text-ink",children:[t.slug,t.projectName?e.jsxs("span",{className:"ml-2 text-xs text-ink-muted border border-border px-1.5 py-0.5",children:["project: ",t.projectName]}):e.jsx("span",{className:"ml-2 text-xs text-ink-faint border border-border border-dashed px-1.5 py-0.5",children:"deployed from local"})]}),e.jsx("a",{href:t.url,target:"_blank",rel:"noopener noreferrer",className:"text-xs text-ink-faint hover:text-ink truncate block",children:t.url})]}),e.jsx("span",{className:"text-xs text-ink-faint shrink-0",title:t.publishedAt,children:g(t.publishedAt)})]},t.slug))}))]})}function T(){const[x,o]=i.useState([]),[n,m]=i.useState(!0),[r,h]=i.useState(null),f=async()=>{m(!0);try{const s=await N("/projects");if(!s.ok){h(s.status===401?"Not authorized (requires internal admin)":"Failed to load projects");return}const c=await s.json();o(c.projects||[])}catch{h("Could not reach the server")}finally{m(!1)}};return i.useEffect(()=>{f()},[]),n?e.jsx("p",{className:"text-sm text-ink-muted",children:"Loading projects..."}):r?e.jsx("p",{className:"text-sm text-red-600",children:r}):e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between mb-4",children:[e.jsxs("h2",{className:"text-lg font-medium text-ink",children:["All Projects",e.jsx("span",{className:"text-ink-faint font-normal ml-2",children:x.length})]}),e.jsx("button",{onClick:f,className:"text-xs text-ink-muted hover:text-ink transition-colors",children:"Refresh"})]}),x.length===0?e.jsx("div",{className:"border border-border py-12 text-center",children:e.jsx("p",{className:"text-sm text-ink-muted",children:"No projects across any org"})}):e.jsxs("div",{className:"border border-border divide-y divide-border",children:[e.jsxs("div",{className:"grid grid-cols-5 gap-4 px-4 py-2 text-xs font-medium text-ink-muted bg-surface-alt",children:[e.jsx("span",{children:"Project"}),e.jsx("span",{children:"Org"}),e.jsx("span",{children:"Owner"}),e.jsx("span",{children:"Last Active"}),e.jsx("span",{children:"Created"})]}),x.map(s=>e.jsxs("div",{className:"grid grid-cols-5 gap-4 px-4 py-3 items-center",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-sm font-medium text-ink",children:s.name}),s.previewUrl&&e.jsx("a",{href:s.previewUrl,target:"_blank",rel:"noopener noreferrer",className:"text-xs text-blue-600 hover:underline truncate block",children:"preview"})]}),e.jsxs("div",{children:[e.jsx("p",{className:"text-sm text-ink",children:s.orgName||s.orgId}),s.orgName&&e.jsx("p",{className:"text-xs text-ink-faint",children:s.orgId})]}),e.jsx("span",{className:"text-sm text-ink-muted truncate",children:s.ownerEmail||"—"}),e.jsx("span",{className:"text-xs text-ink-muted",title:s.lastActiveAt||"",children:s.lastActiveAt?g(s.lastActiveAt):"—"}),e.jsx("span",{className:"text-xs text-ink-faint",title:s.createdAt,children:g(s.createdAt)})]},`${s.orgId}/${s.name}`))]})]})}const U=[{key:"orgs",label:"Organisations"},{key:"projects",label:"All Projects"}],_=["members","projects","sites"];function M(x){const n=x.replace(/^\/internal/,"").replace(/^\/+/,"").split("/").filter(Boolean);if(n[0]==="projects")return{tab:"projects",orgId:null,orgSubtab:"members"};if(n[0]==="orgs"&&n[1]){const m=_.includes(n[2])?n[2]:"members";return{tab:"orgs",orgId:decodeURIComponent(n[1]),orgSubtab:m}}return{tab:"orgs",orgId:null,orgSubtab:"members"}}function K(){const[x,o]=i.useState(null),[n,m]=i.useState(!1),[r,h]=i.useState(!0),{path:f,navigate:s}=D(),c=async()=>(await N("/orgs")).ok;i.useEffect(()=>{(async()=>{if(!E()){h(!1);return}const b=await I();b?(o({email:b.user.email,name:b.user.name}),m(await c())):y(),h(!1)})()},[]);const j=()=>{y(),o(null),m(!1)};if(r)return e.jsx("div",{className:"min-h-screen bg-surface flex items-center justify-center",children:e.jsx("p",{className:"text-sm text-ink-muted",children:"Loading..."})});if(!x||!n)return e.jsx("div",{className:"min-h-screen bg-surface flex items-center justify-center",children:e.jsx("p",{className:"text-sm text-ink-muted",children:"404 — Not found"})});const{tab:a,orgId:u,orgSubtab:t}=M(f);return e.jsxs(P,{brand:"Internal",nav:U,activeKey:a,onNavigate:d=>s(`/internal/${d}`),onBrandClick:()=>s("/internal/orgs"),user:x,onLogout:j,children:[a==="orgs"&&u&&e.jsx(F,{orgId:u,subtab:t,onSubtab:d=>s(`/internal/orgs/${encodeURIComponent(u)}/${d}`),onBack:()=>s("/internal/orgs")}),a==="orgs"&&!u&&e.jsx(R,{onOpenOrg:d=>s(`/internal/orgs/${encodeURIComponent(d)}`)}),a==="projects"&&e.jsx(T,{})]})}export{K as InternalDashboard};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{r as n,j as e}from"./index-
|
|
1
|
+
import{r as n,j as e}from"./index-j26_mgI3.js";import{g as c,a as f,r as m,s as d,A as l}from"./api-nNV-WJu1.js";import{p as h,A as x}from"./AdminLogin-BYZ4BJQb.js";function A(){const s=h(window.location.search),[r,i]=n.useState(s?"checking":"bad-return"),a=n.useRef(null);return n.useEffect(()=>{if(!s)return;let t=!1;return(async()=>c()&&(await f()||await m())?t||i("ready"):t||i("login"))(),()=>{t=!0}},[s]),n.useEffect(()=>{var t;r==="ready"&&((t=a.current)==null||t.submit())},[r]),r==="bad-return"?e.jsx("div",{className:"min-h-screen bg-surface flex items-center justify-center",children:e.jsx("p",{className:"text-sm text-red-600",children:"Invalid or missing sign-in target."})}):r==="login"?e.jsx(x,{onLogin:(t,g,u,o)=>{d(u,o),i("ready")}}):e.jsxs("div",{className:"min-h-screen bg-surface flex items-center justify-center",children:[e.jsx("p",{className:"text-sm text-ink-muted",children:"Signing you in…"}),e.jsxs("form",{ref:a,method:"POST",action:`${l}/site-auth`,className:"hidden",children:[e.jsx("input",{type:"hidden",name:"jwt",value:c()??""}),e.jsx("input",{type:"hidden",name:"return",value:s??""})]})]})}export{A as SiteAuth};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const r="https://api.ooda.run",c="ooda-access-token",i="ooda-refresh-token";function s(){return localStorage.getItem(c)}function f(){return localStorage.getItem(i)}function d(t,e){localStorage.setItem(c,t),localStorage.setItem(i,e)}function l(){localStorage.removeItem(c),localStorage.removeItem(i)}async function u(){const t=f();if(!t)return!1;const e=await fetch(`${r}/auth/refresh`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:t})});if(!e.ok)return!1;const n=await e.json();return d(n.accessToken,n.refreshToken),!0}async function g(){const t=s();if(!t)return null;let e=await fetch(`${r}/auth/me`,{headers:{Authorization:`Bearer ${t}`}});if(e.status===401){if(!await u())return null;e=await fetch(`${r}/auth/me`,{headers:{Authorization:`Bearer ${s()}`}})}return e.ok?e.json():null}async function y(t){await fetch(`${r}/auth/forgot-password`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({email:t})})}async function $(t,e){const n=await fetch(`${r}/auth/reset-password`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({token:t,password:e})}),a=await n.json();return{ok:n.ok,...a}}async function T(t,e,n){const a=s(),o=new Headers(n==null?void 0:n.headers);return a&&o.set("Authorization",`Bearer ${a}`),o.set("Content-Type","application/json"),fetch(`${r}/org/${t}/admin${e}`,{...n,headers:o})}async function h(t,e){const n=s(),a=new Headers(e==null?void 0:e.headers);return n&&a.set("Authorization",`Bearer ${n}`),a.set("Content-Type","application/json"),fetch(`${r}/int${t}`,{...e,headers:a})}async function k(t){return h(`/orgs/${encodeURIComponent(t)}`)}async function m(t,e){return h(`/orgs/${encodeURIComponent(t)}`,{method:"PATCH",body:JSON.stringify(e)})}async function S(t,e,n){const a=s(),o=new Headers(n==null?void 0:n.headers);return a&&o.set("Authorization",`Bearer ${a}`),o.set("Content-Type","application/json"),fetch(`${r}/org/${t}/dashboard${e}`,{...n,headers:o})}export{r as A,g as a,k as b,l as c,m as d,T as e,S as f,s as g,y as h,h as i,$ as j,u as r,d as s};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/*! tailwindcss v4.2.1 | MIT License | https://tailwindcss.com */@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-space-y-reverse:0;--tw-divide-y-reverse:0;--tw-border-style:solid;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial}}}@layer theme{:root,:host{--font-sans:"Geist", ui-sans-serif, system-ui, -apple-system, sans-serif;--font-mono:"Geist Mono", ui-monospace, "SFMono-Regular", monospace;--color-red-100:oklch(93.6% .032 17.717);--color-red-500:oklch(63.7% .237 25.331);--color-red-600:oklch(57.7% .245 27.325);--color-red-700:oklch(50.5% .213 27.518);--color-red-800:oklch(44.4% .177 26.899);--color-orange-100:oklch(95.4% .038 75.164);--color-orange-800:oklch(47% .157 37.304);--color-amber-600:oklch(66.6% .179 58.318);--color-amber-800:oklch(47.3% .137 46.201);--color-yellow-100:oklch(97.3% .071 103.193);--color-yellow-500:oklch(79.5% .184 86.047);--color-yellow-800:oklch(47.6% .114 61.907);--color-green-50:oklch(98.2% .018 155.826);--color-green-100:oklch(96.2% .044 156.743);--color-green-400:oklch(79.2% .209 151.711);--color-green-500:oklch(72.3% .219 149.579);--color-green-600:oklch(62.7% .194 149.214);--color-green-700:oklch(52.7% .154 150.069);--color-green-800:oklch(44.8% .119 151.328);--color-blue-600:oklch(54.6% .245 262.881);--color-gray-50:oklch(98.5% .002 247.839);--color-gray-100:oklch(96.7% .003 264.542);--color-gray-600:oklch(44.6% .03 256.802);--color-white:#fff;--spacing:.25rem;--container-sm:24rem;--container-md:28rem;--container-lg:32rem;--container-4xl:56rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--tracking-normal:0em;--tracking-widest:.1em;--animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--blur-sm:8px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--color-surface:#ebf1e5;--color-ink:#272725;--color-ink-muted:#5a5a56;--color-ink-faint:#8a8a84;--color-border:#cdd4c7}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;-moz-tab-size:4;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){-webkit-appearance:button;-moz-appearance:button;appearance:button}::file-selector-button{-webkit-appearance:button;-moz-appearance:button;appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.sticky{position:sticky}.inset-y-0{inset-block:calc(var(--spacing) * 0)}.start{inset-inline-start:var(--spacing)}.top-0{top:calc(var(--spacing) * 0)}.right-0{right:calc(var(--spacing) * 0)}.bottom-0{bottom:calc(var(--spacing) * 0)}.bottom-full{bottom:100%}.left-0{left:calc(var(--spacing) * 0)}.z-10{z-index:10}.z-20{z-index:20}.col-span-2{grid-column:span 2/span 2}.mx-1{margin-inline:calc(var(--spacing) * 1)}.mx-auto{margin-inline:auto}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:calc(var(--spacing) * 1)}.mt-1\.5{margin-top:calc(var(--spacing) * 1.5)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-5{margin-top:calc(var(--spacing) * 5)}.mt-6{margin-top:calc(var(--spacing) * 6)}.mb-0\.5{margin-bottom:calc(var(--spacing) * .5)}.mb-1{margin-bottom:calc(var(--spacing) * 1)}.mb-1\.5{margin-bottom:calc(var(--spacing) * 1.5)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.mb-5{margin-bottom:calc(var(--spacing) * 5)}.mb-6{margin-bottom:calc(var(--spacing) * 6)}.mb-8{margin-bottom:calc(var(--spacing) * 8)}.ml-1{margin-left:calc(var(--spacing) * 1)}.ml-1\.5{margin-left:calc(var(--spacing) * 1.5)}.ml-2{margin-left:calc(var(--spacing) * 2)}.ml-3{margin-left:calc(var(--spacing) * 3)}.ml-auto{margin-left:auto}.block{display:block}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.h-2{height:calc(var(--spacing) * 2)}.h-3{height:calc(var(--spacing) * 3)}.h-5{height:calc(var(--spacing) * 5)}.h-6{height:calc(var(--spacing) * 6)}.h-7{height:calc(var(--spacing) * 7)}.h-12{height:calc(var(--spacing) * 12)}.h-14{height:calc(var(--spacing) * 14)}.h-full{height:100%}.max-h-60{max-height:calc(var(--spacing) * 60)}.max-h-64{max-height:calc(var(--spacing) * 64)}.max-h-72{max-height:calc(var(--spacing) * 72)}.min-h-screen{min-height:100vh}.w-2{width:calc(var(--spacing) * 2)}.w-3{width:calc(var(--spacing) * 3)}.w-5{width:calc(var(--spacing) * 5)}.w-7{width:calc(var(--spacing) * 7)}.w-16{width:calc(var(--spacing) * 16)}.w-24{width:calc(var(--spacing) * 24)}.w-40{width:calc(var(--spacing) * 40)}.w-56{width:calc(var(--spacing) * 56)}.w-full{width:100%}.max-w-4xl{max-width:var(--container-4xl)}.max-w-lg{max-width:var(--container-lg)}.max-w-md{max-width:var(--container-md)}.max-w-sm{max-width:var(--container-sm)}.min-w-0{min-width:calc(var(--spacing) * 0)}.min-w-\[14rem\]{min-width:14rem}.flex-1{flex:1}.flex-\[2\]{flex:2}.flex-shrink-0,.shrink-0{flex-shrink:0}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.animate-pulse{animation:var(--animate-pulse)}.cursor-default{cursor:default}.cursor-help{cursor:help}.cursor-pointer{cursor:pointer}.scroll-mt-6{scroll-margin-top:calc(var(--spacing) * 6)}.list-inside{list-style-position:inside}.list-disc{list-style-type:disc}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-5{grid-template-columns:repeat(5,minmax(0,1fr))}.grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-end{align-items:flex-end}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-1{gap:calc(var(--spacing) * 1)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-2\.5{gap:calc(var(--spacing) * 2.5)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-6{gap:calc(var(--spacing) * 6)}:where(.space-y-0\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * .5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * .5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 1) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 1) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-6>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 6) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 6) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-8>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 8) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 8) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-12>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 12) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 12) * calc(1 - var(--tw-space-y-reverse)))}:where(.divide-y>:not(:last-child)){--tw-divide-y-reverse:0;border-bottom-style:var(--tw-border-style);border-top-style:var(--tw-border-style);border-top-width:calc(1px * var(--tw-divide-y-reverse));border-bottom-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)))}:where(.divide-border>:not(:last-child)){border-color:var(--color-border)}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.rounded-full{border-radius:3.40282e38px}.border{border-style:var(--tw-border-style);border-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-b-2{border-bottom-style:var(--tw-border-style);border-bottom-width:2px}.border-l{border-left-style:var(--tw-border-style);border-left-width:1px}.border-l-2{border-left-style:var(--tw-border-style);border-left-width:2px}.border-dashed{--tw-border-style:dashed;border-style:dashed}.border-border{border-color:var(--color-border)}.border-border\/30{border-color:#cdd4c74d}@supports (color:color-mix(in lab,red,red)){.border-border\/30{border-color:color-mix(in oklab,var(--color-border) 30%,transparent)}}.border-ink{border-color:var(--color-ink)}.border-red-500{border-color:var(--color-red-500)}.border-transparent{border-color:#0000}.bg-border{background-color:var(--color-border)}.bg-border\/50{background-color:#cdd4c780}@supports (color:color-mix(in lab,red,red)){.bg-border\/50{background-color:color-mix(in oklab,var(--color-border) 50%,transparent)}}.bg-gray-100{background-color:var(--color-gray-100)}.bg-green-50{background-color:var(--color-green-50)}.bg-green-100{background-color:var(--color-green-100)}.bg-green-500{background-color:var(--color-green-500)}.bg-ink{background-color:var(--color-ink)}.bg-orange-100{background-color:var(--color-orange-100)}.bg-red-100{background-color:var(--color-red-100)}.bg-surface{background-color:var(--color-surface)}.bg-surface\/95{background-color:#ebf1e5f2}@supports (color:color-mix(in lab,red,red)){.bg-surface\/95{background-color:color-mix(in oklab,var(--color-surface) 95%,transparent)}}.bg-white{background-color:var(--color-white)}.bg-yellow-100{background-color:var(--color-yellow-100)}.bg-yellow-500{background-color:var(--color-yellow-500)}.p-2{padding:calc(var(--spacing) * 2)}.p-4{padding:calc(var(--spacing) * 4)}.p-6{padding:calc(var(--spacing) * 6)}.p-8{padding:calc(var(--spacing) * 8)}.px-1{padding-inline:calc(var(--spacing) * 1)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-6{padding-inline:calc(var(--spacing) * 6)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:calc(var(--spacing) * 1)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-8{padding-block:calc(var(--spacing) * 8)}.py-12{padding-block:calc(var(--spacing) * 12)}.pt-1{padding-top:calc(var(--spacing) * 1)}.pt-3{padding-top:calc(var(--spacing) * 3)}.pt-20{padding-top:calc(var(--spacing) * 20)}.pb-2{padding-bottom:calc(var(--spacing) * 2)}.pb-8{padding-bottom:calc(var(--spacing) * 8)}.pl-2{padding-left:calc(var(--spacing) * 2)}.pl-3{padding-left:calc(var(--spacing) * 3)}.pl-56{padding-left:calc(var(--spacing) * 56)}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.font-mono{font-family:var(--font-mono)}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-normal{--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-normal{--tw-tracking:var(--tracking-normal);letter-spacing:var(--tracking-normal)}.tracking-widest{--tw-tracking:var(--tracking-widest);letter-spacing:var(--tracking-widest)}.break-all{word-break:break-all}.whitespace-pre-wrap{white-space:pre-wrap}.text-amber-600{color:var(--color-amber-600)}.text-blue-600{color:var(--color-blue-600)}.text-gray-600{color:var(--color-gray-600)}.text-green-400{color:var(--color-green-400)}.text-green-600{color:var(--color-green-600)}.text-green-700{color:var(--color-green-700)}.text-green-800{color:var(--color-green-800)}.text-ink{color:var(--color-ink)}.text-ink-faint{color:var(--color-ink-faint)}.text-ink-muted{color:var(--color-ink-muted)}.text-orange-800{color:var(--color-orange-800)}.text-red-500{color:var(--color-red-500)}.text-red-600{color:var(--color-red-600)}.text-red-800{color:var(--color-red-800)}.text-surface{color:var(--color-surface)}.text-surface\/60{color:#ebf1e599}@supports (color:color-mix(in lab,red,red)){.text-surface\/60{color:color-mix(in oklab,var(--color-surface) 60%,transparent)}}.text-yellow-800{color:var(--color-yellow-800)}.normal-case{text-transform:none}.uppercase{text-transform:uppercase}.underline{text-decoration-line:underline}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.backdrop-blur-sm{--tw-backdrop-blur:blur(var(--blur-sm));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}@media(hover:hover){.group-hover\:underline:is(:where(.group):hover *){text-decoration-line:underline}}.placeholder\:text-ink-faint::placeholder{color:var(--color-ink-faint)}.last\:border-0:last-child{border-style:var(--tw-border-style);border-width:0}@media(hover:hover){.hover\:border-border:hover{border-color:var(--color-border)}.hover\:border-ink:hover{border-color:var(--color-ink)}.hover\:border-ink-faint:hover{border-color:var(--color-ink-faint)}.hover\:bg-border:hover{background-color:var(--color-border)}.hover\:bg-border\/30:hover{background-color:#cdd4c74d}@supports (color:color-mix(in lab,red,red)){.hover\:bg-border\/30:hover{background-color:color-mix(in oklab,var(--color-border) 30%,transparent)}}.hover\:bg-border\/40:hover{background-color:#cdd4c766}@supports (color:color-mix(in lab,red,red)){.hover\:bg-border\/40:hover{background-color:color-mix(in oklab,var(--color-border) 40%,transparent)}}.hover\:bg-border\/50:hover{background-color:#cdd4c780}@supports (color:color-mix(in lab,red,red)){.hover\:bg-border\/50:hover{background-color:color-mix(in oklab,var(--color-border) 50%,transparent)}}.hover\:bg-green-100:hover{background-color:var(--color-green-100)}.hover\:bg-ink\/80:hover{background-color:#272725cc}@supports (color:color-mix(in lab,red,red)){.hover\:bg-ink\/80:hover{background-color:color-mix(in oklab,var(--color-ink) 80%,transparent)}}.hover\:text-amber-800:hover{color:var(--color-amber-800)}.hover\:text-ink:hover{color:var(--color-ink)}.hover\:text-ink\/70:hover{color:#272725b3}@supports (color:color-mix(in lab,red,red)){.hover\:text-ink\/70:hover{color:color-mix(in oklab,var(--color-ink) 70%,transparent)}}.hover\:text-red-700:hover{color:var(--color-red-700)}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-90:hover{opacity:.9}}.focus\:border-ink:focus{border-color:var(--color-ink)}.focus\:border-transparent:focus{border-color:#0000}.focus\:ring-1:focus{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus\:ring-2:focus{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus\:ring-ink:focus{--tw-ring-color:var(--color-ink)}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:bg-gray-50:disabled{background-color:var(--color-gray-50)}.disabled\:text-ink-muted:disabled{color:var(--color-ink-muted)}.disabled\:opacity-30:disabled{opacity:.3}.disabled\:opacity-50:disabled{opacity:.5}}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-divide-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@keyframes pulse{50%{opacity:.5}}
|