1import{r,j as e}from"./react-vendor--6IG9Yi5.js";import{a as h,t as l,aE as X}from"./index-Bys9v8Oy.js";import"./redux-vendor-C8ygHAw9.js";import"./react-router-CEJpt0Xm.js";import"./markdown-vendor-DxXj1xPu.js";import"./radix-vendor-Bx9qoP74.js";import"./tiptap-vendor-rePe3wTF.js";import"./recharts-vendor-DbKwtSaD.js";import"./query-vendor-B3TfXRMZ.js";const Z=[{label:"Cases & clients",scopes:["cases:read","clients:read","tasks:read","calendar:read","cases:write","clients:write","tasks:write","calendar:write"]},{label:"Documents & finance",scopes:["documents:read","documents:download","invoices:read","documents:write","invoices:write"]},{label:"Workflow",scopes:["forms:read","approvals:read","forms:write","approvals:write"]},{label:"Collaboration",scopes:["teamchat:read","communications:read","teamchat:write","communications:write"]},{label:"Workspace",scopes:["workspace:read","workspace:write"]},{label:"Legal corpus (global)",scopes:["library:read"]}],v=i=>i.endsWith(":write"),p={hub:"https://modulaw.ai/support/collection/developers/",apiReference:"https://modulaw.ai/support/modulaw-api-reference/",usingTheApi:"https://modulaw.ai/support/using-the-modulaw-api/",permissions:"https://modulaw.ai/support/api-mcp-permissions/",connectAssistant:"https://modulaw.ai/support/connect-ai-assistant-mcp/"},x=({href:i,children:m})=>e.jsx("a",{href:i,target:"_blank",rel:"noopener noreferrer",className:"text-brass-700 dark:text-brass-400 underline underline-offset-2 hover:text-brass-800 dark:hover:text-brass-300",children:m}),K=["cases:read","clients:read","workspace:read","library:read"],j=`${String(X.API_URL).replace(/\/+$/,"")}/mcp`,N=[{id:"claude-code",label:"Claude Code",kind:"shell",body:i=>`claude mcp add --transport http modulaw ${i}`,note:"Run this in your terminal, then use /mcp inside Claude Code to sign in."},{id:"claude-desktop",label:"Claude Desktop",kind:"steps",body:()=>["Settings â Connectors â Add custom connector","Paste the server URL above","Approve the Modulaw sign-in prompt that opens in your browser"],note:"Claude will remember the connection; it shows up in the list below once approved."},{id:"cursor",label:"Cursor",kind:"code",body:i=>`{ 2 "mcpServers": { 3 "modulaw": { 4 "url": "${i}" 5 } 6 } 7}`,note:"Add to ~/.cursor/mcp.json (or the project-level .cursor/mcp.json), then reload."},{id:"other",label:"Other clients",kind:"steps",body:()=>["Transport: Streamable HTTP","Auth: OAuth 2.1 â dynamic client registration and PKCE, no pre-shared secret","The client discovers everything from /.well-known/oauth-protected-resource"],note:"Any MCP client that speaks Streamable HTTP with OAuth should connect with just the URL."}],ce=({workspaces:i=[],currentWorkspaceId:m=null})=>{const[C,A]=r.useState([]),[O,W]=r.useState(!0),[S,P]=r.useState(!1),[I,L]=r.useState(!1),[f,$]=r.useState(""),[b,R]=r.useState(K),[u,D]=r.useState(m||""),[y,E]=r.useState(null),[T,U]=r.useState([]),[z,G]=r.useState(!0),[_,q]=r.useState(N[0].id),[M,Y]=r.useState(null),g=r.useCallback(async()=>{var t,s,a,o,n,d;try{const c=await h.get("/api/profile/api-keys");A(((s=(t=c==null?void 0:c.data)==null?void 0:t.data)==null?void 0:s.keys)??[]);const k=(o=(a=c==null?void 0:c.data)==null?void 0:a.data)==null?void 0:o.availableScopes;Y(Array.isArray(k)&&k.length?k:null)}catch(c){l.error(((d=(n=c==null?void 0:c.response)==null?void 0:n.data)==null?void 0:d.message)||"Could not load API keys")}finally{W(!1)}},[]),F=r.useCallback(async()=>{var t,s;try{const a=await h.get("/api/profile/connected-apps");U(((s=(t=a==null?void 0:a.data)==null?void 0:t.data)==null?void 0:s.apps)??[])}catch{}finally{G(!1)}},[]);r.useEffect(()=>{g(),F()},[g,F]),r.useEffect(()=>{m&&!u&&D(m)},[m,u]);const H=t=>R(s=>s.includes(t)?s.filter(a=>a!==t):[...s,t]),B=async t=>{var s,a,o,n;if(t.preventDefault(),!f.trim())return l.error("Give the key a name");if(b.length===0)return l.error("Select at least one permission");L(!0);try{const d=await h.post("/api/profile/api-keys",{name:f.trim(),scopes:b,workspacePin:u||null});E(((a=(s=d==null?void 0:d.data)==null?void 0:s.data)==null?void 0:a.key)??null),P(!1),$(""),R(K),await g()}catch(d){l.error(((n=(o=d==null?void 0:d.response)==null?void 0:o.data)==null?void 0:n.message)||"Could not create API key")}finally{L(!1)}},w=async(t,s="API key")=>{try{await navigator.clipboard.writeText(t),l.success(`${s} copied`)}catch{l.error("Failed to copy â select the text and copy manually")}},J=async(t,s)=>{var a,o;if(window.confirm(`Revoke "${s}"? Any application using it will stop working immediately.`))try{await h.delete(`/api/profile/api-keys/${t}`),l.success("API key revoked"),A(n=>n.filter(d=>d.id!==t))}catch(n){l.error(((o=(a=n==null?void 0:n.response)==null?void 0:a.data)==null?void 0:o.message)||"Could not revoke API key")}},Q=async t=>{var s,a;if(window.confirm(t.firstParty?`Sign "${t.clientName}" out of ${t.workspaceName}? It stops working immediately and you would have to sign in again there.`:`Disconnect "${t.clientName}" from ${t.workspaceName}? It will lose access immediately and would have to be re-authorized.`))try{await h.delete(`/api/profile/connected-apps/${encodeURIComponent(t.clientId)}?workspaceId=${t.workspaceId}`),l.success(t.firstParty?"Signed out":"Access revoked"),U(o=>o.filter(n=>!(n.clientId===t.clientId&&n.workspaceId===t.workspaceId)))}catch(o){l.error(((a=(s=o==null?void 0:o.response)==null?void 0:s.data)==null?void 0:a.message)||"Could not revoke access")}},V=t=>{var s;return((s=i.find(a=>String(a._id??a.id)===String(t)))==null?void 0:s.name)||"Unknown workspace"};return e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"bg-surface shadow overflow-hidden sm:rou
7nded-md",children:[e.jsxs("div",{className:"px-4 py-5 sm:px-6 border-b border-border","data-tour":"profile-api-banner",children:[e.jsx("h3",{className:"text-lg leading-6 font-medium text-chambers-900 dark:text-white",children:"API Keys"}),e.jsx("p",{className:"mt-1 max-w-2xl text-sm text-muted-foreground",children:"Use an API key to work with your Modulaw data from your own applications. Keys act as you, limited to the permissions you grant â they can never do more than your own account can."}),e.jsxs("p",{className:"mt-2 max-w-2xl text-sm text-muted-foreground",children:["Send it as ",e.jsx("code",{className:"px-1 rounded bg-muted font-mono text-xs",children:"Authorization: Bearer mk_live_â¦"})," ","from your ",e.jsx("strong",{children:"server"})," â never from a browser, where anyone can read it. Keys cannot access billing, account settings, or the AI assistant."]}),e.jsxs("p",{className:"mt-2 max-w-2xl text-sm text-muted-foreground",children:[e.jsx(x,{href:p.apiReference,children:"API reference"})," · ",e.jsx(x,{href:p.usingTheApi,children:"Getting started"})," · ",e.jsx(x,{href:p.permissions,children:"Permissions"})," · ",e.jsx(x,{href:p.hub,children:"All developer docs"})]})]}),e.jsxs("div",{className:"px-4 py-5 sm:p-6",children:[y&&e.jsxs("div",{className:"mb-6 p-4 bg-brass-50 dark:bg-chambers-800 border border-brass-300 dark:border-brass-800 rounded-md",children:[e.jsx("div",{className:"mb-2 text-sm font-medium text-brass-800 dark:text-brass-200",children:"Copy this key now â it will not be shown again."}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("input",{type:"text",readOnly:!0,value:y,onFocus:t=>t.target.select(),className:"flex-grow p-2 bg-surface border border-border rounded-md text-sm font-mono"}),e.jsx("button",{type:"button",onClick:()=>w(y),className:"px-3 py-2 text-sm rounded-md bg-brass-600 text-white hover:bg-brass-700",children:"Copy"}),e.jsx("button",{type:"button",onClick:()=>E(null),className:"px-3 py-2 text-sm rounded-md border border-border text-foreground",children:"Done"})]})]}),e.jsx("div",{className:"mb-6",children:e.jsx("button",{type:"button",onClick:()=>P(t=>!t),"data-tour":"profile-api-create",className:"inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-brass-600 hover:bg-brass-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-brass-500",children:S?"Cancel":"Create New API Key"})}),S&&e.jsxs("form",{onSubmit:B,className:"mb-6 p-4 border border-border rounded-md space-y-4",children:[e.jsxs("div",{children:[e.jsx("label",{htmlFor:"keyName",className:"block text-sm font-medium text-foreground",children:"Name"}),e.jsx("input",{type:"text",id:"keyName",className:"mt-1 block w-full rounded-md border-border shadow-sm focus:border-brass-500 focus:ring-brass-500 dark:bg-chambers-700 dark:text-white sm:text-sm",placeholder:"e.g. Compliance dashboard",value:f,onChange:t=>$(t.target.value),required:!0})]}),e.jsxs("div",{children:[e.jsx("label",{htmlFor:"wsPin",className:"block text-sm font-medium text-foreground",children:"Workspace"}),e.jsxs("select",{id:"wsPin",value:u,onChange:t=>D(t.target.value),className:"mt-1 block w-full rounded-md border-border shadow-sm dark:bg-chambers-700 dark:text-white sm:text-sm",children:[i.map(t=>e.jsx("option",{value:String(t._id??t.id),children:t.name},String(t._id??t.id))),e.jsx("option",{value:"",children:"All my workspaces (less safe)"})]}),e.jsx("p",{className:"mt-1 text-xs text-muted-foreground",children:"Limiting a key to one workspace means a leak exposes only that workspace."})]}),e.jsxs("fieldset",{children:[e.jsx("legend",{className:"block text-sm font-medium text-foreground",children:"Permissions"}),e.jsxs("p",{className:"mt-1 mb-2 text-xs text-muted-foreground",children:["Grant the least a key needs. ",e.jsx("code",{className:"font-mono",children:":read"})," can only look things up; ",e.jsx("code",{className:"font-mono",children:":write"})," lets it create, change and delete â give that out sparingly, and prefer pinning the key to one workspace."," ",e.jsx(x,{href:p.permissions,children:"What each permission covers"}),"."]}),e.jsx("div",{className:"grid gap-3 sm:grid-cols-2",children:Z.map(t=>{const s=t.scopes.filter(a=>M?M.includes(a):!v(a));return s.length===0?null:e.jsxs("div",{className:"p-3 rounded-md bg-muted",children:[e.jsx("div",{className:"text-xs font-semibold uppercase tracking-wide text-muted-foreground mb-1",children:t.label}),s.map(a=>e.jsxs("label",{className:"flex items-center gap-2 text-sm text-foreground",children:[e.jsx("input",{type:"checkbox",checked:b.includes(a),onChange:()=>H(a)}),e.jsx("code",{className:`font-mono text-xs ${v(a)?"text-amber-700 dark:text-amber-400":""}`,children:a})]},a))]},t.label)})}),b.some(v)&&e.jsxs("p",{className:"mt-2 text-xs text-amber-700 dark:text-amber-400",children:["This key will be able to change and delete data in",u?" the selected workspace":" every workspace you belong to","."]})]}),e.jsx("div",{className:"flex justify-end",children:e.jsx("button",{type:"submit",disabled:I,className:"inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-brass-600 hover:bg-brass-700 disabled:opacity-50",children:I?"Creatingâ¦":"Create key"})})]}),e.jsx("div",{"data-tour":"profile-api-table",children:O?e.jsx("p",{className:"text-sm text-muted-foreground",children:"Loadingâ¦"}):C.length===0?e.jsx("p",{className:"text-sm text-muted-foreground",children:"No API keys yet. Create one to start using the Modulaw API."}):e.jsx("div",{className:"overflow-x-auto",children:e.jsxs("table",{className:"min-w-full divide-y divide-chambers-200 dark:divide-chambers-700",children:[e.jsx("thead",{children:e.jsx("tr",{children:["Name","Key","Workspace","Permissions","Last used",""].map(t=>e.jsx("th",{scope:"col",className:"px-4 py-3 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider",children:t},t))})}),e.jsx("tbody",{className:"divide-y divide-chambers-200 dark:divide-chambers-700",children:C.map(t=>{var s;return e.jsxs("tr",{children:[e.jsx("td",{className:"px-4 py-3 text-sm text-chambers-900 dark:text-white",children:t.name}),e.jsx("td",{className:"px-4 py-3 text-sm font-mono text-muted-foreground",children:t.keyPreview}),e.jsx("td",{className:"px-4 py-3 text-sm text-foreground",children:t.workspacePin?V(t.workspacePin):e.jsx("span",{className:"text-amber-600 dar
7k:text-amber-400",children:"All workspaces"})}),e.jsxs("td",{className:"px-4 py-3 text-sm text-foreground",children:[((s=t.scopes)==null?void 0:s.length)??0," granted"]}),e.jsxs("td",{className:"px-4 py-3 text-sm text-muted-foreground",children:[t.lastUsedAt?new Date(t.lastUsedAt).toLocaleString():"Never",t.requestCount?` · ${t.requestCount} calls`:""]}),e.jsx("td",{className:"px-4 py-3 text-right",children:e.jsx("button",{type:"button",onClick:()=>J(t.id,t.name),className:"text-sm text-red-600 dark:text-red-400 hover:text-red-800 dark:hover:text-red-300",children:"Revoke"})})]},t.id)})})]})})})]})]}),e.jsxs("div",{className:"bg-surface shadow overflow-hidden sm:rounded-md","data-tour":"profile-mcp-connect",children:[e.jsxs("div",{className:"px-4 py-5 sm:px-6 border-b border-border",children:[e.jsx("h3",{className:"text-lg leading-6 font-medium text-chambers-900 dark:text-white",children:"Connect an AI assistant"}),e.jsxs("p",{className:"mt-1 max-w-2xl text-sm text-muted-foreground",children:["Modulaw runs an MCP server, so assistants like Claude and Cursor can work with your cases, clients, documents and the legal corpus directly. You do not need a key â point the client at the URL below, sign in, and approve the workspace it may reach."," ",e.jsx(x,{href:p.connectAssistant,children:"Full setup guide"}),"."]})]}),e.jsxs("div",{className:"px-4 py-5 sm:p-6 space-y-5",children:[e.jsxs("div",{children:[e.jsx("span",{className:"block text-sm font-medium text-foreground mb-1.5",children:"Server URL"}),e.jsxs("div",{className:"flex items-stretch gap-2",children:[e.jsx("code",{className:"flex-1 min-w-0 overflow-x-auto whitespace-nowrap rounded-md bg-muted px-3 py-2 font-mono text-sm text-chambers-900 dark:text-parchment-50",children:j}),e.jsx("button",{type:"button",onClick:()=>w(j,"Server URL"),className:"shrink-0 px-3 py-2 border border-border rounded-md text-sm font-medium text-foreground hover:bg-accent",children:"Copy"})]})]}),e.jsxs("div",{children:[e.jsx("div",{className:"flex flex-wrap gap-1.5 border-b border-border mb-3",children:N.map(t=>e.jsx("button",{type:"button",onClick:()=>q(t.id),className:`px-3 py-1.5 text-sm font-medium rounded-t-md -mb-px border-b-2 ${_===t.id?"border-brass-600 text-brass-700 dark:text-brass-400":"border-transparent text-chambers-500 dark:text-chambers-400 hover:text-chambers-700 dark:hover:text-chambers-200"}`,children:t.label},t.id))}),N.filter(t=>t.id===_).map(t=>{const s=t.body(j);return e.jsxs("div",{className:"space-y-2",children:[Array.isArray(s)?e.jsx("ol",{className:"list-decimal list-inside space-y-1 text-sm text-foreground",children:s.map(a=>e.jsx("li",{children:a},a))}):e.jsxs("div",{className:"flex items-start gap-2",children:[e.jsx("pre",{className:"flex-1 min-w-0 overflow-x-auto rounded-md bg-muted px-3 py-2 font-mono text-xs text-chambers-900 dark:text-parchment-50",children:s}),e.jsx("button",{type:"button",onClick:()=>w(s,t.label==="Claude Code"?"Command":"Config"),className:"shrink-0 px-3 py-2 border border-border rounded-md text-sm font-medium text-foreground hover:bg-accent",children:"Copy"})]}),e.jsx("p",{className:"text-xs text-muted-foreground",children:t.note})]},t.id)})]}),e.jsx("p",{className:"text-xs text-muted-foreground border-t border-border pt-4",children:"You choose what the assistant may do when you approve it, and access is scoped to the single workspace you pick. If you grant write access it can create and change data, and destructive actions ask for confirmation first. You can disconnect it below at any time."})]})]}),e.jsxs("div",{className:"bg-surface shadow overflow-hidden sm:rounded-md","data-tour":"profile-connected-apps",children:[e.jsxs("div",{className:"px-4 py-5 sm:px-6 border-b border-border",children:[e.jsx("h3",{className:"text-lg leading-6 font-medium text-chambers-900 dark:text-white",children:"Connected apps & agents"}),e.jsx("p",{className:"mt-1 max-w-2xl text-sm text-muted-foreground",children:"Everything signed in to your account besides this browser: the Word add-in and the desktop app, plus any AI assistant, IDE or command-line tool you have authorized. They were approved by you, not created here, so there is no key to copy."})]}),e.jsx("div",{className:"px-4 py-5 sm:p-6",children:z?e.jsx("p",{className:"text-sm text-muted-foreground",children:"Loadingâ¦"}):T.length===0?e.jsx("p",{className:"text-sm text-muted-foreground",children:"Nothing connected. When you authorize an app it will appear here, and you can disconnect it at any time."}):e.jsx("div",{className:"overflow-x-auto",children:e.jsxs("table",{className:"min-w-full divide-y divide-chambers-200 dark:divide-chambers-700",children:[e.jsx("thead",{children:e.jsx("tr",{children:["Application","Workspace","Permissions","Last active",""].map(t=>e.jsx("th",{scope:"col",className:"px-4 py-3 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider",children:t},t))})}),e.jsx("tbody",{className:"divide-y divide-chambers-200 dark:divide-chambers-700",children:T.map(t=>{var s;return e.jsxs("tr",{children:[e.jsxs("td",{className:"px-4 py-3 text-sm text-chambers-900 dark:text-white",children:[t.clientName,t.firstParty&&e.jsx("span",{className:"ml-2 align-middle text-[10px] uppercase tracking-wider px-1.5 py-0.5 rounded bg-muted text-muted-foreground",children:"Modulaw app"})]}),e.jsx("td",{className:"px-4 py-3 text-sm text-foreground",children:t.workspaceName}),e.jsx("td",{className:"px-4 py-3 text-sm text-foreground",children:t.firstParty?"Signs in as you":`${((s=t.scopes)==null?void 0:s.length)??0} granted`}),e.jsx("td",{className:"px-4 py-3 text-sm text-muted-foreground",children:t.lastActiveAt?new Date(t.lastActiveAt).toLocaleStr
7ing():"â"}),e.jsx("td",{className:"px-4 py-3 text-right",children:e.jsx("button",{type:"button",onClick:()=>Q(t),className:"text-sm text-red-600 dark:text-red-400 hover:text-red-800 dark:hover:text-red-300",children:"Disconnect"})})]},`${t.clientId}:${t.workspaceId}`)})})]})})})]})]})};export{ce as default};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.