@flexkit/studio 0.2.38 → 0.2.40
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 +76 -7
- package/dist/{chat-page-DW3FP4UZ.js → chat-page-I2IFVZA3.js} +3 -3
- package/dist/{chat-page-DW3FP4UZ.js.map → chat-page-I2IFVZA3.js.map} +1 -1
- package/dist/{chunk-DSZJXMN5.js → chunk-2IJWBRN2.js} +2 -2
- package/dist/{chunk-DSZJXMN5.js.map → chunk-2IJWBRN2.js.map} +1 -1
- package/dist/{chunk-IJECATW3.js → chunk-4JG3OWQW.js} +2 -2
- package/dist/{chunk-IJECATW3.js.map → chunk-4JG3OWQW.js.map} +1 -1
- package/dist/{chunk-JUWAKQPE.js → chunk-53GVTCXC.js} +3 -3
- package/dist/{chunk-JUWAKQPE.js.map → chunk-53GVTCXC.js.map} +1 -1
- package/dist/{chunk-WYVXSLB7.js → chunk-CQS6AIOX.js} +2 -2
- package/dist/{chunk-WYVXSLB7.js.map → chunk-CQS6AIOX.js.map} +1 -1
- package/dist/{chunk-AQBULUC2.js → chunk-DAXVPJJS.js} +4 -4
- package/dist/{chunk-AQBULUC2.js.map → chunk-DAXVPJJS.js.map} +1 -1
- package/dist/{chunk-LMJEP4VR.js → chunk-DFOPVG7I.js} +2 -2
- package/dist/{chunk-LMJEP4VR.js.map → chunk-DFOPVG7I.js.map} +1 -1
- package/dist/{chunk-IUWDNPMY.js → chunk-E3KO5NGM.js} +2 -2
- package/dist/{chunk-IUWDNPMY.js.map → chunk-E3KO5NGM.js.map} +1 -1
- package/dist/chunk-GPMBBJHK.js +7 -0
- package/dist/chunk-GPMBBJHK.js.map +1 -0
- package/dist/{chunk-3GXM5SSM.js → chunk-GPTSQ2WH.js} +3 -3
- package/dist/{chunk-3GXM5SSM.js.map → chunk-GPTSQ2WH.js.map} +1 -1
- package/dist/{chunk-GORBKX24.js → chunk-HOAVEDVI.js} +3 -3
- package/dist/{chunk-GORBKX24.js.map → chunk-HOAVEDVI.js.map} +1 -1
- package/dist/{chunk-KV4OGH5U.js → chunk-HUG2NGZI.js} +2 -2
- package/dist/{chunk-KV4OGH5U.js.map → chunk-HUG2NGZI.js.map} +1 -1
- package/dist/{chunk-377TM7UG.js → chunk-L62VVHKS.js} +2 -2
- package/dist/{chunk-377TM7UG.js.map → chunk-L62VVHKS.js.map} +1 -1
- package/dist/{chunk-6J3ZIVDQ.js → chunk-LO37DY2Z.js} +2 -2
- package/dist/{chunk-6J3ZIVDQ.js.map → chunk-LO37DY2Z.js.map} +1 -1
- package/dist/{chunk-32B35YDF.js → chunk-LWI3HNJL.js} +3 -3
- package/dist/{chunk-32B35YDF.js.map → chunk-LWI3HNJL.js.map} +1 -1
- package/dist/{chunk-UOTVVZPA.js → chunk-NPMBADZL.js} +3 -3
- package/dist/{chunk-UOTVVZPA.js.map → chunk-NPMBADZL.js.map} +1 -1
- package/dist/chunk-NPO7ISWV.js +2 -0
- package/dist/chunk-NPO7ISWV.js.map +1 -0
- package/dist/{chunk-4OGLWOO3.js → chunk-X5QKLF63.js} +3 -3
- package/dist/chunk-X5QKLF63.js.map +1 -0
- package/dist/{chunk-INZZOKRC.js → chunk-Y7VBTUNI.js} +3 -3
- package/dist/{chunk-INZZOKRC.js.map → chunk-Y7VBTUNI.js.map} +1 -1
- package/dist/{entry-G2R3W5NU.js → entry-NCKQ45MI.js} +2 -2
- package/dist/{entry-G2R3W5NU.js.map → entry-NCKQ45MI.js.map} +1 -1
- package/dist/index.d.ts +12 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/list-UHHDZ3DM.js +2 -0
- package/dist/list-UHHDZ3DM.js.map +1 -0
- package/dist/{list-LVXMUJHP.js → list-VWN4IJYC.js} +3 -3
- package/dist/{list-LVXMUJHP.js.map → list-VWN4IJYC.js.map} +1 -1
- package/dist/{pages-HJHR7DFO.js → pages-LZEKCA4W.js} +3 -3
- package/dist/{pages-HJHR7DFO.js.map → pages-LZEKCA4W.js.map} +1 -1
- package/dist/{plugin-pages-ZO3TLUYW.js → plugin-pages-LLJPZJWL.js} +2 -2
- package/dist/{plugin-pages-ZO3TLUYW.js.map → plugin-pages-LLJPZJWL.js.map} +1 -1
- package/dist/{project-selector-OXDEHTJ5.js → project-selector-K3T6H77F.js} +2 -2
- package/dist/{project-selector-OXDEHTJ5.js.map → project-selector-K3T6H77F.js.map} +1 -1
- package/dist/record-links-CILZYRSE.js +2 -0
- package/dist/{record-links-SZQUATM6.js.map → record-links-CILZYRSE.js.map} +1 -1
- package/dist/{root-4ATHF5ZZ.js → root-ADEORVTL.js} +2 -2
- package/dist/{root-4ATHF5ZZ.js.map → root-ADEORVTL.js.map} +1 -1
- package/dist/root-CE6LNBBW.js +23 -0
- package/dist/root-CE6LNBBW.js.map +1 -0
- package/dist/{root-P537YXFS.js → root-LSBCX6AE.js} +2 -2
- package/dist/{root-P537YXFS.js.map → root-LSBCX6AE.js.map} +1 -1
- package/dist/{root-MMGPZ4ZF.js → root-PY5SBJ4F.js} +3 -3
- package/dist/{root-MMGPZ4ZF.js.map → root-PY5SBJ4F.js.map} +1 -1
- package/dist/{root-E4GIVJYA.js → root-XTF6EH63.js} +3 -3
- package/dist/{root-E4GIVJYA.js.map → root-XTF6EH63.js.map} +1 -1
- package/dist/{root-BRIEXCDH.js → root-Y3D2FTDR.js} +2 -2
- package/dist/{root-BRIEXCDH.js.map → root-Y3D2FTDR.js.map} +1 -1
- package/dist/{search-57W7MXQ3.js → search-MGY3OWZQ.js} +2 -2
- package/dist/{search-57W7MXQ3.js.map → search-MGY3OWZQ.js.map} +1 -1
- package/dist/{skills-pages-LUOBTEAP.js → skills-pages-7QYBKBSB.js} +2 -2
- package/dist/{skills-pages-LUOBTEAP.js.map → skills-pages-7QYBKBSB.js.map} +1 -1
- package/dist/{source-CJPY5PTU.js → source-M746FR3B.js} +2 -2
- package/dist/{source-CJPY5PTU.js.map → source-M746FR3B.js.map} +1 -1
- package/package.json +4 -4
- package/dist/chunk-4OGLWOO3.js.map +0 -1
- package/dist/chunk-CCVE7GGO.js +0 -2
- package/dist/chunk-CCVE7GGO.js.map +0 -1
- package/dist/chunk-GSKQHFQM.js +0 -7
- package/dist/chunk-GSKQHFQM.js.map +0 -1
- package/dist/list-IRTUEW55.js +0 -2
- package/dist/list-IRTUEW55.js.map +0 -1
- package/dist/record-links-SZQUATM6.js +0 -2
- package/dist/root-BIUU3CXY.js +0 -23
- package/dist/root-BIUU3CXY.js.map +0 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import'./index.css';import {f as f$1}from'./chunk-
|
|
2
|
-
//# sourceMappingURL=chunk-
|
|
1
|
+
import'./index.css';import {f as f$1}from'./chunk-HOAVEDVI.js';import {f as f$2}from'./chunk-Y7VBTUNI.js';import {createContext,useReducer,useContext}from'react';import {jsx}from'react/jsx-runtime';var d="core.context.scope:",a={breadcrumbs:[],isRouteLoading:false,pageTitle:"",scope:"",relationships:{}},u=createContext(a),l=createContext(()=>{});function f(e,t){let{type:n,payload:o}=t;switch(n){case "setScope":return typeof localStorage<"u"&&o.projectId&&localStorage.setItem(`${d}${o.projectId}`,o.scope),{...e,scope:o.scope};case "setRelationship":return {...e,relationships:{...e.relationships,...o}};default:throw Error(`Unknown action: ${n}`)}}function x({children:e}){let[t,n]=useReducer(f,a);return jsx(u.Provider,{value:t,children:jsx(l.Provider,{value:n,children:e})})}function m(){return useContext(u)}function C(){return useContext(l)}function A(e){return e?.find(t=>t.isDefault)?.name??e?.[0]?.name??f$1}function E(){let{currentProject:e}=f$2();return A(e?.scopes)}export{d as a,x as b,m as c,C as d,A as e,E as f};//# sourceMappingURL=chunk-2IJWBRN2.js.map
|
|
2
|
+
//# sourceMappingURL=chunk-2IJWBRN2.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/app-context.tsx","../src/core/default-scope.ts"],"names":["SCOPE_STORAGE_KEY","initialState","AppContext","createContext","AppDispatchContext","reducer","state","action","type","payload","AppProvider","children","dispatch","useReducer","jsx","useAppContext","useContext","useAppDispatch","defaultScopeName","scopes","scope","DEFAULT_SCOPE_KEY","useDefaultScope","currentProject","useConfig"],"mappings":"sMAMO,IAAMA,CAAAA,CAAoB,sBAE3BC,CAAAA,CAAe,CACnB,YAAa,EAAC,CACd,eAAgB,KAAA,CAChB,SAAA,CAAW,GACX,KAAA,CAAO,EAAA,CACP,cAAe,EACjB,EAEMC,CAAAA,CAAaC,aAAAA,CAA8BF,CAAY,CAAA,CAEvDG,CAAAA,CAAqBD,cAAgE,IAAM,CAEjG,CAAC,EAED,SAASE,EAAQC,CAAAA,CAAuBC,CAAAA,CAAgE,CACtG,GAAM,CAAE,KAAAC,CAAAA,CAAM,OAAA,CAAAC,CAAQ,CAAA,CAAIF,CAAAA,CAE1B,OAAQC,CAAAA,EACN,KAAK,UAAA,CACH,OAAI,OAAO,YAAA,CAAiB,GAAA,EAAeC,EAAQ,SAAA,EACjD,YAAA,CAAa,QAAQ,CAAA,EAAGT,CAAiB,GAAGS,CAAAA,CAAQ,SAAS,GAAIA,CAAAA,CAAQ,KAAK,EAGzE,CACL,GAAGH,EACH,KAAA,CAAOG,CAAAA,CAAQ,KACjB,CAAA,CACF,KAAK,kBACH,OAAO,CACL,GAAGH,CAAAA,CACH,aAAA,CAAe,CAAE,GAAGA,CAAAA,CAAM,cAAe,GAAGG,CAAQ,CACtD,CAAA,CACF,QACE,MAAM,KAAA,CAAM,CAAA,gBAAA,EAAmBD,CAAc,CAAA,CAAE,CACnD,CACF,CAEO,SAASE,EAAY,CAAE,QAAA,CAAAC,CAAS,CAAA,CAAyC,CAC9E,GAAM,CAACL,CAAAA,CAAOM,CAAQ,CAAA,CAAIC,UAAAA,CAAWR,EAASJ,CAAY,CAAA,CAE1D,OACEa,GAAAA,CAACZ,CAAAA,CAAW,SAAX,CAAoB,KAAA,CAAOI,EAC1B,QAAA,CAAAQ,GAAAA,CAACV,EAAmB,QAAA,CAAnB,CAA4B,MAAOQ,CAAAA,CAAW,QAAA,CAAAD,EAAS,CAAA,CAC1D,CAEJ,CAEO,SAASI,CAAAA,EAAgC,CAC9C,OAAOC,UAAAA,CAAWd,CAAU,CAC9B,CAEO,SAASe,CAAAA,EAAmE,CACjF,OAAOD,UAAAA,CAAWZ,CAAkB,CACtC,CCpDO,SAASc,EAAiBC,CAAAA,CAAyD,CACxF,OAAOA,CAAAA,EAAQ,IAAA,CAAMC,GAAUA,CAAAA,CAAM,SAAS,GAAG,IAAA,EAAQD,CAAAA,GAAS,CAAC,CAAA,EAAG,IAAA,EAAQE,GAChF,CAGO,SAASC,GAA0B,CACxC,GAAM,CAAE,cAAA,CAAAC,CAAe,EAAIC,GAAAA,EAAU,CAErC,OAAON,CAAAA,CAAiBK,CAAAA,EAAgB,MAAM,CAChD","file":"chunk-
|
|
1
|
+
{"version":3,"sources":["../src/core/app-context.tsx","../src/core/default-scope.ts"],"names":["SCOPE_STORAGE_KEY","initialState","AppContext","createContext","AppDispatchContext","reducer","state","action","type","payload","AppProvider","children","dispatch","useReducer","jsx","useAppContext","useContext","useAppDispatch","defaultScopeName","scopes","scope","DEFAULT_SCOPE_KEY","useDefaultScope","currentProject","useConfig"],"mappings":"sMAMO,IAAMA,CAAAA,CAAoB,sBAE3BC,CAAAA,CAAe,CACnB,YAAa,EAAC,CACd,eAAgB,KAAA,CAChB,SAAA,CAAW,GACX,KAAA,CAAO,EAAA,CACP,cAAe,EACjB,EAEMC,CAAAA,CAAaC,aAAAA,CAA8BF,CAAY,CAAA,CAEvDG,CAAAA,CAAqBD,cAAgE,IAAM,CAEjG,CAAC,EAED,SAASE,EAAQC,CAAAA,CAAuBC,CAAAA,CAAgE,CACtG,GAAM,CAAE,KAAAC,CAAAA,CAAM,OAAA,CAAAC,CAAQ,CAAA,CAAIF,CAAAA,CAE1B,OAAQC,CAAAA,EACN,KAAK,UAAA,CACH,OAAI,OAAO,YAAA,CAAiB,GAAA,EAAeC,EAAQ,SAAA,EACjD,YAAA,CAAa,QAAQ,CAAA,EAAGT,CAAiB,GAAGS,CAAAA,CAAQ,SAAS,GAAIA,CAAAA,CAAQ,KAAK,EAGzE,CACL,GAAGH,EACH,KAAA,CAAOG,CAAAA,CAAQ,KACjB,CAAA,CACF,KAAK,kBACH,OAAO,CACL,GAAGH,CAAAA,CACH,aAAA,CAAe,CAAE,GAAGA,CAAAA,CAAM,cAAe,GAAGG,CAAQ,CACtD,CAAA,CACF,QACE,MAAM,KAAA,CAAM,CAAA,gBAAA,EAAmBD,CAAc,CAAA,CAAE,CACnD,CACF,CAEO,SAASE,EAAY,CAAE,QAAA,CAAAC,CAAS,CAAA,CAAyC,CAC9E,GAAM,CAACL,CAAAA,CAAOM,CAAQ,CAAA,CAAIC,UAAAA,CAAWR,EAASJ,CAAY,CAAA,CAE1D,OACEa,GAAAA,CAACZ,CAAAA,CAAW,SAAX,CAAoB,KAAA,CAAOI,EAC1B,QAAA,CAAAQ,GAAAA,CAACV,EAAmB,QAAA,CAAnB,CAA4B,MAAOQ,CAAAA,CAAW,QAAA,CAAAD,EAAS,CAAA,CAC1D,CAEJ,CAEO,SAASI,CAAAA,EAAgC,CAC9C,OAAOC,UAAAA,CAAWd,CAAU,CAC9B,CAEO,SAASe,CAAAA,EAAmE,CACjF,OAAOD,UAAAA,CAAWZ,CAAkB,CACtC,CCpDO,SAASc,EAAiBC,CAAAA,CAAyD,CACxF,OAAOA,CAAAA,EAAQ,IAAA,CAAMC,GAAUA,CAAAA,CAAM,SAAS,GAAG,IAAA,EAAQD,CAAAA,GAAS,CAAC,CAAA,EAAG,IAAA,EAAQE,GAChF,CAGO,SAASC,GAA0B,CACxC,GAAM,CAAE,cAAA,CAAAC,CAAe,EAAIC,GAAAA,EAAU,CAErC,OAAON,CAAAA,CAAiBK,CAAAA,EAAgB,MAAM,CAChD","file":"chunk-2IJWBRN2.js","sourcesContent":["'use client';\n\nimport { createContext, useContext, useReducer } from 'react';\nimport type { Dispatch, JSX, ReactNode } from 'react';\nimport type { ActionSetRelationship, ActionSetScope, AppContextType } from './types';\n\nexport const SCOPE_STORAGE_KEY = 'core.context.scope:';\n\nconst initialState = {\n breadcrumbs: [],\n isRouteLoading: false,\n pageTitle: '',\n scope: '',\n relationships: {},\n};\n\nconst AppContext = createContext<AppContextType>(initialState);\n\nconst AppDispatchContext = createContext<Dispatch<ActionSetRelationship | ActionSetScope>>(() => {\n /* void */\n});\n\nfunction reducer(state: AppContextType, action: ActionSetRelationship | ActionSetScope): AppContextType {\n const { type, payload } = action;\n\n switch (type) {\n case 'setScope':\n if (typeof localStorage !== 'undefined' && payload.projectId) {\n localStorage.setItem(`${SCOPE_STORAGE_KEY}${payload.projectId}`, payload.scope);\n }\n\n return {\n ...state,\n scope: payload.scope,\n };\n case 'setRelationship':\n return {\n ...state,\n relationships: { ...state.relationships, ...payload },\n };\n default:\n throw Error(`Unknown action: ${type as string}`);\n }\n}\n\nexport function AppProvider({ children }: { children: ReactNode }): JSX.Element {\n const [state, dispatch] = useReducer(reducer, initialState);\n\n return (\n <AppContext.Provider value={state}>\n <AppDispatchContext.Provider value={dispatch}>{children}</AppDispatchContext.Provider>\n </AppContext.Provider>\n );\n}\n\nexport function useAppContext(): AppContextType {\n return useContext(AppContext);\n}\n\nexport function useAppDispatch(): Dispatch<ActionSetRelationship | ActionSetScope> {\n return useContext(AppDispatchContext);\n}\n","import { DEFAULT_SCOPE_KEY } from '../graphql-client/queries';\nimport { useConfig } from './config/config-context';\n\ntype ScopeLike = { name: string; isDefault?: boolean };\n\n/**\n * The scope local values fall back to: the one marked `isDefault`, whatever\n * its name. A project without scopes has a single scope named `default`.\n */\nexport function defaultScopeName(scopes: readonly ScopeLike[] | null | undefined): string {\n return scopes?.find((scope) => scope.isDefault)?.name ?? scopes?.[0]?.name ?? DEFAULT_SCOPE_KEY;\n}\n\n/** The current project's default scope. */\nexport function useDefaultScope(): string {\n const { currentProject } = useConfig();\n\n return defaultScopeName(currentProject?.scopes);\n}\n"]}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import'./index.css';import {a,c as c$1,d,f as f$1,g as g$1,e as e$1,i,h as h$2}from'./chunk-4ZWQ44NZ.js';import {b as b$1}from'./chunk-DSLPTDZX.js';import {h}from'./chunk-7KLXWCDS.js';import {f}from'./chunk-
|
|
2
|
-
//# sourceMappingURL=chunk-
|
|
1
|
+
import'./index.css';import {a,c as c$1,d,f as f$1,g as g$1,e as e$1,i,h as h$2}from'./chunk-4ZWQ44NZ.js';import {b as b$1}from'./chunk-DSLPTDZX.js';import {h}from'./chunk-7KLXWCDS.js';import {f}from'./chunk-Y7VBTUNI.js';import {ma}from'./chunk-RULCANNM.js';import {e,g,h as h$1,j as j$1,o,n}from'./chunk-A4DPLZZF.js';import {b}from'./chunk-5JUG4BEF.js';import {c}from'./chunk-X3SHNHHM.js';import {put}from'@vercel/blob/client';import {useMemo,useRef,useEffect,useState}from'react';import {LoaderCircle,EllipsisVerticalIcon,DownloadIcon,ExternalLinkIcon,Trash2Icon}from'lucide-react';import {mutate}from'swr';import {Document}from'@untitledui/file-icons/dist/solid/document.mjs';import {Docx}from'@untitledui/file-icons/dist/solid/docx.mjs';import {Html}from'@untitledui/file-icons/dist/solid/html.mjs';import {Pdf}from'@untitledui/file-icons/dist/solid/pdf.mjs';import {Pptx}from'@untitledui/file-icons/dist/solid/pptx.mjs';import {Txt}from'@untitledui/file-icons/dist/solid/txt.mjs';import {jsx,jsxs,Fragment}from'react/jsx-runtime';var u=class extends Error{code;status;constructor(n,t,r=null){super(t),this.name="KnowledgeApiError",this.code=r,this.status=n;}},k=class extends Error{status;constructor(n,t="Request failed"){super(t),this.name="FetcherError",this.status=n;}},fe=async e=>{let n=await fetch(e,{credentials:"include"});if(!n.ok)throw new k(n.status);return await n.json()};function j(e){let n=`/api/flexkit/${e}/knowledge`;return {entitySources:t=>`${n}/entities/${encodeURIComponent(t)}/sources`,file:t=>`${n}/sources/${encodeURIComponent(t)}/file`,job:t=>`${n}/jobs/${encodeURIComponent(t)}`,links:t=>`${n}/sources/${encodeURIComponent(t)}/links`,passages:(t,{from:r,to:o})=>`${n}/sources/${encodeURIComponent(t)}/passages?from=${String(r)}&to=${String(o)}`,recordSources:({entity:t,recordId:r})=>`${n}/records/${encodeURIComponent(t)}/${encodeURIComponent(r)}/sources`,source:t=>`${n}/sources/${encodeURIComponent(t)}`,sources:(t={})=>{let{limit:r=25,offset:o=0,search:i,status:a}=t,l=new URLSearchParams({limit:r.toString(),offset:o.toString()}),c=i?.trim();return c&&l.set("q",c),a&&l.set("status",a),`${n}/sources?${l.toString()}`},spaces:`/api/flexkit/${e}/spaces`}}function N(e){return typeof e=="string"&&e.includes("/knowledge/sources?")}function J(e){return typeof e=="string"&&(e.includes("/knowledge/records/")||e.includes("/knowledge/entities/")||e.includes("/knowledge/sources/")&&e.endsWith("/links"))}async function L(e,n){let t={};try{t=await e.json();}catch{}return new u(e.status,t.error?String(t.error):n,t.code??null)}function O(e){let n=`/api/flexkit/${e}/knowledge`;async function t(o,i){let{fallback:a,...l}=i,c=await fetch(o,{credentials:"include",headers:{"Content-Type":"application/json",...l.headers??{}},...l});if(!c.ok)throw await L(c,a);return await c.json()}function r(o){return t(`${n}/sources`,{body:JSON.stringify(o),fallback:"The document could not be added.",method:"POST"})}return {addFile:async(o,i)=>{let a=await fetch(`${n}/uploads`,{body:JSON.stringify({filename:o.name,mediaType:o.type||null,sizeBytes:o.size}),credentials:"include",headers:{"Content-Type":"application/json"},method:"POST",signal:i?.signal});if(!a.ok)throw await L(a,"The file could not be uploaded.");let l=await a.json();if(!l.pathname||!l.token||!l.mediaType)throw new u(a.status,"The file could not be uploaded.");return await put(l.pathname,o,{abortSignal:i?.signal,access:"public",contentType:l.mediaType,token:l.token}),r({kind:"upload",pathname:l.pathname})},addUrl:({title:o,url:i})=>r({kind:"url",url:i,...o?{title:o}:{}}),addChatAttachment:({filename:o,url:i})=>r({filename:o,kind:"chat-attachment",url:i}),deleteSource:o=>t(`${n}/sources/${encodeURIComponent(o)}`,{fallback:"The document could not be removed.",method:"DELETE"}),linkSource:(o,i)=>t(`${n}/sources/${encodeURIComponent(o)}/links`,{body:JSON.stringify(i),fallback:"The document could not be attached.",method:"POST"}),reingestSource:o=>t(`${n}/sources/${encodeURIComponent(o)}/reingest`,{fallback:"The document could not be re-indexed.",method:"POST"}),unlinkSource:(o,{entity:i,recordId:a})=>t(`${n}/sources/${encodeURIComponent(o)}/links/${encodeURIComponent(i)}${a===void 0?"":`/${encodeURIComponent(a)}`}`,{fallback:"The document could not be detached.",method:"DELETE"}),updateSource:(o,i)=>t(`${n}/sources/${encodeURIComponent(o)}`,{body:JSON.stringify(i),fallback:"The document could not be updated.",method:"PATCH"})}}var ae={busy:"fk:bg-amber-500/15 fk:text-amber-700 fk:dark:text-amber-400",error:"fk:bg-destructive/15 fk:text-destructive",muted:"fk:bg-muted fk:text-muted-foreground",ready:"fk:bg-emerald-500/15 fk:text-emerald-700 fk:dark:text-emerald-400"};function le(){let{currentProjectId:e}=f();return {api:useMemo(()=>e?O(e):null,[e]),projectId:e}}function de(){return mutate(N,void 0,{revalidate:true})}function Pe(){return mutate(J,void 0,{revalidate:true})}function ce(e,n){return e instanceof u||e instanceof Error?e.message:n}function Ee(e,n){if(e.duplicate){ma.info(`"${e.source.title}" is already in Knowledge.`);return}ma.success(`Added ${n}. Indexing starts now.`);}function _e({children:e}){return jsx("div",{className:"fk:rounded-md fk:border fk:border-dashed fk:p-8 fk:text-center fk:text-sm fk:text-muted-foreground fk:corner-squircle",children:e})}function Me({label:e,tone:n}){return jsxs(b,{className:`fk:border-none fk:corner-squircle ${ae[n]}`,variant:"outline",children:[n==="busy"?jsx(LoaderCircle,{className:"fk:size-3 fk:animate-spin"}):null,e]})}var ue={document:Document,docx:Docx,html:Html,pdf:Pdf,pptx:Pptx,txt:Txt};function ge({className:e="",size:n=24,source:t}){let r=h(t),o=ue[r.icon];return jsx("span",{"aria-label":r.label,className:`fk:flex fk:shrink-0 fk:items-center fk:justify-center ${e}`,"data-knowledge-type":r.icon,role:"img",children:jsx(o,{size:n})})}function Ue({source:e}){return jsx(ge,{size:40,source:e})}function Le({onVisible:e}){let n=useRef(null),t=useRef(e);return t.current=e,useEffect(()=>{let r=n.current;if(!r)return;let o=new IntersectionObserver(i=>{i.some(a=>a.isIntersecting)&&t.current();});return o.observe(r),()=>{o.disconnect();}},[]),jsx("div",{"aria-hidden":true,className:"fk:h-px",ref:n})}function je({isBusy:e$2=false,onOpen:n$1,onRemoved:t,source:r,trigger:o$1="row"}){let{api:i$1,projectId:a$1}=le(),l=b$1(),[c$2,p]=useState(false),[f,b]=useState(false);if(!i$1||!a$1)return null;let X=i$1;async function H(){b(true);try{await X.deleteSource(r.id),ma.success(`Removed "${r.title}".`),p(!1),t(),de();}catch(w){ma.error(ce(w,"The document could not be removed."));}finally{b(false);}}return jsxs(Fragment,{children:[jsxs(e,{children:[jsx(g,{asChild:true,children:jsx(c,{"aria-label":`Actions for ${r.title}`,className:o$1==="row"?"fk:size-8 fk:shrink-0 fk:text-muted-foreground":void 0,"data-knowledge-menu":true,size:"icon-sm",variant:o$1==="row"?"ghost":"outline",children:jsx(EllipsisVerticalIcon,{className:"fk:size-4"})})}),jsxs(h$1,{align:"end",children:[n$1?jsx(j$1,{onSelect:n$1,children:"Open"}):null,r.path?jsx(j$1,{asChild:true,children:jsxs("a",{href:j(a$1).file(r.id),children:[jsx(DownloadIcon,{}),"Download"]})}):null,r.originUrl?jsx(j$1,{asChild:true,children:jsxs("a",{href:r.originUrl,rel:"noreferrer",target:"_blank",children:[jsx(ExternalLinkIcon,{}),"Open page"]})}):null,n$1||r.path||r.originUrl?jsx(o,{}):null,jsxs(j$1,{disabled:!l||e$2,variant:"destructive",onSelect:()=>p(true),children:[jsx(Trash2Icon,{}),"Remove"]}),l?null:jsx(n,{className:"fk:max-w-56 fk:whitespace-normal fk:text-xs fk:font-normal fk:text-muted-foreground",children:"Your member role cannot remove documents."})]})]}),jsx(a,{open:c$2,onOpenChange:p,children:jsxs(c$1,{children:[jsxs(d,{children:[jsx(f$1,{children:"Remove this document?"}),jsxs(g$1,{children:['"',r.title,'" and its indexed passages are deleted for everyone. Answers the agent gave earlier keep their citations, but the document can no longer be opened.']})]}),jsxs(e$1,{children:[jsx(i,{disabled:f,children:"Cancel"}),jsxs(h$2,{disabled:f,onClick:w=>{w.preventDefault(),H();},children:[f?jsx(LoaderCircle,{className:"fk:animate-spin"}):null,"Remove document"]})]})]})})]})}export{k as a,fe as b,j as c,O as d,le as e,de as f,Pe as g,ce as h,Ee as i,_e as j,Me as k,ge as l,Ue as m,Le as n,je as o};//# sourceMappingURL=chunk-4JG3OWQW.js.map
|
|
2
|
+
//# sourceMappingURL=chunk-4JG3OWQW.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/apps/knowledge/api.ts","../src/apps/knowledge/shared.tsx"],"names":["KnowledgeApiError","status","message","code","FetcherError","fetcher","url","response","knowledgePaths","projectId","basePath","entity","sourceId","jobId","from","to","recordId","options","limit","offset","search","params","trimmedSearch","isKnowledgeListKey","key","isKnowledgeLinkKey","readError","fallback","data","createKnowledgeApi","request","init","requestInit","register","body","file","tokenResponse","tokenData","put","title","filename","target","patch","STATUS_TONE_CLASSES","useProjectKnowledge","currentProjectId","useConfig","useMemo","invalidateKnowledgeLists","mutateGlobal","invalidateKnowledgeLinks","describeApiError","error","announceRegistered","result","name","toast","PageMessage","children","jsx","StatusBadge","label","tone","jsxs","Badge","LoaderCircle","FILE_ICONS","Document","Docx","Html","Pdf","Pptx","Txt","KnowledgeTypeIcon","className","size","source","format","getKnowledgeFormat","Icon","SourceIcon","InfiniteScrollSentinel","onVisible","sentinelRef","useRef","onVisibleRef","useEffect","node","observer","entries","entry","SourceActionsMenu","isBusy","onOpen","onRemoved","trigger","api","canMutate","useCanMutate","isConfirmingRemoval","setIsConfirmingRemoval","useState","isRemoving","setIsRemoving","knowledgeApi","remove","removeError","Fragment","DropdownMenu","DropdownMenuTrigger","Button","EllipsisVerticalIcon","DropdownMenuContent","DropdownMenuItem","DownloadIcon","ExternalLinkIcon","DropdownMenuSeparator","Trash2Icon","DropdownMenuLabel","AlertDialog","AlertDialogContent","AlertDialogHeader","AlertDialogTitle","AlertDialogDescription","AlertDialogFooter","AlertDialogCancel","AlertDialogAction","event"],"mappings":"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","file":"chunk-IJECATW3.js","sourcesContent":["import { put } from '@vercel/blob/client';\nimport type {\n KnowledgeJob,\n KnowledgeLinkTarget,\n KnowledgeRecordRef,\n KnowledgeSource,\n KnowledgeSourcePatch,\n KnowledgeSourceStatus,\n RegisterKnowledgeSourceResult,\n} from './knowledge';\n\n/** The platform refused a knowledge request; `code` lets the UI tailor the message. */\nexport class KnowledgeApiError extends Error {\n code: string | null;\n status: number;\n\n constructor(status: number, message: string, code: string | null = null) {\n super(message);\n this.name = 'KnowledgeApiError';\n this.code = code;\n this.status = status;\n }\n}\n\nexport interface ProjectSpace {\n code: string;\n id: string;\n label: string;\n}\n\nexport interface KnowledgeApi {\n /** Uploads a document to the file store, then registers it; resolves once indexing is queued or the file was already there. */\n addFile: (_file: File, _options?: { signal?: AbortSignal }) => Promise<RegisterKnowledgeSourceResult>;\n addUrl: (_input: { title?: string; url: string }) => Promise<RegisterKnowledgeSourceResult>;\n /** Promotes a file the caller attached to a chat: the platform copies it into the knowledge folder. */\n addChatAttachment: (_input: { filename: string; url: string }) => Promise<RegisterKnowledgeSourceResult>;\n deleteSource: (_sourceId: string) => Promise<{ deleted: true }>;\n /** Attaches the document to a record, or to every record of an entity type; `linked` is false when it already was. */\n linkSource: (_sourceId: string, _target: KnowledgeLinkTarget) => Promise<{ linked: boolean }>;\n reingestSource: (_sourceId: string) => Promise<{ job: KnowledgeJob }>;\n unlinkSource: (_sourceId: string, _target: KnowledgeLinkTarget) => Promise<{ unlinked: boolean }>;\n updateSource: (_sourceId: string, _patch: KnowledgeSourcePatch) => Promise<{ source: KnowledgeSource }>;\n}\n\nexport class FetcherError extends Error {\n status: number;\n\n constructor(status: number, message = 'Request failed') {\n super(message);\n this.name = 'FetcherError';\n this.status = status;\n }\n}\n\nexport const fetcher = async <T>(url: string): Promise<T> => {\n const response = await fetch(url, { credentials: 'include' });\n\n if (!response.ok) {\n throw new FetcherError(response.status);\n }\n\n return (await response.json()) as T;\n};\n\nexport function knowledgePaths(projectId: string): {\n /** The documents attached to every record of an entity type. */\n entitySources: (_entity: string) => string;\n /** The original file of an uploaded document, served under its name. */\n file: (_sourceId: string) => string;\n job: (_jobId: string) => string;\n /** The records a document is attached to, and the entity types it applies to. */\n links: (_sourceId: string) => string;\n passages: (_sourceId: string, _options: { from: number; to: number }) => string;\n /** The documents attached to a record. */\n recordSources: (_record: KnowledgeRecordRef) => string;\n source: (_sourceId: string) => string;\n sources: (_options?: { limit?: number; offset?: number; search?: string; status?: KnowledgeSourceStatus }) => string;\n spaces: string;\n} {\n const basePath = `/api/flexkit/${projectId}/knowledge`;\n\n return {\n entitySources: (entity) => `${basePath}/entities/${encodeURIComponent(entity)}/sources`,\n file: (sourceId) => `${basePath}/sources/${encodeURIComponent(sourceId)}/file`,\n job: (jobId) => `${basePath}/jobs/${encodeURIComponent(jobId)}`,\n links: (sourceId) => `${basePath}/sources/${encodeURIComponent(sourceId)}/links`,\n passages: (sourceId, { from, to }) =>\n `${basePath}/sources/${encodeURIComponent(sourceId)}/passages?from=${String(from)}&to=${String(to)}`,\n recordSources: ({ entity, recordId }) =>\n `${basePath}/records/${encodeURIComponent(entity)}/${encodeURIComponent(recordId)}/sources`,\n source: (sourceId) => `${basePath}/sources/${encodeURIComponent(sourceId)}`,\n sources: (options = {}) => {\n const { limit = 25, offset = 0, search, status } = options;\n const params = new URLSearchParams({ limit: limit.toString(), offset: offset.toString() });\n const trimmedSearch = search?.trim();\n\n if (trimmedSearch) {\n params.set('q', trimmedSearch);\n }\n\n if (status) {\n params.set('status', status);\n }\n\n return `${basePath}/sources?${params.toString()}`;\n },\n spaces: `/api/flexkit/${projectId}/spaces`,\n };\n}\n\n/** Whether an SWR key is a page of the document list, whatever its filters. */\nexport function isKnowledgeListKey(key: unknown): boolean {\n return typeof key === 'string' && key.includes('/knowledge/sources?');\n}\n\n/** Whether an SWR key lists the documents of a record or an entity type, or the links of a document. */\nexport function isKnowledgeLinkKey(key: unknown): boolean {\n return (\n typeof key === 'string' &&\n (key.includes('/knowledge/records/') ||\n key.includes('/knowledge/entities/') ||\n (key.includes('/knowledge/sources/') && key.endsWith('/links')))\n );\n}\n\nasync function readError(response: Response, fallback: string): Promise<KnowledgeApiError> {\n let data: { code?: string; error?: string } = {};\n\n try {\n data = (await response.json()) as { code?: string; error?: string };\n } catch {\n // Non-JSON error bodies keep the fallback message.\n }\n\n return new KnowledgeApiError(response.status, data.error ? String(data.error) : fallback, data.code ?? null);\n}\n\nexport function createKnowledgeApi(projectId: string): KnowledgeApi {\n const basePath = `/api/flexkit/${projectId}/knowledge`;\n\n async function request<T>(url: string, init: RequestInit & { fallback: string }): Promise<T> {\n const { fallback, ...requestInit } = init;\n const response = await fetch(url, {\n credentials: 'include',\n headers: { 'Content-Type': 'application/json', ...(requestInit.headers ?? {}) },\n ...requestInit,\n });\n\n if (!response.ok) {\n throw await readError(response, fallback);\n }\n\n return (await response.json()) as T;\n }\n\n function register(body: Record<string, unknown>): Promise<RegisterKnowledgeSourceResult> {\n return request<RegisterKnowledgeSourceResult>(`${basePath}/sources`, {\n body: JSON.stringify(body),\n fallback: 'The document could not be added.',\n method: 'POST',\n });\n }\n\n return {\n addFile: async (file, options) => {\n // The platform issues a token pinned to one pathname, type and size; the\n // browser writes the bytes to the store itself, so a 20 MB document never\n // crosses the API function body limit. Registration then hashes the blob.\n const tokenResponse = await fetch(`${basePath}/uploads`, {\n body: JSON.stringify({ filename: file.name, mediaType: file.type || null, sizeBytes: file.size }),\n credentials: 'include',\n headers: { 'Content-Type': 'application/json' },\n method: 'POST',\n signal: options?.signal,\n });\n\n if (!tokenResponse.ok) {\n throw await readError(tokenResponse, 'The file could not be uploaded.');\n }\n\n const tokenData = (await tokenResponse.json()) as { mediaType?: string; pathname?: string; token?: string };\n\n if (!tokenData.pathname || !tokenData.token || !tokenData.mediaType) {\n throw new KnowledgeApiError(tokenResponse.status, 'The file could not be uploaded.');\n }\n\n await put(tokenData.pathname, file, {\n abortSignal: options?.signal,\n access: 'public',\n contentType: tokenData.mediaType,\n token: tokenData.token,\n });\n\n return register({ kind: 'upload', pathname: tokenData.pathname });\n },\n addUrl: ({ title, url }) => register({ kind: 'url', url, ...(title ? { title } : {}) }),\n addChatAttachment: ({ filename, url }) => register({ filename, kind: 'chat-attachment', url }),\n deleteSource: (sourceId) =>\n request<{ deleted: true }>(`${basePath}/sources/${encodeURIComponent(sourceId)}`, {\n fallback: 'The document could not be removed.',\n method: 'DELETE',\n }),\n linkSource: (sourceId, target) =>\n request<{ linked: boolean }>(`${basePath}/sources/${encodeURIComponent(sourceId)}/links`, {\n body: JSON.stringify(target),\n fallback: 'The document could not be attached.',\n method: 'POST',\n }),\n reingestSource: (sourceId) =>\n request<{ job: KnowledgeJob }>(`${basePath}/sources/${encodeURIComponent(sourceId)}/reingest`, {\n fallback: 'The document could not be re-indexed.',\n method: 'POST',\n }),\n unlinkSource: (sourceId, { entity, recordId }) =>\n request<{ unlinked: boolean }>(\n `${basePath}/sources/${encodeURIComponent(sourceId)}/links/${encodeURIComponent(entity)}${\n recordId === undefined ? '' : `/${encodeURIComponent(recordId)}`\n }`,\n { fallback: 'The document could not be detached.', method: 'DELETE' }\n ),\n updateSource: (sourceId, patch) =>\n request<{ source: KnowledgeSource }>(`${basePath}/sources/${encodeURIComponent(sourceId)}`, {\n body: JSON.stringify(patch),\n fallback: 'The document could not be updated.',\n method: 'PATCH',\n }),\n };\n}\n","import type { JSX, MouseEvent } from 'react';\nimport { useEffect, useMemo, useRef, useState } from 'react';\nimport { DownloadIcon, EllipsisVerticalIcon, ExternalLinkIcon, LoaderCircle, Trash2Icon } from 'lucide-react';\nimport { mutate as mutateGlobal } from 'swr';\n// File type icons: Untitled UI's free file icons, Solid variant. The set is\n// published as the MIT package `@untitledui/file-icons`; the page below shows\n// every icon and offers each as SVG or JSX should another format need one.\n// https://www.untitledui.com/resources/file-icons\nimport { Document } from '@untitledui/file-icons/dist/solid/document.mjs';\nimport { Docx } from '@untitledui/file-icons/dist/solid/docx.mjs';\nimport { Html } from '@untitledui/file-icons/dist/solid/html.mjs';\nimport { Pdf } from '@untitledui/file-icons/dist/solid/pdf.mjs';\nimport { Pptx } from '@untitledui/file-icons/dist/solid/pptx.mjs';\nimport { Txt } from '@untitledui/file-icons/dist/solid/txt.mjs';\nimport { useConfig } from '../../core/config/config-context';\nimport { useCanMutate } from '../../core/permissions';\nimport {\n Badge,\n Button,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n toast,\n} from '../../ui';\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n} from '../../ui/primitives/alert-dialog';\nimport {\n createKnowledgeApi,\n isKnowledgeLinkKey,\n isKnowledgeListKey,\n KnowledgeApiError,\n knowledgePaths,\n type KnowledgeApi,\n} from './api';\nimport {\n getKnowledgeFormat,\n type KnowledgeFileIcon,\n type KnowledgeSource,\n type KnowledgeStatusTone,\n type RegisterKnowledgeSourceResult,\n} from './knowledge';\n\nconst STATUS_TONE_CLASSES: { [tone in KnowledgeStatusTone]: string } = {\n busy: 'fk:bg-amber-500/15 fk:text-amber-700 fk:dark:text-amber-400',\n error: 'fk:bg-destructive/15 fk:text-destructive',\n muted: 'fk:bg-muted fk:text-muted-foreground',\n ready: 'fk:bg-emerald-500/15 fk:text-emerald-700 fk:dark:text-emerald-400',\n};\n\nexport function useProjectKnowledge(): { api: KnowledgeApi | null; projectId: string | undefined } {\n const { currentProjectId } = useConfig();\n const api = useMemo(() => (currentProjectId ? createKnowledgeApi(currentProjectId) : null), [currentProjectId]);\n\n return { api, projectId: currentProjectId };\n}\n\n/** Drops every cached page of the document list, so the next visit fetches it afresh. */\nexport function invalidateKnowledgeLists(): Promise<unknown> {\n return mutateGlobal(isKnowledgeListKey, undefined, { revalidate: true });\n}\n\n/** Drops every cached link listing (a record's documents, a document's records) after a link changed. */\nexport function invalidateKnowledgeLinks(): Promise<unknown> {\n return mutateGlobal(isKnowledgeLinkKey, undefined, { revalidate: true });\n}\n\nexport function describeApiError(error: unknown, fallback: string): string {\n if (error instanceof KnowledgeApiError) {\n return error.message;\n }\n\n return error instanceof Error ? error.message : fallback;\n}\n\n/** What the user hears once a document was registered. */\nexport function announceRegistered(result: RegisterKnowledgeSourceResult, name: string): void {\n if (result.duplicate) {\n toast.info(`\"${result.source.title}\" is already in Knowledge.`);\n\n return;\n }\n\n toast.success(`Added ${name}. Indexing starts now.`);\n}\n\nexport function PageMessage({ children }: { children: string }): JSX.Element {\n return (\n <div className=\"fk:rounded-md fk:border fk:border-dashed fk:p-8 fk:text-center fk:text-sm fk:text-muted-foreground fk:corner-squircle\">\n {children}\n </div>\n );\n}\n\nexport function StatusBadge({ label, tone }: { label: string; tone: KnowledgeStatusTone }): JSX.Element {\n return (\n <Badge className={`fk:border-none fk:corner-squircle ${STATUS_TONE_CLASSES[tone]}`} variant=\"outline\">\n {tone === 'busy' ? <LoaderCircle className=\"fk:size-3 fk:animate-spin\" /> : null}\n {label}\n </Badge>\n );\n}\n\nconst FILE_ICONS: { [icon in KnowledgeFileIcon]: typeof Pdf } = {\n document: Document,\n docx: Docx,\n html: Html,\n pdf: Pdf,\n pptx: Pptx,\n txt: Txt,\n};\n\n/** The document's format as its file icon; the format's name is what a screen reader hears. */\nexport function KnowledgeTypeIcon({\n className = '',\n size = 24,\n source,\n}: {\n className?: string;\n size?: number;\n source: Pick<KnowledgeSource, 'kind' | 'mimeType'>;\n}): JSX.Element {\n const format = getKnowledgeFormat(source);\n const Icon = FILE_ICONS[format.icon];\n\n return (\n <span\n aria-label={format.label}\n className={`fk:flex fk:shrink-0 fk:items-center fk:justify-center ${className}`}\n data-knowledge-type={format.icon}\n role=\"img\"\n >\n <Icon size={size} />\n </span>\n );\n}\n\n/** The larger file icon of the document page and the record panel: the same icon as the list, at 40px. */\nexport function SourceIcon({ source }: { source: Pick<KnowledgeSource, 'kind' | 'mimeType'> }): JSX.Element {\n return <KnowledgeTypeIcon size={40} source={source} />;\n}\n\nexport function InfiniteScrollSentinel({ onVisible }: { onVisible: () => void }): JSX.Element {\n const sentinelRef = useRef<HTMLDivElement>(null);\n const onVisibleRef = useRef(onVisible);\n\n onVisibleRef.current = onVisible;\n\n useEffect(() => {\n const node = sentinelRef.current;\n\n if (!node) {\n return;\n }\n\n const observer = new IntersectionObserver((entries) => {\n if (entries.some((entry) => entry.isIntersecting)) {\n onVisibleRef.current();\n }\n });\n\n observer.observe(node);\n\n return () => {\n observer.disconnect();\n };\n }, []);\n\n return <div aria-hidden className=\"fk:h-px\" ref={sentinelRef} />;\n}\n\n/**\n * The actions of one document, behind a three-dots button: open (lists\n * only), download the original file (web pages open their address instead)\n * and remove, behind one confirmation. The list and the document page share\n * it so the copy, the download link and the busy rules stay the same.\n */\nexport function SourceActionsMenu({\n isBusy = false,\n onOpen,\n onRemoved,\n source,\n trigger = 'row',\n}: {\n /** Another action on the document is in flight; removing waits for it. */\n isBusy?: boolean;\n /** Offered as the first item when given (the document page is already open). */\n onOpen?: () => void;\n /** The document is gone: drop it from the list, or leave its page. The list invalidation is done here. */\n onRemoved: () => void;\n source: KnowledgeSource;\n /** How the button looks: a quiet icon in a row or card, an outlined one next to page actions. */\n trigger?: 'row' | 'page';\n}): JSX.Element | null {\n const { api, projectId } = useProjectKnowledge();\n const canMutate = useCanMutate();\n const [isConfirmingRemoval, setIsConfirmingRemoval] = useState(false);\n const [isRemoving, setIsRemoving] = useState(false);\n\n if (!api || !projectId) {\n return null;\n }\n\n const knowledgeApi = api;\n\n async function remove(): Promise<void> {\n setIsRemoving(true);\n\n try {\n await knowledgeApi.deleteSource(source.id);\n toast.success(`Removed \"${source.title}\".`);\n setIsConfirmingRemoval(false);\n onRemoved();\n void invalidateKnowledgeLists();\n } catch (removeError) {\n toast.error(describeApiError(removeError, 'The document could not be removed.'));\n } finally {\n setIsRemoving(false);\n }\n }\n\n return (\n <>\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n aria-label={`Actions for ${source.title}`}\n className={trigger === 'row' ? 'fk:size-8 fk:shrink-0 fk:text-muted-foreground' : undefined}\n data-knowledge-menu\n size=\"icon-sm\"\n variant={trigger === 'row' ? 'ghost' : 'outline'}\n >\n <EllipsisVerticalIcon className=\"fk:size-4\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n {onOpen ? <DropdownMenuItem onSelect={onOpen}>Open</DropdownMenuItem> : null}\n {source.path ? (\n <DropdownMenuItem asChild>\n <a href={knowledgePaths(projectId).file(source.id)}>\n <DownloadIcon />\n Download\n </a>\n </DropdownMenuItem>\n ) : null}\n {source.originUrl ? (\n <DropdownMenuItem asChild>\n <a href={source.originUrl} rel=\"noreferrer\" target=\"_blank\">\n <ExternalLinkIcon />\n Open page\n </a>\n </DropdownMenuItem>\n ) : null}\n {onOpen || source.path || source.originUrl ? <DropdownMenuSeparator /> : null}\n <DropdownMenuItem\n disabled={!canMutate || isBusy}\n variant=\"destructive\"\n onSelect={() => setIsConfirmingRemoval(true)}\n >\n <Trash2Icon />\n Remove\n </DropdownMenuItem>\n {canMutate ? null : (\n <DropdownMenuLabel className=\"fk:max-w-56 fk:whitespace-normal fk:text-xs fk:font-normal fk:text-muted-foreground\">\n Your member role cannot remove documents.\n </DropdownMenuLabel>\n )}\n </DropdownMenuContent>\n </DropdownMenu>\n <AlertDialog open={isConfirmingRemoval} onOpenChange={setIsConfirmingRemoval}>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>Remove this document?</AlertDialogTitle>\n <AlertDialogDescription>\n \"{source.title}\" and its indexed passages are deleted for everyone. Answers the agent gave earlier keep\n their citations, but the document can no longer be opened.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel disabled={isRemoving}>Cancel</AlertDialogCancel>\n <AlertDialogAction\n disabled={isRemoving}\n onClick={(event: MouseEvent) => {\n event.preventDefault();\n void remove();\n }}\n >\n {isRemoving ? <LoaderCircle className=\"fk:animate-spin\" /> : null}\n Remove document\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n </>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/apps/knowledge/api.ts","../src/apps/knowledge/shared.tsx"],"names":["KnowledgeApiError","status","message","code","FetcherError","fetcher","url","response","knowledgePaths","projectId","basePath","entity","sourceId","jobId","from","to","recordId","options","limit","offset","search","params","trimmedSearch","isKnowledgeListKey","key","isKnowledgeLinkKey","readError","fallback","data","createKnowledgeApi","request","init","requestInit","register","body","file","tokenResponse","tokenData","put","title","filename","target","patch","STATUS_TONE_CLASSES","useProjectKnowledge","currentProjectId","useConfig","useMemo","invalidateKnowledgeLists","mutateGlobal","invalidateKnowledgeLinks","describeApiError","error","announceRegistered","result","name","toast","PageMessage","children","jsx","StatusBadge","label","tone","jsxs","Badge","LoaderCircle","FILE_ICONS","Document","Docx","Html","Pdf","Pptx","Txt","KnowledgeTypeIcon","className","size","source","format","getKnowledgeFormat","Icon","SourceIcon","InfiniteScrollSentinel","onVisible","sentinelRef","useRef","onVisibleRef","useEffect","node","observer","entries","entry","SourceActionsMenu","isBusy","onOpen","onRemoved","trigger","api","canMutate","useCanMutate","isConfirmingRemoval","setIsConfirmingRemoval","useState","isRemoving","setIsRemoving","knowledgeApi","remove","removeError","Fragment","DropdownMenu","DropdownMenuTrigger","Button","EllipsisVerticalIcon","DropdownMenuContent","DropdownMenuItem","DownloadIcon","ExternalLinkIcon","DropdownMenuSeparator","Trash2Icon","DropdownMenuLabel","AlertDialog","AlertDialogContent","AlertDialogHeader","AlertDialogTitle","AlertDialogDescription","AlertDialogFooter","AlertDialogCancel","AlertDialogAction","event"],"mappings":"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","file":"chunk-4JG3OWQW.js","sourcesContent":["import { put } from '@vercel/blob/client';\nimport type {\n KnowledgeJob,\n KnowledgeLinkTarget,\n KnowledgeRecordRef,\n KnowledgeSource,\n KnowledgeSourcePatch,\n KnowledgeSourceStatus,\n RegisterKnowledgeSourceResult,\n} from './knowledge';\n\n/** The platform refused a knowledge request; `code` lets the UI tailor the message. */\nexport class KnowledgeApiError extends Error {\n code: string | null;\n status: number;\n\n constructor(status: number, message: string, code: string | null = null) {\n super(message);\n this.name = 'KnowledgeApiError';\n this.code = code;\n this.status = status;\n }\n}\n\nexport interface ProjectSpace {\n code: string;\n id: string;\n label: string;\n}\n\nexport interface KnowledgeApi {\n /** Uploads a document to the file store, then registers it; resolves once indexing is queued or the file was already there. */\n addFile: (_file: File, _options?: { signal?: AbortSignal }) => Promise<RegisterKnowledgeSourceResult>;\n addUrl: (_input: { title?: string; url: string }) => Promise<RegisterKnowledgeSourceResult>;\n /** Promotes a file the caller attached to a chat: the platform copies it into the knowledge folder. */\n addChatAttachment: (_input: { filename: string; url: string }) => Promise<RegisterKnowledgeSourceResult>;\n deleteSource: (_sourceId: string) => Promise<{ deleted: true }>;\n /** Attaches the document to a record, or to every record of an entity type; `linked` is false when it already was. */\n linkSource: (_sourceId: string, _target: KnowledgeLinkTarget) => Promise<{ linked: boolean }>;\n reingestSource: (_sourceId: string) => Promise<{ job: KnowledgeJob }>;\n unlinkSource: (_sourceId: string, _target: KnowledgeLinkTarget) => Promise<{ unlinked: boolean }>;\n updateSource: (_sourceId: string, _patch: KnowledgeSourcePatch) => Promise<{ source: KnowledgeSource }>;\n}\n\nexport class FetcherError extends Error {\n status: number;\n\n constructor(status: number, message = 'Request failed') {\n super(message);\n this.name = 'FetcherError';\n this.status = status;\n }\n}\n\nexport const fetcher = async <T>(url: string): Promise<T> => {\n const response = await fetch(url, { credentials: 'include' });\n\n if (!response.ok) {\n throw new FetcherError(response.status);\n }\n\n return (await response.json()) as T;\n};\n\nexport function knowledgePaths(projectId: string): {\n /** The documents attached to every record of an entity type. */\n entitySources: (_entity: string) => string;\n /** The original file of an uploaded document, served under its name. */\n file: (_sourceId: string) => string;\n job: (_jobId: string) => string;\n /** The records a document is attached to, and the entity types it applies to. */\n links: (_sourceId: string) => string;\n passages: (_sourceId: string, _options: { from: number; to: number }) => string;\n /** The documents attached to a record. */\n recordSources: (_record: KnowledgeRecordRef) => string;\n source: (_sourceId: string) => string;\n sources: (_options?: { limit?: number; offset?: number; search?: string; status?: KnowledgeSourceStatus }) => string;\n spaces: string;\n} {\n const basePath = `/api/flexkit/${projectId}/knowledge`;\n\n return {\n entitySources: (entity) => `${basePath}/entities/${encodeURIComponent(entity)}/sources`,\n file: (sourceId) => `${basePath}/sources/${encodeURIComponent(sourceId)}/file`,\n job: (jobId) => `${basePath}/jobs/${encodeURIComponent(jobId)}`,\n links: (sourceId) => `${basePath}/sources/${encodeURIComponent(sourceId)}/links`,\n passages: (sourceId, { from, to }) =>\n `${basePath}/sources/${encodeURIComponent(sourceId)}/passages?from=${String(from)}&to=${String(to)}`,\n recordSources: ({ entity, recordId }) =>\n `${basePath}/records/${encodeURIComponent(entity)}/${encodeURIComponent(recordId)}/sources`,\n source: (sourceId) => `${basePath}/sources/${encodeURIComponent(sourceId)}`,\n sources: (options = {}) => {\n const { limit = 25, offset = 0, search, status } = options;\n const params = new URLSearchParams({ limit: limit.toString(), offset: offset.toString() });\n const trimmedSearch = search?.trim();\n\n if (trimmedSearch) {\n params.set('q', trimmedSearch);\n }\n\n if (status) {\n params.set('status', status);\n }\n\n return `${basePath}/sources?${params.toString()}`;\n },\n spaces: `/api/flexkit/${projectId}/spaces`,\n };\n}\n\n/** Whether an SWR key is a page of the document list, whatever its filters. */\nexport function isKnowledgeListKey(key: unknown): boolean {\n return typeof key === 'string' && key.includes('/knowledge/sources?');\n}\n\n/** Whether an SWR key lists the documents of a record or an entity type, or the links of a document. */\nexport function isKnowledgeLinkKey(key: unknown): boolean {\n return (\n typeof key === 'string' &&\n (key.includes('/knowledge/records/') ||\n key.includes('/knowledge/entities/') ||\n (key.includes('/knowledge/sources/') && key.endsWith('/links')))\n );\n}\n\nasync function readError(response: Response, fallback: string): Promise<KnowledgeApiError> {\n let data: { code?: string; error?: string } = {};\n\n try {\n data = (await response.json()) as { code?: string; error?: string };\n } catch {\n // Non-JSON error bodies keep the fallback message.\n }\n\n return new KnowledgeApiError(response.status, data.error ? String(data.error) : fallback, data.code ?? null);\n}\n\nexport function createKnowledgeApi(projectId: string): KnowledgeApi {\n const basePath = `/api/flexkit/${projectId}/knowledge`;\n\n async function request<T>(url: string, init: RequestInit & { fallback: string }): Promise<T> {\n const { fallback, ...requestInit } = init;\n const response = await fetch(url, {\n credentials: 'include',\n headers: { 'Content-Type': 'application/json', ...(requestInit.headers ?? {}) },\n ...requestInit,\n });\n\n if (!response.ok) {\n throw await readError(response, fallback);\n }\n\n return (await response.json()) as T;\n }\n\n function register(body: Record<string, unknown>): Promise<RegisterKnowledgeSourceResult> {\n return request<RegisterKnowledgeSourceResult>(`${basePath}/sources`, {\n body: JSON.stringify(body),\n fallback: 'The document could not be added.',\n method: 'POST',\n });\n }\n\n return {\n addFile: async (file, options) => {\n // The platform issues a token pinned to one pathname, type and size; the\n // browser writes the bytes to the store itself, so a 20 MB document never\n // crosses the API function body limit. Registration then hashes the blob.\n const tokenResponse = await fetch(`${basePath}/uploads`, {\n body: JSON.stringify({ filename: file.name, mediaType: file.type || null, sizeBytes: file.size }),\n credentials: 'include',\n headers: { 'Content-Type': 'application/json' },\n method: 'POST',\n signal: options?.signal,\n });\n\n if (!tokenResponse.ok) {\n throw await readError(tokenResponse, 'The file could not be uploaded.');\n }\n\n const tokenData = (await tokenResponse.json()) as { mediaType?: string; pathname?: string; token?: string };\n\n if (!tokenData.pathname || !tokenData.token || !tokenData.mediaType) {\n throw new KnowledgeApiError(tokenResponse.status, 'The file could not be uploaded.');\n }\n\n await put(tokenData.pathname, file, {\n abortSignal: options?.signal,\n access: 'public',\n contentType: tokenData.mediaType,\n token: tokenData.token,\n });\n\n return register({ kind: 'upload', pathname: tokenData.pathname });\n },\n addUrl: ({ title, url }) => register({ kind: 'url', url, ...(title ? { title } : {}) }),\n addChatAttachment: ({ filename, url }) => register({ filename, kind: 'chat-attachment', url }),\n deleteSource: (sourceId) =>\n request<{ deleted: true }>(`${basePath}/sources/${encodeURIComponent(sourceId)}`, {\n fallback: 'The document could not be removed.',\n method: 'DELETE',\n }),\n linkSource: (sourceId, target) =>\n request<{ linked: boolean }>(`${basePath}/sources/${encodeURIComponent(sourceId)}/links`, {\n body: JSON.stringify(target),\n fallback: 'The document could not be attached.',\n method: 'POST',\n }),\n reingestSource: (sourceId) =>\n request<{ job: KnowledgeJob }>(`${basePath}/sources/${encodeURIComponent(sourceId)}/reingest`, {\n fallback: 'The document could not be re-indexed.',\n method: 'POST',\n }),\n unlinkSource: (sourceId, { entity, recordId }) =>\n request<{ unlinked: boolean }>(\n `${basePath}/sources/${encodeURIComponent(sourceId)}/links/${encodeURIComponent(entity)}${\n recordId === undefined ? '' : `/${encodeURIComponent(recordId)}`\n }`,\n { fallback: 'The document could not be detached.', method: 'DELETE' }\n ),\n updateSource: (sourceId, patch) =>\n request<{ source: KnowledgeSource }>(`${basePath}/sources/${encodeURIComponent(sourceId)}`, {\n body: JSON.stringify(patch),\n fallback: 'The document could not be updated.',\n method: 'PATCH',\n }),\n };\n}\n","import type { JSX, MouseEvent } from 'react';\nimport { useEffect, useMemo, useRef, useState } from 'react';\nimport { DownloadIcon, EllipsisVerticalIcon, ExternalLinkIcon, LoaderCircle, Trash2Icon } from 'lucide-react';\nimport { mutate as mutateGlobal } from 'swr';\n// File type icons: Untitled UI's free file icons, Solid variant. The set is\n// published as the MIT package `@untitledui/file-icons`; the page below shows\n// every icon and offers each as SVG or JSX should another format need one.\n// https://www.untitledui.com/resources/file-icons\nimport { Document } from '@untitledui/file-icons/dist/solid/document.mjs';\nimport { Docx } from '@untitledui/file-icons/dist/solid/docx.mjs';\nimport { Html } from '@untitledui/file-icons/dist/solid/html.mjs';\nimport { Pdf } from '@untitledui/file-icons/dist/solid/pdf.mjs';\nimport { Pptx } from '@untitledui/file-icons/dist/solid/pptx.mjs';\nimport { Txt } from '@untitledui/file-icons/dist/solid/txt.mjs';\nimport { useConfig } from '../../core/config/config-context';\nimport { useCanMutate } from '../../core/permissions';\nimport {\n Badge,\n Button,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n toast,\n} from '../../ui';\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n} from '../../ui/primitives/alert-dialog';\nimport {\n createKnowledgeApi,\n isKnowledgeLinkKey,\n isKnowledgeListKey,\n KnowledgeApiError,\n knowledgePaths,\n type KnowledgeApi,\n} from './api';\nimport {\n getKnowledgeFormat,\n type KnowledgeFileIcon,\n type KnowledgeSource,\n type KnowledgeStatusTone,\n type RegisterKnowledgeSourceResult,\n} from './knowledge';\n\nconst STATUS_TONE_CLASSES: { [tone in KnowledgeStatusTone]: string } = {\n busy: 'fk:bg-amber-500/15 fk:text-amber-700 fk:dark:text-amber-400',\n error: 'fk:bg-destructive/15 fk:text-destructive',\n muted: 'fk:bg-muted fk:text-muted-foreground',\n ready: 'fk:bg-emerald-500/15 fk:text-emerald-700 fk:dark:text-emerald-400',\n};\n\nexport function useProjectKnowledge(): { api: KnowledgeApi | null; projectId: string | undefined } {\n const { currentProjectId } = useConfig();\n const api = useMemo(() => (currentProjectId ? createKnowledgeApi(currentProjectId) : null), [currentProjectId]);\n\n return { api, projectId: currentProjectId };\n}\n\n/** Drops every cached page of the document list, so the next visit fetches it afresh. */\nexport function invalidateKnowledgeLists(): Promise<unknown> {\n return mutateGlobal(isKnowledgeListKey, undefined, { revalidate: true });\n}\n\n/** Drops every cached link listing (a record's documents, a document's records) after a link changed. */\nexport function invalidateKnowledgeLinks(): Promise<unknown> {\n return mutateGlobal(isKnowledgeLinkKey, undefined, { revalidate: true });\n}\n\nexport function describeApiError(error: unknown, fallback: string): string {\n if (error instanceof KnowledgeApiError) {\n return error.message;\n }\n\n return error instanceof Error ? error.message : fallback;\n}\n\n/** What the user hears once a document was registered. */\nexport function announceRegistered(result: RegisterKnowledgeSourceResult, name: string): void {\n if (result.duplicate) {\n toast.info(`\"${result.source.title}\" is already in Knowledge.`);\n\n return;\n }\n\n toast.success(`Added ${name}. Indexing starts now.`);\n}\n\nexport function PageMessage({ children }: { children: string }): JSX.Element {\n return (\n <div className=\"fk:rounded-md fk:border fk:border-dashed fk:p-8 fk:text-center fk:text-sm fk:text-muted-foreground fk:corner-squircle\">\n {children}\n </div>\n );\n}\n\nexport function StatusBadge({ label, tone }: { label: string; tone: KnowledgeStatusTone }): JSX.Element {\n return (\n <Badge className={`fk:border-none fk:corner-squircle ${STATUS_TONE_CLASSES[tone]}`} variant=\"outline\">\n {tone === 'busy' ? <LoaderCircle className=\"fk:size-3 fk:animate-spin\" /> : null}\n {label}\n </Badge>\n );\n}\n\nconst FILE_ICONS: { [icon in KnowledgeFileIcon]: typeof Pdf } = {\n document: Document,\n docx: Docx,\n html: Html,\n pdf: Pdf,\n pptx: Pptx,\n txt: Txt,\n};\n\n/** The document's format as its file icon; the format's name is what a screen reader hears. */\nexport function KnowledgeTypeIcon({\n className = '',\n size = 24,\n source,\n}: {\n className?: string;\n size?: number;\n source: Pick<KnowledgeSource, 'kind' | 'mimeType'>;\n}): JSX.Element {\n const format = getKnowledgeFormat(source);\n const Icon = FILE_ICONS[format.icon];\n\n return (\n <span\n aria-label={format.label}\n className={`fk:flex fk:shrink-0 fk:items-center fk:justify-center ${className}`}\n data-knowledge-type={format.icon}\n role=\"img\"\n >\n <Icon size={size} />\n </span>\n );\n}\n\n/** The larger file icon of the document page and the record panel: the same icon as the list, at 40px. */\nexport function SourceIcon({ source }: { source: Pick<KnowledgeSource, 'kind' | 'mimeType'> }): JSX.Element {\n return <KnowledgeTypeIcon size={40} source={source} />;\n}\n\nexport function InfiniteScrollSentinel({ onVisible }: { onVisible: () => void }): JSX.Element {\n const sentinelRef = useRef<HTMLDivElement>(null);\n const onVisibleRef = useRef(onVisible);\n\n onVisibleRef.current = onVisible;\n\n useEffect(() => {\n const node = sentinelRef.current;\n\n if (!node) {\n return;\n }\n\n const observer = new IntersectionObserver((entries) => {\n if (entries.some((entry) => entry.isIntersecting)) {\n onVisibleRef.current();\n }\n });\n\n observer.observe(node);\n\n return () => {\n observer.disconnect();\n };\n }, []);\n\n return <div aria-hidden className=\"fk:h-px\" ref={sentinelRef} />;\n}\n\n/**\n * The actions of one document, behind a three-dots button: open (lists\n * only), download the original file (web pages open their address instead)\n * and remove, behind one confirmation. The list and the document page share\n * it so the copy, the download link and the busy rules stay the same.\n */\nexport function SourceActionsMenu({\n isBusy = false,\n onOpen,\n onRemoved,\n source,\n trigger = 'row',\n}: {\n /** Another action on the document is in flight; removing waits for it. */\n isBusy?: boolean;\n /** Offered as the first item when given (the document page is already open). */\n onOpen?: () => void;\n /** The document is gone: drop it from the list, or leave its page. The list invalidation is done here. */\n onRemoved: () => void;\n source: KnowledgeSource;\n /** How the button looks: a quiet icon in a row or card, an outlined one next to page actions. */\n trigger?: 'row' | 'page';\n}): JSX.Element | null {\n const { api, projectId } = useProjectKnowledge();\n const canMutate = useCanMutate();\n const [isConfirmingRemoval, setIsConfirmingRemoval] = useState(false);\n const [isRemoving, setIsRemoving] = useState(false);\n\n if (!api || !projectId) {\n return null;\n }\n\n const knowledgeApi = api;\n\n async function remove(): Promise<void> {\n setIsRemoving(true);\n\n try {\n await knowledgeApi.deleteSource(source.id);\n toast.success(`Removed \"${source.title}\".`);\n setIsConfirmingRemoval(false);\n onRemoved();\n void invalidateKnowledgeLists();\n } catch (removeError) {\n toast.error(describeApiError(removeError, 'The document could not be removed.'));\n } finally {\n setIsRemoving(false);\n }\n }\n\n return (\n <>\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n aria-label={`Actions for ${source.title}`}\n className={trigger === 'row' ? 'fk:size-8 fk:shrink-0 fk:text-muted-foreground' : undefined}\n data-knowledge-menu\n size=\"icon-sm\"\n variant={trigger === 'row' ? 'ghost' : 'outline'}\n >\n <EllipsisVerticalIcon className=\"fk:size-4\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n {onOpen ? <DropdownMenuItem onSelect={onOpen}>Open</DropdownMenuItem> : null}\n {source.path ? (\n <DropdownMenuItem asChild>\n <a href={knowledgePaths(projectId).file(source.id)}>\n <DownloadIcon />\n Download\n </a>\n </DropdownMenuItem>\n ) : null}\n {source.originUrl ? (\n <DropdownMenuItem asChild>\n <a href={source.originUrl} rel=\"noreferrer\" target=\"_blank\">\n <ExternalLinkIcon />\n Open page\n </a>\n </DropdownMenuItem>\n ) : null}\n {onOpen || source.path || source.originUrl ? <DropdownMenuSeparator /> : null}\n <DropdownMenuItem\n disabled={!canMutate || isBusy}\n variant=\"destructive\"\n onSelect={() => setIsConfirmingRemoval(true)}\n >\n <Trash2Icon />\n Remove\n </DropdownMenuItem>\n {canMutate ? null : (\n <DropdownMenuLabel className=\"fk:max-w-56 fk:whitespace-normal fk:text-xs fk:font-normal fk:text-muted-foreground\">\n Your member role cannot remove documents.\n </DropdownMenuLabel>\n )}\n </DropdownMenuContent>\n </DropdownMenu>\n <AlertDialog open={isConfirmingRemoval} onOpenChange={setIsConfirmingRemoval}>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>Remove this document?</AlertDialogTitle>\n <AlertDialogDescription>\n \"{source.title}\" and its indexed passages are deleted for everyone. Answers the agent gave earlier keep\n their citations, but the document can no longer be opened.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel disabled={isRemoving}>Cancel</AlertDialogCancel>\n <AlertDialogAction\n disabled={isRemoving}\n onClick={(event: MouseEvent) => {\n event.preventDefault();\n void remove();\n }}\n >\n {isRemoving ? <LoaderCircle className=\"fk:animate-spin\" /> : null}\n Remove document\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n </>\n );\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import'./index.css';import {f,a,b,g}from'./chunk-
|
|
1
|
+
import'./index.css';import {f,a,b,g}from'./chunk-HOAVEDVI.js';import {find,propEq}from'ramda';var I=25,K=25,B=2e3,N=12,x=new Set(["_asset"]),P={light:["#2a78d6","#eb6834","#1baf7a","#eda100","#e87ba4","#008300","#6250d6","#e34948","#0e9aa7","#6b8e23","#9c27b0","#a05a2c"],dark:["#3987e5","#d95926","#199e70","#c98500","#d55181","#008300","#9085e9","#e66767","#1a9fb0","#6f8a28","#c058d6","#a35226"]};function $(t,n){return `${t}:${n}`}function l(t){return t.attributes.filter(n=>a(n)==="relationship"&&n.relationship!==void 0&&!x.has(n.relationship.entity))}function V(t){return t.filter(n=>!x.has(n.name)&&l(n).length>0)}function _(t,n){return find(propEq(n,"name"))(t)}function J(t){return t.menu?.label??t.plural}function W(t,n){let e=P[n];return Object.fromEntries(t.filter(r=>!x.has(r.name)).map((r,i)=>[r.name,e[i%e.length]]))}function S(t,n,e=f){let r=b(t);if(!r)return "";let i=a(r);return i==="global"?r.name:i==="local"?`${r.name} { ${D(n,e)} }`:""}function D(t,n=f){let e=g(n);return t===n?e:`${e} ${t}`}function T(t,n,e,r,i){let o=_(n,t.relationship?.entity??"");return `${t.name}${r} { _id ${S(o,e,i)} }`}function q(t){return `${t.name}Connection { aggregate { count { nodes } } }`}var Y=5;function z({defaultScope:t,entity:n,schema:e,scope:r,expand:i}){let o=i?l(n).map(s=>T(s,e,r,`(limit: ${I})`,t)):[];return `query GraphRecords($where: ${n.name}Where, $limit: Int) {
|
|
2
2
|
${n.plural}(where: $where, limit: $limit) {
|
|
3
3
|
_id
|
|
4
4
|
${S(n,r,t)}
|
|
@@ -26,5 +26,5 @@ import'./index.css';import {f,a,b,g}from'./chunk-GORBKX24.js';import {find,propE
|
|
|
26
26
|
}`}function O(t){return t.filter(n=>(n.spaces?.length??0)===0)}function nt(t){return `query GraphTotals {
|
|
27
27
|
${O(t).map(n=>`${n.plural}Total`).join(`
|
|
28
28
|
`)}
|
|
29
|
-
}`}function j(t,n){if(t==null)return "";if(Array.isArray(t)){let[e]=t;return j(e?.[n]??e?.default,n)}return typeof t=="object"?JSON.stringify(t):String(t)}function G(t,n,e){let r=b(n),i=r?t[r.name]:void 0;if(typeof i=="string"||typeof i=="number")return String(i);if(Array.isArray(i)){let[o]=i,s=o?.[e]??o?.default;if(typeof s=="string"||typeof s=="number")return String(s)}return t._id}function M(t,n,e){let r=e.name,i=e.relationship?.field??e.name,[o]=[t.key,n.key].sort(),s=o===t.key?r:i,d=o===t.key?n.key:t.key;return {key:`${o}|${d}|${s}`,source:t.key,target:n.key,sourceAttribute:r,targetAttribute:i}}function et({records:t,entity:n,schema:e,scope:r}){let i=new Map,o=new Map,s={},d=l(n);return t.forEach(p=>{let a={key:$(n.name,p._id),entity:n.name,id:p._id,label:G(p,n,r)};i.set(a.key,a),d.forEach(u=>{let y=u.relationship?.entity??"",C=_(e,y),A=p[u.name],k=p[`${u.name}Connection`]?.aggregate?.count?.nodes;typeof k=="number"&&(s[a.key]={...s[a.key],[u.name]:k}),Array.isArray(A)&&A.forEach(f=>{let c={key:$(y,f._id),entity:y,id:f._id,label:G(f,C,r)};if(i.has(c.key)||i.set(c.key,c),c.key!==a.key){let h=M(a,c,u);o.has(h.key)||o.set(h.key,h);}});});}),{nodes:[...i.values()],edges:[...o.values()],counts:s}}function rt(t,n){let e={};return t.forEach(r=>{l(n).forEach(i=>{let o=r[i.name];if(Array.isArray(o)){let s=$(n.name,r._id);e[s]={...e[s],[i.name]:o.length};}});}),e}function it(t,{entity:n,ids:e}){let r=new URLSearchParams({entity:n});return e&&e.length>0&&r.set("ids",e.join(",")),`/${t}/graph?${r.toString()}`}function ot(t){let n=new URLSearchParams(t),e=n.get("entity");if(!e)return null;let r=(n.get("ids")??"").split(",").map(i=>i.trim()).filter(Boolean);return {entity:e,ids:r}}export{I as a,K as b,B as c,$ as d,l as e,V as f,_ as g,J as h,W as i,S as j,Y as k,z as l,Z as m,v as n,L as o,tt as p,O as q,nt as r,j as s,G as t,M as u,et as v,rt as w,it as x,ot as y};//# sourceMappingURL=chunk-
|
|
30
|
-
//# sourceMappingURL=chunk-
|
|
29
|
+
}`}function j(t,n){if(t==null)return "";if(Array.isArray(t)){let[e]=t;return j(e?.[n]??e?.default,n)}return typeof t=="object"?JSON.stringify(t):String(t)}function G(t,n,e){let r=b(n),i=r?t[r.name]:void 0;if(typeof i=="string"||typeof i=="number")return String(i);if(Array.isArray(i)){let[o]=i,s=o?.[e]??o?.default;if(typeof s=="string"||typeof s=="number")return String(s)}return t._id}function M(t,n,e){let r=e.name,i=e.relationship?.field??e.name,[o]=[t.key,n.key].sort(),s=o===t.key?r:i,d=o===t.key?n.key:t.key;return {key:`${o}|${d}|${s}`,source:t.key,target:n.key,sourceAttribute:r,targetAttribute:i}}function et({records:t,entity:n,schema:e,scope:r}){let i=new Map,o=new Map,s={},d=l(n);return t.forEach(p=>{let a={key:$(n.name,p._id),entity:n.name,id:p._id,label:G(p,n,r)};i.set(a.key,a),d.forEach(u=>{let y=u.relationship?.entity??"",C=_(e,y),A=p[u.name],k=p[`${u.name}Connection`]?.aggregate?.count?.nodes;typeof k=="number"&&(s[a.key]={...s[a.key],[u.name]:k}),Array.isArray(A)&&A.forEach(f=>{let c={key:$(y,f._id),entity:y,id:f._id,label:G(f,C,r)};if(i.has(c.key)||i.set(c.key,c),c.key!==a.key){let h=M(a,c,u);o.has(h.key)||o.set(h.key,h);}});});}),{nodes:[...i.values()],edges:[...o.values()],counts:s}}function rt(t,n){let e={};return t.forEach(r=>{l(n).forEach(i=>{let o=r[i.name];if(Array.isArray(o)){let s=$(n.name,r._id);e[s]={...e[s],[i.name]:o.length};}});}),e}function it(t,{entity:n,ids:e}){let r=new URLSearchParams({entity:n});return e&&e.length>0&&r.set("ids",e.join(",")),`/${t}/graph?${r.toString()}`}function ot(t){let n=new URLSearchParams(t),e=n.get("entity");if(!e)return null;let r=(n.get("ids")??"").split(",").map(i=>i.trim()).filter(Boolean);return {entity:e,ids:r}}export{I as a,K as b,B as c,$ as d,l as e,V as f,_ as g,J as h,W as i,S as j,Y as k,z as l,Z as m,v as n,L as o,tt as p,O as q,nt as r,j as s,G as t,M as u,et as v,rt as w,it as x,ot as y};//# sourceMappingURL=chunk-53GVTCXC.js.map
|
|
30
|
+
//# sourceMappingURL=chunk-53GVTCXC.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/apps/graph/graph.ts"],"names":["EXPAND_PAGE","SAMPLE_LIMIT","MAX_NODES","DETAIL_ATTRIBUTE_LIMIT","HIDDEN_ENTITIES","GRAPH_PALETTE","nodeKey","entity","id","getRelationshipAttributes","attribute","getAttributeScope","getGraphEntities","schema","getEntity","name","find","propEq","getEntityLabel","getEntityColors","theme","palette","index","getDisplaySelection","scope","defaultScope","DEFAULT_SCOPE_KEY","display","getDisplayAttribute","scopeType","getScopeFields","fallback","defaultValueSelection","getRelatedSelection","args","relatedEntity","getCountSelection","EXPAND_HOP_MAX_RECORDS","buildRecordsQuery","expand","relationships","buildExpandQuery","buildCountsQuery","getDetailAttributes","buildDetailsQuery","fields","getTotalEntities","entities","buildTotalsQuery","formatDetailValue","value","first","captionOf","record","scoped","edgeOf","source","target","sourceAttribute","targetAttribute","left","leftAttribute","right","graphFromRecords","records","nodes","edges","counts","relatedEntityName","relatedRecords","total","relatedRecord","edge","fetchedFromRecords","fetched","related","key","graphPath","projectId","ids","params","parseGraphParams","search"],"mappings":"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","file":"chunk-JUWAKQPE.js","sourcesContent":["import { find, propEq } from 'ramda';\nimport { DEFAULT_SCOPE_KEY, defaultValueSelection } from '../../graphql-client/queries';\nimport { getAttributeScope } from '../../core/attribute-scope';\nimport { getDisplayAttribute } from '../../core/get-display-attribute';\nimport type { Attribute, Entity } from '../../core/types';\n\n/**\n * Pure helpers of the Graph app: the GraphQL queries that fetch records with\n * their relationships, and the mapping of their results to the nodes and\n * edges the canvas draws. No React, no sigma, so the rules are unit-testable.\n */\n\n/** Related records fetched per relationship attribute in one go. */\nexport const EXPAND_PAGE = 25;\n/** Records loaded when starting from an entity. */\nexport const SAMPLE_LIMIT = 25;\n/** Nodes a canvas holds at most; later additions are dropped with a notice. */\nexport const MAX_NODES = 2000;\n/** Attributes shown in the inspector at most. */\nexport const DETAIL_ATTRIBUTE_LIMIT = 12;\n\n/** Entities whose nodes are never drawn: assets are media, not records. */\nconst HIDDEN_ENTITIES = new Set(['_asset']);\n\n/**\n * Categorical palette, one hue per entity in schema order (light and dark\n * surfaces step the same hues). The first eight are the validated dataviz\n * palette; the next four were checked with its script so adjacent pairs\n * stay apart under colour-blindness simulation and no pair on either\n * surface comes closer than the reference palette's own closest pair.\n * Projects with more entities than hues reuse them.\n */\nexport const GRAPH_PALETTE = {\n light: [\n '#2a78d6',\n '#eb6834',\n '#1baf7a',\n '#eda100',\n '#e87ba4',\n '#008300',\n '#6250d6',\n '#e34948',\n '#0e9aa7',\n '#6b8e23',\n '#9c27b0',\n '#a05a2c',\n ],\n dark: [\n '#3987e5',\n '#d95926',\n '#199e70',\n '#c98500',\n '#d55181',\n '#008300',\n '#9085e9',\n '#e66767',\n '#1a9fb0',\n '#6f8a28',\n '#c058d6',\n '#a35226',\n ],\n} as const;\n\nexport interface GraphNode {\n key: string;\n entity: string;\n id: string;\n label: string;\n}\n\nexport interface GraphEdge {\n key: string;\n source: string;\n target: string;\n /** The relationship attribute on the source node's entity. */\n sourceAttribute: string;\n /** The mirror attribute on the target node's entity. */\n targetAttribute: string;\n}\n\n/** Related records per relationship attribute, keyed by node, as the API counted them. */\nexport type GraphCounts = { [nodeKey: string]: { [attribute: string]: number } };\n\nexport interface GraphData {\n nodes: GraphNode[];\n edges: GraphEdge[];\n counts: GraphCounts;\n}\n\nexport type GraphRecord = { _id: string; [key: string]: unknown };\n\ntype ConnectionCount = { aggregate?: { count?: { nodes?: number } } };\n\nexport function nodeKey(entity: string, id: string): string {\n return `${entity}:${id}`;\n}\n\n/** Relationship attributes of an entity that point at drawable entities. */\nexport function getRelationshipAttributes(entity: Entity): Attribute[] {\n return entity.attributes.filter(\n (attribute) =>\n getAttributeScope(attribute) === 'relationship' &&\n attribute.relationship !== undefined &&\n !HIDDEN_ENTITIES.has(attribute.relationship.entity)\n );\n}\n\n/** Entities worth starting from: at least one drawable relationship. */\nexport function getGraphEntities(schema: Entity[]): Entity[] {\n return schema.filter((entity) => !HIDDEN_ENTITIES.has(entity.name) && getRelationshipAttributes(entity).length > 0);\n}\n\nexport function getEntity(schema: Entity[], name: string): Entity | undefined {\n return find<Entity>(propEq(name, 'name'))(schema);\n}\n\nexport function getEntityLabel(entity: Entity): string {\n return entity.menu?.label ?? entity.plural;\n}\n\n/** Colour per entity name, assigned in schema order and never re-cycled on filter. */\nexport function getEntityColors(schema: Entity[], theme: 'light' | 'dark'): { [entity: string]: string } {\n const palette = GRAPH_PALETTE[theme];\n\n return Object.fromEntries(\n schema.filter((entity) => !HIDDEN_ENTITIES.has(entity.name)).map((entity, index) => [entity.name, palette[index % palette.length]])\n );\n}\n\n/**\n * Selection of the display attribute: a scalar for global attributes, the\n * current scope's value for local ones. Relationship display attributes fall\n * back to the id.\n */\nexport function getDisplaySelection(\n entity: Entity | undefined,\n scope: string,\n defaultScope = DEFAULT_SCOPE_KEY\n): string {\n const display = getDisplayAttribute(entity);\n\n if (!display) {\n return '';\n }\n\n const scopeType = getAttributeScope(display);\n\n if (scopeType === 'global') {\n return display.name;\n }\n\n if (scopeType === 'local') {\n return `${display.name} { ${getScopeFields(scope, defaultScope)} }`;\n }\n\n return '';\n}\n\n/**\n * The scope value and the default one to fall back on, as the Desk queries\n * select them: the default scope's value always comes back as `default`,\n * whatever the project named that scope.\n */\nexport function getScopeFields(scope: string, defaultScope = DEFAULT_SCOPE_KEY): string {\n const fallback = defaultValueSelection(defaultScope);\n\n return scope === defaultScope ? fallback : `${fallback} ${scope}`;\n}\n\nfunction getRelatedSelection(\n attribute: Attribute,\n schema: Entity[],\n scope: string,\n args: string,\n defaultScope?: string\n): string {\n const relatedEntity = getEntity(schema, attribute.relationship?.entity ?? '');\n\n return `${attribute.name}${args} { _id ${getDisplaySelection(relatedEntity, scope, defaultScope)} }`;\n}\n\nfunction getCountSelection(attribute: Attribute): string {\n return `${attribute.name}Connection { aggregate { count { nodes } } }`;\n}\n\n/** Records a one-hop load covers at most; more records come without their relationships. */\nexport const EXPAND_HOP_MAX_RECORDS = 5;\n\n/**\n * Records by id or a sample of them; with `expand`, each comes with the first\n * page of every drawable relationship. Totals are left to the inspector:\n * counting every relationship of every record is what makes a load slow.\n */\nexport function buildRecordsQuery({\n defaultScope,\n entity,\n schema,\n scope,\n expand,\n}: {\n defaultScope?: string;\n entity: Entity;\n schema: Entity[];\n scope: string;\n expand: boolean;\n}): string {\n const relationships = expand\n ? getRelationshipAttributes(entity).map((attribute) =>\n getRelatedSelection(attribute, schema, scope, `(limit: ${EXPAND_PAGE})`, defaultScope)\n )\n : [];\n\n return `query GraphRecords($where: ${entity.name}Where, $limit: Int) {\n ${entity.plural}(where: $where, limit: $limit) {\n _id\n ${getDisplaySelection(entity, scope, defaultScope)}\n ${relationships.join('\\n ')}\n }\n}`;\n}\n\n/** One more page of a single relationship of one record. */\nexport function buildExpandQuery({\n defaultScope,\n entity,\n schema,\n scope,\n attribute,\n}: {\n defaultScope?: string;\n entity: Entity;\n schema: Entity[];\n scope: string;\n attribute: Attribute;\n}): string {\n return `query GraphExpand($id: ID!, $offset: Int, $limit: Int) {\n ${entity.plural}(where: { _id: { eq: $id } }) {\n _id\n ${getRelatedSelection(attribute, schema, scope, '(limit: $limit, offset: $offset)', defaultScope)}\n }\n}`;\n}\n\n/** The total per drawable relationship of one record. */\nexport function buildCountsQuery({ entity }: { entity: Entity }): string {\n return `query GraphCounts($id: ID!) {\n ${entity.plural}(where: { _id: { eq: $id } }) {\n _id\n ${getRelationshipAttributes(entity).map(getCountSelection).join('\\n ')}\n }\n}`;\n}\n\n/** Attributes the inspector lists: visible scalars, global or in the current scope; rich text is skipped. */\nexport function getDetailAttributes(entity: Entity): Attribute[] {\n return entity.attributes\n .filter((attribute) => {\n const scopeType = getAttributeScope(attribute);\n\n return (\n !attribute.hidden &&\n attribute.dataType !== 'asset' &&\n attribute.inputType !== 'editor' &&\n (scopeType === 'global' || scopeType === 'local')\n );\n })\n .slice(0, DETAIL_ATTRIBUTE_LIMIT);\n}\n\n/** The scalar values of one record for the inspector. */\nexport function buildDetailsQuery({\n defaultScope,\n entity,\n scope,\n}: {\n defaultScope?: string;\n entity: Entity;\n scope: string;\n}): string {\n const fields = getDetailAttributes(entity).map((attribute) =>\n getAttributeScope(attribute) === 'local'\n ? `${attribute.name} { ${getScopeFields(scope, defaultScope)} }`\n : attribute.name\n );\n\n return `query GraphDetails($id: ID!) {\n ${entity.plural}(where: { _id: { eq: $id } }) {\n _id\n _updatedAt\n ${fields.join('\\n ')}\n }\n}`;\n}\n\n/** Entities whose count-store total the API exposes (not space-bound). */\nexport function getTotalEntities(entities: Entity[]): Entity[] {\n return entities.filter((entity) => (entity.spaces?.length ?? 0) === 0);\n}\n\nexport function buildTotalsQuery(entities: Entity[]): string {\n return `query GraphTotals {\\n ${getTotalEntities(entities)\n .map((entity) => `${entity.plural}Total`)\n .join('\\n ')}\\n}`;\n}\n\n/** A scalar as the inspector shows it: the scope value of a local attribute, else the value itself. */\nexport function formatDetailValue(value: unknown, scope: string): string {\n if (value === null || value === undefined) {\n return '';\n }\n\n if (Array.isArray(value)) {\n const [first] = value as { [key: string]: unknown }[];\n\n return formatDetailValue(first?.[scope] ?? first?.default, scope);\n }\n\n if (typeof value === 'object') {\n return JSON.stringify(value);\n }\n\n return String(value);\n}\n\n/** The caption of a record: its display value in the scope, else in the default scope, else its id. */\nexport function captionOf(record: GraphRecord, entity: Entity | undefined, scope: string): string {\n const display = getDisplayAttribute(entity);\n const value = display ? record[display.name] : undefined;\n\n if (typeof value === 'string' || typeof value === 'number') {\n return String(value);\n }\n\n if (Array.isArray(value)) {\n const [first] = value as { [key: string]: unknown }[];\n const scoped = first?.[scope] ?? first?.default;\n\n if (typeof scoped === 'string' || typeof scoped === 'number') {\n return String(scoped);\n }\n }\n\n return record._id;\n}\n\n/**\n * The edge between two nodes for a relationship: one Neo4j relationship per\n * entity pair, so the key is the same whichever side it was fetched from.\n */\nexport function edgeOf(source: GraphNode, target: GraphNode, attribute: Attribute): GraphEdge {\n const sourceAttribute = attribute.name;\n const targetAttribute = attribute.relationship?.field ?? attribute.name;\n const [left] = [source.key, target.key].sort();\n const leftAttribute = left === source.key ? sourceAttribute : targetAttribute;\n const right = left === source.key ? target.key : source.key;\n\n return { key: `${left}|${right}|${leftAttribute}`, source: source.key, target: target.key, sourceAttribute, targetAttribute };\n}\n\n/**\n * Nodes and edges from records of an entity; the related records under each\n * relationship attribute become nodes too, and `xConnection` aggregates\n * become counts.\n */\nexport function graphFromRecords({\n records,\n entity,\n schema,\n scope,\n}: {\n records: GraphRecord[];\n entity: Entity;\n schema: Entity[];\n scope: string;\n}): GraphData {\n const nodes = new Map<string, GraphNode>();\n const edges = new Map<string, GraphEdge>();\n const counts: GraphCounts = {};\n const relationships = getRelationshipAttributes(entity);\n\n records.forEach((record) => {\n const source: GraphNode = {\n key: nodeKey(entity.name, record._id),\n entity: entity.name,\n id: record._id,\n label: captionOf(record, entity, scope),\n };\n nodes.set(source.key, source);\n\n relationships.forEach((attribute) => {\n const relatedEntityName = attribute.relationship?.entity ?? '';\n const relatedEntity = getEntity(schema, relatedEntityName);\n const relatedRecords = record[attribute.name];\n const connection = record[`${attribute.name}Connection`] as ConnectionCount | undefined;\n const total = connection?.aggregate?.count?.nodes;\n\n if (typeof total === 'number') {\n counts[source.key] = { ...counts[source.key], [attribute.name]: total };\n }\n\n if (!Array.isArray(relatedRecords)) {\n return;\n }\n\n (relatedRecords as GraphRecord[]).forEach((relatedRecord) => {\n const target: GraphNode = {\n key: nodeKey(relatedEntityName, relatedRecord._id),\n entity: relatedEntityName,\n id: relatedRecord._id,\n label: captionOf(relatedRecord, relatedEntity, scope),\n };\n\n if (!nodes.has(target.key)) {\n nodes.set(target.key, target);\n }\n\n if (target.key !== source.key) {\n const edge = edgeOf(source, target, attribute);\n\n if (!edges.has(edge.key)) {\n edges.set(edge.key, edge);\n }\n }\n });\n });\n });\n\n return { nodes: [...nodes.values()], edges: [...edges.values()], counts };\n}\n\n/** How many related records each record carries per relationship, to continue paging from. */\nexport function fetchedFromRecords(records: GraphRecord[], entity: Entity): GraphCounts {\n const fetched: GraphCounts = {};\n\n records.forEach((record) => {\n getRelationshipAttributes(entity).forEach((attribute) => {\n const related = record[attribute.name];\n\n if (Array.isArray(related)) {\n const key = nodeKey(entity.name, record._id);\n fetched[key] = { ...fetched[key], [attribute.name]: related.length };\n }\n });\n });\n\n return fetched;\n}\n\n/** The Graph app route for an entity, optionally for given records. */\nexport function graphPath(projectId: string, { entity, ids }: { entity: string; ids?: string[] }): string {\n const params = new URLSearchParams({ entity });\n\n if (ids && ids.length > 0) {\n params.set('ids', ids.join(','));\n }\n\n return `/${projectId}/graph?${params.toString()}`;\n}\n\nexport function parseGraphParams(search: string): { entity: string; ids: string[] } | null {\n const params = new URLSearchParams(search);\n const entity = params.get('entity');\n\n if (!entity) {\n return null;\n }\n\n const ids = (params.get('ids') ?? '')\n .split(',')\n .map((id) => id.trim())\n .filter(Boolean);\n\n return { entity, ids };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/apps/graph/graph.ts"],"names":["EXPAND_PAGE","SAMPLE_LIMIT","MAX_NODES","DETAIL_ATTRIBUTE_LIMIT","HIDDEN_ENTITIES","GRAPH_PALETTE","nodeKey","entity","id","getRelationshipAttributes","attribute","getAttributeScope","getGraphEntities","schema","getEntity","name","find","propEq","getEntityLabel","getEntityColors","theme","palette","index","getDisplaySelection","scope","defaultScope","DEFAULT_SCOPE_KEY","display","getDisplayAttribute","scopeType","getScopeFields","fallback","defaultValueSelection","getRelatedSelection","args","relatedEntity","getCountSelection","EXPAND_HOP_MAX_RECORDS","buildRecordsQuery","expand","relationships","buildExpandQuery","buildCountsQuery","getDetailAttributes","buildDetailsQuery","fields","getTotalEntities","entities","buildTotalsQuery","formatDetailValue","value","first","captionOf","record","scoped","edgeOf","source","target","sourceAttribute","targetAttribute","left","leftAttribute","right","graphFromRecords","records","nodes","edges","counts","relatedEntityName","relatedRecords","total","relatedRecord","edge","fetchedFromRecords","fetched","related","key","graphPath","projectId","ids","params","parseGraphParams","search"],"mappings":"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","file":"chunk-53GVTCXC.js","sourcesContent":["import { find, propEq } from 'ramda';\nimport { DEFAULT_SCOPE_KEY, defaultValueSelection } from '../../graphql-client/queries';\nimport { getAttributeScope } from '../../core/attribute-scope';\nimport { getDisplayAttribute } from '../../core/get-display-attribute';\nimport type { Attribute, Entity } from '../../core/types';\n\n/**\n * Pure helpers of the Graph app: the GraphQL queries that fetch records with\n * their relationships, and the mapping of their results to the nodes and\n * edges the canvas draws. No React, no sigma, so the rules are unit-testable.\n */\n\n/** Related records fetched per relationship attribute in one go. */\nexport const EXPAND_PAGE = 25;\n/** Records loaded when starting from an entity. */\nexport const SAMPLE_LIMIT = 25;\n/** Nodes a canvas holds at most; later additions are dropped with a notice. */\nexport const MAX_NODES = 2000;\n/** Attributes shown in the inspector at most. */\nexport const DETAIL_ATTRIBUTE_LIMIT = 12;\n\n/** Entities whose nodes are never drawn: assets are media, not records. */\nconst HIDDEN_ENTITIES = new Set(['_asset']);\n\n/**\n * Categorical palette, one hue per entity in schema order (light and dark\n * surfaces step the same hues). The first eight are the validated dataviz\n * palette; the next four were checked with its script so adjacent pairs\n * stay apart under colour-blindness simulation and no pair on either\n * surface comes closer than the reference palette's own closest pair.\n * Projects with more entities than hues reuse them.\n */\nexport const GRAPH_PALETTE = {\n light: [\n '#2a78d6',\n '#eb6834',\n '#1baf7a',\n '#eda100',\n '#e87ba4',\n '#008300',\n '#6250d6',\n '#e34948',\n '#0e9aa7',\n '#6b8e23',\n '#9c27b0',\n '#a05a2c',\n ],\n dark: [\n '#3987e5',\n '#d95926',\n '#199e70',\n '#c98500',\n '#d55181',\n '#008300',\n '#9085e9',\n '#e66767',\n '#1a9fb0',\n '#6f8a28',\n '#c058d6',\n '#a35226',\n ],\n} as const;\n\nexport interface GraphNode {\n key: string;\n entity: string;\n id: string;\n label: string;\n}\n\nexport interface GraphEdge {\n key: string;\n source: string;\n target: string;\n /** The relationship attribute on the source node's entity. */\n sourceAttribute: string;\n /** The mirror attribute on the target node's entity. */\n targetAttribute: string;\n}\n\n/** Related records per relationship attribute, keyed by node, as the API counted them. */\nexport type GraphCounts = { [nodeKey: string]: { [attribute: string]: number } };\n\nexport interface GraphData {\n nodes: GraphNode[];\n edges: GraphEdge[];\n counts: GraphCounts;\n}\n\nexport type GraphRecord = { _id: string; [key: string]: unknown };\n\ntype ConnectionCount = { aggregate?: { count?: { nodes?: number } } };\n\nexport function nodeKey(entity: string, id: string): string {\n return `${entity}:${id}`;\n}\n\n/** Relationship attributes of an entity that point at drawable entities. */\nexport function getRelationshipAttributes(entity: Entity): Attribute[] {\n return entity.attributes.filter(\n (attribute) =>\n getAttributeScope(attribute) === 'relationship' &&\n attribute.relationship !== undefined &&\n !HIDDEN_ENTITIES.has(attribute.relationship.entity)\n );\n}\n\n/** Entities worth starting from: at least one drawable relationship. */\nexport function getGraphEntities(schema: Entity[]): Entity[] {\n return schema.filter((entity) => !HIDDEN_ENTITIES.has(entity.name) && getRelationshipAttributes(entity).length > 0);\n}\n\nexport function getEntity(schema: Entity[], name: string): Entity | undefined {\n return find<Entity>(propEq(name, 'name'))(schema);\n}\n\nexport function getEntityLabel(entity: Entity): string {\n return entity.menu?.label ?? entity.plural;\n}\n\n/** Colour per entity name, assigned in schema order and never re-cycled on filter. */\nexport function getEntityColors(schema: Entity[], theme: 'light' | 'dark'): { [entity: string]: string } {\n const palette = GRAPH_PALETTE[theme];\n\n return Object.fromEntries(\n schema.filter((entity) => !HIDDEN_ENTITIES.has(entity.name)).map((entity, index) => [entity.name, palette[index % palette.length]])\n );\n}\n\n/**\n * Selection of the display attribute: a scalar for global attributes, the\n * current scope's value for local ones. Relationship display attributes fall\n * back to the id.\n */\nexport function getDisplaySelection(\n entity: Entity | undefined,\n scope: string,\n defaultScope = DEFAULT_SCOPE_KEY\n): string {\n const display = getDisplayAttribute(entity);\n\n if (!display) {\n return '';\n }\n\n const scopeType = getAttributeScope(display);\n\n if (scopeType === 'global') {\n return display.name;\n }\n\n if (scopeType === 'local') {\n return `${display.name} { ${getScopeFields(scope, defaultScope)} }`;\n }\n\n return '';\n}\n\n/**\n * The scope value and the default one to fall back on, as the Desk queries\n * select them: the default scope's value always comes back as `default`,\n * whatever the project named that scope.\n */\nexport function getScopeFields(scope: string, defaultScope = DEFAULT_SCOPE_KEY): string {\n const fallback = defaultValueSelection(defaultScope);\n\n return scope === defaultScope ? fallback : `${fallback} ${scope}`;\n}\n\nfunction getRelatedSelection(\n attribute: Attribute,\n schema: Entity[],\n scope: string,\n args: string,\n defaultScope?: string\n): string {\n const relatedEntity = getEntity(schema, attribute.relationship?.entity ?? '');\n\n return `${attribute.name}${args} { _id ${getDisplaySelection(relatedEntity, scope, defaultScope)} }`;\n}\n\nfunction getCountSelection(attribute: Attribute): string {\n return `${attribute.name}Connection { aggregate { count { nodes } } }`;\n}\n\n/** Records a one-hop load covers at most; more records come without their relationships. */\nexport const EXPAND_HOP_MAX_RECORDS = 5;\n\n/**\n * Records by id or a sample of them; with `expand`, each comes with the first\n * page of every drawable relationship. Totals are left to the inspector:\n * counting every relationship of every record is what makes a load slow.\n */\nexport function buildRecordsQuery({\n defaultScope,\n entity,\n schema,\n scope,\n expand,\n}: {\n defaultScope?: string;\n entity: Entity;\n schema: Entity[];\n scope: string;\n expand: boolean;\n}): string {\n const relationships = expand\n ? getRelationshipAttributes(entity).map((attribute) =>\n getRelatedSelection(attribute, schema, scope, `(limit: ${EXPAND_PAGE})`, defaultScope)\n )\n : [];\n\n return `query GraphRecords($where: ${entity.name}Where, $limit: Int) {\n ${entity.plural}(where: $where, limit: $limit) {\n _id\n ${getDisplaySelection(entity, scope, defaultScope)}\n ${relationships.join('\\n ')}\n }\n}`;\n}\n\n/** One more page of a single relationship of one record. */\nexport function buildExpandQuery({\n defaultScope,\n entity,\n schema,\n scope,\n attribute,\n}: {\n defaultScope?: string;\n entity: Entity;\n schema: Entity[];\n scope: string;\n attribute: Attribute;\n}): string {\n return `query GraphExpand($id: ID!, $offset: Int, $limit: Int) {\n ${entity.plural}(where: { _id: { eq: $id } }) {\n _id\n ${getRelatedSelection(attribute, schema, scope, '(limit: $limit, offset: $offset)', defaultScope)}\n }\n}`;\n}\n\n/** The total per drawable relationship of one record. */\nexport function buildCountsQuery({ entity }: { entity: Entity }): string {\n return `query GraphCounts($id: ID!) {\n ${entity.plural}(where: { _id: { eq: $id } }) {\n _id\n ${getRelationshipAttributes(entity).map(getCountSelection).join('\\n ')}\n }\n}`;\n}\n\n/** Attributes the inspector lists: visible scalars, global or in the current scope; rich text is skipped. */\nexport function getDetailAttributes(entity: Entity): Attribute[] {\n return entity.attributes\n .filter((attribute) => {\n const scopeType = getAttributeScope(attribute);\n\n return (\n !attribute.hidden &&\n attribute.dataType !== 'asset' &&\n attribute.inputType !== 'editor' &&\n (scopeType === 'global' || scopeType === 'local')\n );\n })\n .slice(0, DETAIL_ATTRIBUTE_LIMIT);\n}\n\n/** The scalar values of one record for the inspector. */\nexport function buildDetailsQuery({\n defaultScope,\n entity,\n scope,\n}: {\n defaultScope?: string;\n entity: Entity;\n scope: string;\n}): string {\n const fields = getDetailAttributes(entity).map((attribute) =>\n getAttributeScope(attribute) === 'local'\n ? `${attribute.name} { ${getScopeFields(scope, defaultScope)} }`\n : attribute.name\n );\n\n return `query GraphDetails($id: ID!) {\n ${entity.plural}(where: { _id: { eq: $id } }) {\n _id\n _updatedAt\n ${fields.join('\\n ')}\n }\n}`;\n}\n\n/** Entities whose count-store total the API exposes (not space-bound). */\nexport function getTotalEntities(entities: Entity[]): Entity[] {\n return entities.filter((entity) => (entity.spaces?.length ?? 0) === 0);\n}\n\nexport function buildTotalsQuery(entities: Entity[]): string {\n return `query GraphTotals {\\n ${getTotalEntities(entities)\n .map((entity) => `${entity.plural}Total`)\n .join('\\n ')}\\n}`;\n}\n\n/** A scalar as the inspector shows it: the scope value of a local attribute, else the value itself. */\nexport function formatDetailValue(value: unknown, scope: string): string {\n if (value === null || value === undefined) {\n return '';\n }\n\n if (Array.isArray(value)) {\n const [first] = value as { [key: string]: unknown }[];\n\n return formatDetailValue(first?.[scope] ?? first?.default, scope);\n }\n\n if (typeof value === 'object') {\n return JSON.stringify(value);\n }\n\n return String(value);\n}\n\n/** The caption of a record: its display value in the scope, else in the default scope, else its id. */\nexport function captionOf(record: GraphRecord, entity: Entity | undefined, scope: string): string {\n const display = getDisplayAttribute(entity);\n const value = display ? record[display.name] : undefined;\n\n if (typeof value === 'string' || typeof value === 'number') {\n return String(value);\n }\n\n if (Array.isArray(value)) {\n const [first] = value as { [key: string]: unknown }[];\n const scoped = first?.[scope] ?? first?.default;\n\n if (typeof scoped === 'string' || typeof scoped === 'number') {\n return String(scoped);\n }\n }\n\n return record._id;\n}\n\n/**\n * The edge between two nodes for a relationship: one Neo4j relationship per\n * entity pair, so the key is the same whichever side it was fetched from.\n */\nexport function edgeOf(source: GraphNode, target: GraphNode, attribute: Attribute): GraphEdge {\n const sourceAttribute = attribute.name;\n const targetAttribute = attribute.relationship?.field ?? attribute.name;\n const [left] = [source.key, target.key].sort();\n const leftAttribute = left === source.key ? sourceAttribute : targetAttribute;\n const right = left === source.key ? target.key : source.key;\n\n return { key: `${left}|${right}|${leftAttribute}`, source: source.key, target: target.key, sourceAttribute, targetAttribute };\n}\n\n/**\n * Nodes and edges from records of an entity; the related records under each\n * relationship attribute become nodes too, and `xConnection` aggregates\n * become counts.\n */\nexport function graphFromRecords({\n records,\n entity,\n schema,\n scope,\n}: {\n records: GraphRecord[];\n entity: Entity;\n schema: Entity[];\n scope: string;\n}): GraphData {\n const nodes = new Map<string, GraphNode>();\n const edges = new Map<string, GraphEdge>();\n const counts: GraphCounts = {};\n const relationships = getRelationshipAttributes(entity);\n\n records.forEach((record) => {\n const source: GraphNode = {\n key: nodeKey(entity.name, record._id),\n entity: entity.name,\n id: record._id,\n label: captionOf(record, entity, scope),\n };\n nodes.set(source.key, source);\n\n relationships.forEach((attribute) => {\n const relatedEntityName = attribute.relationship?.entity ?? '';\n const relatedEntity = getEntity(schema, relatedEntityName);\n const relatedRecords = record[attribute.name];\n const connection = record[`${attribute.name}Connection`] as ConnectionCount | undefined;\n const total = connection?.aggregate?.count?.nodes;\n\n if (typeof total === 'number') {\n counts[source.key] = { ...counts[source.key], [attribute.name]: total };\n }\n\n if (!Array.isArray(relatedRecords)) {\n return;\n }\n\n (relatedRecords as GraphRecord[]).forEach((relatedRecord) => {\n const target: GraphNode = {\n key: nodeKey(relatedEntityName, relatedRecord._id),\n entity: relatedEntityName,\n id: relatedRecord._id,\n label: captionOf(relatedRecord, relatedEntity, scope),\n };\n\n if (!nodes.has(target.key)) {\n nodes.set(target.key, target);\n }\n\n if (target.key !== source.key) {\n const edge = edgeOf(source, target, attribute);\n\n if (!edges.has(edge.key)) {\n edges.set(edge.key, edge);\n }\n }\n });\n });\n });\n\n return { nodes: [...nodes.values()], edges: [...edges.values()], counts };\n}\n\n/** How many related records each record carries per relationship, to continue paging from. */\nexport function fetchedFromRecords(records: GraphRecord[], entity: Entity): GraphCounts {\n const fetched: GraphCounts = {};\n\n records.forEach((record) => {\n getRelationshipAttributes(entity).forEach((attribute) => {\n const related = record[attribute.name];\n\n if (Array.isArray(related)) {\n const key = nodeKey(entity.name, record._id);\n fetched[key] = { ...fetched[key], [attribute.name]: related.length };\n }\n });\n });\n\n return fetched;\n}\n\n/** The Graph app route for an entity, optionally for given records. */\nexport function graphPath(projectId: string, { entity, ids }: { entity: string; ids?: string[] }): string {\n const params = new URLSearchParams({ entity });\n\n if (ids && ids.length > 0) {\n params.set('ids', ids.join(','));\n }\n\n return `/${projectId}/graph?${params.toString()}`;\n}\n\nexport function parseGraphParams(search: string): { entity: string; ids: string[] } | null {\n const params = new URLSearchParams(search);\n const entity = params.get('entity');\n\n if (!entity) {\n return null;\n }\n\n const ids = (params.get('ids') ?? '')\n .split(',')\n .map((id) => id.trim())\n .filter(Boolean);\n\n return { entity, ids };\n}\n"]}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import'./index.css';import {e,c,b,a,g,h as h$1,m,k as k$2,n}from'./chunk-IJECATW3.js';import {e as e$3}from'./chunk-CCVE7GGO.js';import {b as b$2}from'./chunk-DSLPTDZX.js';import {j as j$1}from'./chunk-4OGLWOO3.js';import {c as c$4}from'./chunk-DSZJXMN5.js';import {t,s,u,q as q$2,v,k as k$1,i,o as o$1,r as r$1,p as p$2}from'./chunk-7KLXWCDS.js';import {s as s$3,b as b$5}from'./chunk-GORBKX24.js';import {f}from'./chunk-INZZOKRC.js';import {ja,o,p as p$1,q as q$1,r,s as s$2,t as t$3,ma}from'./chunk-RULCANNM.js';import {t as t$1}from'./chunk-A4DPLZZF.js';import {b as b$4}from'./chunk-G5N6HEPW.js';import {b as b$1,c as c$3,e as e$2,f as f$1,g as g$1,h,j}from'./chunk-5JUG4BEF.js';import {k,p,q,s as s$1,t as t$2}from'./chunk-S7Z6KKIN.js';import {a as a$1,b as b$3,c as c$2,e as e$1}from'./chunk-N33S7BSG.js';import {c as c$1}from'./chunk-X3SHNHHM.js';import {useState,useMemo,useDeferredValue}from'react';import {BookOpenTextIcon,PaperclipIcon,ChevronRightIcon,LayersIcon,XIcon,PlusIcon,Unlink2Icon,LoaderCircle,SearchIcon}from'lucide-react';import {Link}from'react-router-dom';import H from'swr';import Qe from'swr/infinite';import {jsxs,Fragment,jsx}from'react/jsx-runtime';var Be=50;function fe({disabled:n,label:l,onClick:o}){return jsxs(b$3,{children:[jsx(c$2,{asChild:true,children:jsx(c$1,{"aria-label":l,className:"fk:size-7 fk:shrink-0",disabled:n,size:"icon",variant:"ghost",onClick:o,children:jsx(Unlink2Icon,{className:"fk:size-4"})})}),jsx(e$1,{children:l})]})}function Xe({api:n$1,attachedIds:l,onAttached:o,onOpenChange:a,open:s,projectId:u,target:r,targetLabel:c$1}){let[p$1,h]=useState(""),m$1=useDeferredValue(p$1.trim()),[y,f]=useState(null),b$1=(k,K)=>!s||K&&!K.hasMore?null:c(u).sources({limit:Be,offset:k*Be,search:m$1||void 0}),{data:v,error:w,isLoading:x,setSize:i$1,size:d}=Qe(b$1,b,{keepPreviousData:true}),g=useMemo(()=>r$1(v?.flatMap(k=>k.sources)??[],l),[l,v]),L=v?.[v.length-1]?.hasMore??false,C=v!==void 0&&d>v.length;async function A(k){f(k.id);try{let K=await n$1.linkSource(k.id,r);ma.success(K.linked?`Attached "${k.title}".`:`"${k.title}" was already attached.`),o(k),a(!1);}catch(K){ma.error(h$1(K,"The document could not be attached."));}finally{f(null);}}let R;return w?R=jsx("p",{className:"fk:py-6 fk:text-center fk:text-sm fk:text-destructive",children:"The documents could not be loaded."}):x&&!v?R=jsxs("div",{"aria-busy":"true",className:"fk:flex fk:flex-col fk:gap-3 fk:py-2",children:[jsx(t$1,{className:"fk:h-10 fk:w-full"}),jsx(t$1,{className:"fk:h-10 fk:w-full"}),jsx(t$1,{className:"fk:h-10 fk:w-full"})]}):g.length===0&&!L?R=jsx("p",{className:"fk:py-6 fk:text-center fk:text-sm fk:text-muted-foreground",children:m$1?"No documents match your search.":"Every document is attached already, or there are none yet. Add documents in Knowledge first."}):R=jsxs("ul",{className:"fk:flex fk:max-h-80 fk:flex-col fk:overflow-y-auto fk:-mx-2",children:[g.map(k=>{let K=k$1(k),B=y===k.id;return jsx("li",{children:jsxs("button",{className:"fk:flex fk:w-full fk:min-w-0 fk:items-center fk:gap-3 fk:rounded-lg fk:px-2 fk:py-2 fk:text-left fk:transition-colors fk:hover:bg-accent fk:focus-visible:bg-accent fk:focus-visible:outline-none fk:disabled:opacity-60 fk:corner-squircle",disabled:y!==null,type:"button",onClick:()=>{A(k);},children:[jsx(m,{source:k}),jsxs("span",{className:"fk:min-w-0 fk:flex-1",children:[jsx("span",{className:"fk:block fk:truncate fk:text-sm fk:font-medium",children:k.title}),jsxs("span",{className:"fk:block fk:truncate fk:text-xs fk:text-muted-foreground",children:[i(k)," \xB7 ",K.detail]})]}),B?jsx(LoaderCircle,{className:"fk:size-4 fk:shrink-0 fk:animate-spin fk:text-muted-foreground"}):jsx(k$2,{label:K.label,tone:K.tone})]})},k.id)}),L&&!C?jsx("li",{"aria-hidden":true,children:jsx(n,{onVisible:()=>{i$1(k=>k+1);}})}):null,C?jsx("li",{className:"fk:flex fk:justify-center fk:py-2",children:jsx(LoaderCircle,{className:"fk:size-4 fk:animate-spin fk:text-muted-foreground"})}):null]}),jsx(k,{open:s,onOpenChange:a,children:jsxs(p,{className:"fk:sm:max-w-lg",children:[jsxs(q,{children:[jsx(s$1,{children:"Attach a document"}),jsx(t$2,{children:r.recordId===void 0?`Documents attached to every ${c$1} are searched before the rest of Knowledge when a question is about one of them, or about ${c$1} in general.`:`Documents attached to ${c$1} are searched before the rest of Knowledge when a question is about it.`})]}),jsxs("div",{className:"fk:relative",children:[jsx(SearchIcon,{className:"fk:pointer-events-none fk:absolute fk:left-2.5 fk:top-1/2 fk:size-4 fk:-translate-y-1/2 fk:text-muted-foreground"}),jsx(b$4,{"aria-label":"Search documents",autoFocus:true,className:"fk:pl-8",placeholder:"Search documents by title",value:p$1,onChange:k=>h(k.target.value)})]}),R]})})}function re({projectId:n,renderAction:l,sources:o}){return jsx("ul",{className:"fk:flex fk:flex-col fk:gap-1 fk:-mx-2",children:o.map(a=>{let s=k$1(a);return jsxs("li",{className:"fk:flex fk:min-w-0 fk:items-center fk:gap-2 fk:rounded-lg fk:px-2 fk:py-1.5 fk:corner-squircle",children:[jsxs(Link,{className:"fk:flex fk:min-w-0 fk:flex-1 fk:items-center fk:gap-3 fk:rounded-md fk:hover:underline fk:underline-offset-2",to:o$1(n,a.id),children:[jsx(m,{source:a}),jsxs("span",{className:"fk:min-w-0 fk:flex-1",children:[jsx("span",{className:"fk:block fk:truncate fk:text-sm fk:font-medium",children:a.title}),jsxs("span",{className:"fk:block fk:truncate fk:text-xs fk:text-muted-foreground",children:[i(a)," \xB7 ",s.detail]})]})]}),jsx(k$2,{label:s.label,tone:s.tone}),l?.(a)]},a.id)})})}function yt({entityName:n}){let{api:l,projectId:o}=e(),{currentProject:a$1}=f(),[s$1,u$1]=useState(false),r=t(a$1?.schema??[],n),c$2=!!r&&s(n),{data:p,error:h}=H(o&&c$2?c(o).entitySources(n):null,b);if(!l||!o||!r||!c$2||h instanceof a&&h.status===404)return null;let m=p?.sources.length??0;return jsxs(Fragment,{children:[jsxs(c$1,{"aria-label":`Knowledge for every ${u(r)}`,className:"fk:mr-2 fk:h-8","data-knowledge-entity-button":true,size:"sm",variant:"outline",onClick:()=>u$1(true),children:[jsx(BookOpenTextIcon,{}),"Knowledge",m>0?jsx(b$1,{className:"fk:corner-squircle",variant:"secondary",children:m}):null]}),jsx(Ue,{api:l,entityLabel:u(r),entityName:n,open:s$1,projectId:o,onOpenChange:u$1})]})}function Ue({api:n,entityLabel:l,entityName:o,onOpenChange:a,open:s,projectId:u}){let r=b$2(),[c$2,p$1]=useState(false),[h,m]=useState(null),{data:y,error:f,isLoading:b$3,mutate:v}=H(c(u).entitySources(o),b),w=y?.sources??[],x=useMemo(()=>({entity:o}),[o]);async function i(g$1){m(g$1.id);try{await n.unlinkSource(g$1.id,x),ma.success(`"${g$1.title}" no longer applies to every ${l}.`),await v({sources:w.filter(L=>L.id!==g$1.id)},{revalidate:!1}),g();}catch(L){ma.error(h$1(L,"The document could not be detached."));}finally{m(null);}}let d;return f?d=jsx("p",{className:"fk:text-sm fk:text-destructive",children:"The documents could not be loaded."}):b$3&&!y?d=jsxs("div",{"aria-busy":"true",className:"fk:flex fk:flex-col fk:gap-2",children:[jsx(t$1,{className:"fk:h-9 fk:w-full"}),jsx(t$1,{className:"fk:h-9 fk:w-2/3"})]}):w.length===0?d=jsxs("p",{className:"fk:text-sm fk:text-muted-foreground",children:["No documents apply to every ",l," yet. Attach a guide, a policy or a spec that holds for all of them and the agent searches it first when asked about any ",l,", or about ",l," in general."]}):d=jsx(re,{projectId:u,sources:w,renderAction:g=>r?jsx(fe,{disabled:h!==null,label:`Detach ${g.title}`,onClick:()=>{i(g);}}):null}),jsx(k,{open:s,onOpenChange:a,children:jsxs(p,{className:"fk:sm:max-w-lg","data-knowledge-entity-dialog":true,children:[jsxs(q,{children:[jsxs(s$1,{className:"fk:flex fk:items-center fk:gap-2",children:[jsx(BookOpenTextIcon,{className:"fk:size-4 fk:text-muted-foreground"}),"Knowledge for every ",l,y?jsx(b$1,{className:"fk:corner-squircle",variant:"outline",children:w.length}):null]}),jsxs(t$2,{children:["Documents attached here apply to every ",l,"; each record can hold its own on top."]})]}),jsx("div",{className:"fk:max-h-80 fk:overflow-y-auto",children:d}),jsx("div",{className:"fk:flex fk:justify-end",children:jsx(ja,{disabled:!r,children:jsxs(c$1,{disabled:!r,size:"sm",variant:"outline",onClick:()=>p$1(true),children:[jsx(PaperclipIcon,{}),"Attach document"]})})}),jsx(Xe,{api:n,attachedIds:w.map(g=>g.id),open:c$2,projectId:u,target:x,targetLabel:l,onAttached:g$1=>{v({sources:w.some(L=>L.id===g$1.id)?w:[...w,g$1]},{revalidate:false}),g();},onOpenChange:p$1})]})})}function bt({entityName:n,recordId:l,recordLabel:o$1}){let{api:a$2,projectId:s$1}=e(),{currentProject:u$1}=f(),r=b$2(),[c$2,p]=useState(false),[h,m]=useState(false),[y,f$1]=useState(null),b$3=useMemo(()=>({entity:n,recordId:l}),[n,l]),v=t(u$1?.schema??[],n),w=v?u(v):n,x=s(n),{data:i,error:d,isLoading:g$1,mutate:L}=H(s$1&&x?c(s$1).recordSources(b$3):null,b);if(!a$2||!s$1||!x||d instanceof a&&d.status===404)return null;let C=i?.sources??[],A=i?.inherited??[],R=C.map(N=>N.id),k=a$2;async function K(N){f$1(N.id);try{await k.unlinkSource(N.id,b$3),ma.success(`Detached "${N.title}".`),await L({sources:C.filter($=>$.id!==N.id),inherited:A},{revalidate:!1}),g();}catch($){ma.error(h$1($,"The document could not be detached."));}finally{f$1(null);}}let B;return d?B=jsx("p",{className:"fk:text-sm fk:text-destructive",children:"The attached documents could not be loaded."}):g$1&&!i?B=jsxs("div",{"aria-busy":"true",className:"fk:flex fk:flex-col fk:gap-2",children:[jsx(t$1,{className:"fk:h-9 fk:w-full"}),jsx(t$1,{className:"fk:h-9 fk:w-2/3"})]}):B=jsxs("div",{className:"fk:flex fk:flex-col fk:gap-4",children:[C.length===0?jsx("p",{className:"fk:text-sm fk:text-muted-foreground",children:A.length>0?"No documents attached to this record itself; the ones below apply to every record of its type.":"No documents attached. Attach a manual, spec or contract and the agent will use it alongside the record's data when asked about this record."}):jsx(re,{projectId:s$1,sources:C,renderAction:N=>r?jsx(fe,{disabled:y!==null,label:`Detach ${N.title}`,onClick:()=>{K(N);}}):null}),A.length>0?jsxs("div",{className:"fk:flex fk:flex-col fk:gap-1","data-knowledge-inherited":true,children:[jsxs("span",{className:"fk:text-xs fk:font-medium fk:uppercase fk:tracking-wide fk:text-muted-foreground",children:["Applies to every ",w]}),jsx(re,{projectId:s$1,sources:A})]}):null]}),jsx(a$1,{children:jsxs(o,{className:`fk:z-10 fk:flex fk:shrink-0 fk:flex-col fk:border-t fk:bg-background ${c$2?"fk:h-1/2":""}`,"data-knowledge-record-panel":true,open:c$2,onOpenChange:p,children:[jsxs("div",{className:"fk:flex fk:shrink-0 fk:items-center fk:gap-2 fk:pl-4 fk:pr-10 fk:py-2",children:[jsx(p$1,{asChild:true,children:jsxs("button",{className:"fk:flex fk:min-w-0 fk:flex-1 fk:items-center fk:gap-2 fk:rounded-md fk:py-1 fk:text-left fk:text-sm fk:font-semibold fk:tracking-tight fk:hover:text-foreground/80 fk:focus-visible:outline-none fk:focus-visible:ring-2 fk:focus-visible:ring-ring",type:"button",children:[jsx(ChevronRightIcon,{className:`fk:size-4 fk:shrink-0 fk:text-muted-foreground fk:transition-transform ${c$2?"fk:rotate-90":""}`}),jsx(BookOpenTextIcon,{className:"fk:size-4 fk:shrink-0 fk:text-muted-foreground"}),"Knowledge",i?jsx(b$1,{className:"fk:corner-squircle",variant:"outline",children:C.length+A.length}):null]})}),c$2?jsx(ja,{disabled:!r,children:jsxs(c$1,{disabled:!r,size:"sm",variant:"outline",onClick:()=>m(true),children:[jsx(PaperclipIcon,{}),"Attach document"]})}):null]}),jsx(q$1,{className:"fk:min-h-0 fk:flex-1 fk:overflow-y-auto fk:px-10 fk:pb-6",children:B}),jsx(Xe,{api:a$2,attachedIds:R,open:h,projectId:s$1,target:b$3,targetLabel:o$1||`this ${n}`,onAttached:N=>{L({sources:C.some($=>$.id===N.id)?C:[...C,N],inherited:A.filter($=>$.id!==N.id)},{revalidate:false}),g();},onOpenChange:m})]})})}function Ze(n,l,o){let{scope:a}=c$4(),s=n.links.map(r=>r.recordId),{data:u}=e$3({entityNamePlural:n.entityPlural,schema:l,scope:a,selection:"display",includeCount:false,variables:{where:{_id:{in:s}},limit:s.length}});return useMemo(()=>{let r={};for(let c of u??[]){let p=c[o.name];typeof p=="string"&&p.trim()&&(r[c._id]=p);}return r},[u,o])}function Ye(n){let{currentProject:l}=f(),o=useMemo(()=>l?.schema??[],[l]),a=s$3(o,n.group.entityPlural),s=b$5(a);return !a||!s?jsx(Je,{...n,entityLabel:a?u(a):n.group.entityPlural,labels:{}}):jsx(et,{...n,displayAttribute:s,schema:o,entityLabel:u(a)})}function et({displayAttribute:n,entityLabel:l,schema:o,...a}){let s=Ze(a.group,o,n);return jsx(Je,{...a,entityLabel:l,labels:s})}function Je({canMutate:n,detachingKey:l,entityLabel:o,group:a,labels:s,onDetach:u}){let r=j$1();return jsxs("div",{className:"fk:flex fk:flex-col fk:gap-1",children:[jsx("span",{className:"fk:text-xs fk:font-medium fk:uppercase fk:tracking-wide fk:text-muted-foreground",children:o}),jsx("ul",{className:"fk:flex fk:flex-col fk:-mx-2",children:a.links.map(c=>{let p=p$2(c,s[c.recordId]),h=`${c.entity}:${c.recordId}`;return jsxs("li",{className:"fk:flex fk:min-w-0 fk:items-center fk:gap-2 fk:rounded-lg fk:px-2 fk:py-1 fk:corner-squircle",children:[jsx("button",{className:"fk:min-w-0 fk:flex-1 fk:truncate fk:text-left fk:text-sm fk:hover:underline fk:underline-offset-2",title:c.recordId,type:"button",onClick:()=>r({type:"EditEntity",payload:{entityId:c.recordId,entityNamePlural:a.entityPlural}}),children:p}),n?jsx(fe,{disabled:l!==null,label:`Detach from ${p}`,onClick:()=>u(c)}):null]},h)})})]})}function vt({api:n,projectId:l,source:o}){let a=b$2(),[s,u$1]=useState(null),{data:r,error:c$1,isLoading:p,mutate:h}=H(c(l).links(o.id),b),m=useMemo(()=>r?.links??[],[r]),y=useMemo(()=>r?.entities??[],[r]),f=useMemo(()=>q$2(m),[m]);async function b$3(i){u$1(`${i.entity}:${i.recordId}`);try{await n.unlinkSource(o.id,{entity:i.entity,recordId:i.recordId}),ma.success("Detached."),await h({links:m.filter(d=>d.entity!==i.entity||d.recordId!==i.recordId),entities:y},{revalidate:!1}),g();}catch(d){ma.error(h$1(d,"The document could not be detached."));}finally{u$1(null);}}async function v(i){u$1(`${i.entity}:*`);try{await n.unlinkSource(o.id,{entity:i.entity}),ma.success("Detached."),await h({links:m,entities:y.filter(d=>d.entity!==i.entity)},{revalidate:!1}),g();}catch(d){ma.error(h$1(d,"The document could not be detached."));}finally{u$1(null);}}async function w(i){u$1(`${i.name}:+`);try{let d=await n.linkSource(o.id,{entity:i.name});ma.success(d.linked?`Applies to every ${u(i)} now.`:`Already applied to every ${u(i)}.`),await h({links:m,entities:y.some(g=>g.entity===i.name)?y:[...y,{entity:i.name,entityPlural:i.plural}]},{revalidate:!1}),g();}catch(d){ma.error(h$1(d,"The document could not be attached."));}finally{u$1(null);}}let x;return c$1?x=jsx("p",{className:"fk:text-sm fk:text-destructive",children:"The linked records could not be loaded."}):p&&!r?x=jsxs("div",{"aria-busy":"true",className:"fk:flex fk:flex-col fk:gap-2",children:[jsx(t$1,{className:"fk:h-6 fk:w-1/2"}),jsx(t$1,{className:"fk:h-6 fk:w-1/3"})]}):f.length===0?x=jsx("p",{className:"fk:text-sm fk:text-muted-foreground",children:'Not attached to any record. Open a record in the Desk and use "Attach document" so the agent searches this document before the rest of Knowledge when asked about that record.'}):x=jsx("div",{className:"fk:flex fk:flex-col fk:gap-4",children:f.map(i=>jsx(Ye,{canMutate:a,detachingKey:s,group:i,onDetach:d=>{b$3(d);}},i.entityPlural))}),jsxs(Fragment,{children:[jsx(tt,{busy:s!==null,canMutate:a,entities:y,isLoading:p&&!r,onAttach:i=>{w(i);},onDetach:i=>{v(i);}}),jsxs("div",{className:"fk:mt-2 fk:flex fk:items-center fk:gap-2",children:[jsx(PaperclipIcon,{className:"fk:size-4 fk:text-muted-foreground"}),jsx("h3",{className:"fk:text-sm fk:font-semibold fk:tracking-tight",children:"Linked records"}),m.length>0?jsx(b$1,{className:"fk:corner-squircle",variant:"outline",children:m.length}):null]}),jsx("p",{className:"fk:text-sm fk:text-muted-foreground",children:"When a question is about one of these records, the agent searches this document before the rest."}),x]})}function tt({busy:n,canMutate:l,entities:o,isLoading:a,onAttach:s,onDetach:u$1}){let{currentProject:r$1}=f(),c=useMemo(()=>r$1?.schema??[],[r$1]),[p,h$1]=useState(false),m=useMemo(()=>v(c,o),[o,c]),y=f=>{let b=t(c,f.entity);return b?u(b):f.entityPlural};return jsxs("div",{className:"fk:flex fk:flex-col fk:gap-3","data-knowledge-applies-to":true,children:[jsxs("div",{className:"fk:flex fk:items-center fk:gap-2",children:[jsx(LayersIcon,{className:"fk:size-4 fk:text-muted-foreground"}),jsx("h3",{className:"fk:text-sm fk:font-semibold fk:tracking-tight",children:"Applies to"}),o.length>0?jsx(b$1,{className:"fk:corner-squircle",variant:"outline",children:o.length}):null]}),jsx("p",{className:"fk:text-sm fk:text-muted-foreground",children:"Attach this document to a whole entity type and the agent searches it before the rest of Knowledge for every record of that type, and for questions about the type in general."}),a?jsx(t$1,{className:"fk:h-7 fk:w-1/3"}):jsxs("div",{className:"fk:flex fk:flex-wrap fk:items-center fk:gap-2",children:[o.map(f=>{let b=y(f);return jsxs(b$1,{className:"fk:gap-1 fk:py-1 fk:pl-2.5 fk:pr-1 fk:corner-squircle",variant:"secondary",children:[jsx("span",{className:"fk:capitalize",children:b}),l?jsxs(b$3,{children:[jsx(c$2,{asChild:true,children:jsx("button",{"aria-label":`No longer apply to every ${b}`,className:"fk:rounded-sm fk:p-0.5 fk:text-muted-foreground fk:hover:text-foreground fk:focus-visible:outline-none fk:focus-visible:ring-2 fk:focus-visible:ring-ring fk:disabled:opacity-50",disabled:n,type:"button",onClick:()=>u$1(f),children:jsx(XIcon,{className:"fk:size-3"})})}),jsxs(e$1,{children:["No longer apply to every ",b]})]}):null]},f.entity)}),jsxs(r,{open:p,onOpenChange:h$1,children:[jsx(ja,{disabled:!l,children:jsx(s$2,{asChild:true,children:jsxs(c$1,{className:"fk:h-7",disabled:!l||m.length===0,size:"sm",variant:"outline",children:[jsx(PlusIcon,{}),"Add entity type"]})})}),jsx(t$3,{align:"start",className:"fk:w-64 fk:p-0",children:jsxs(c$3,{children:[jsx(e$2,{placeholder:"Search entity types"}),jsxs(f$1,{children:[jsx(g$1,{children:"No entity type matches."}),jsx(h,{children:m.map(f=>jsx(j,{keywords:[u(f),f.name,f.plural],value:f.name,onSelect:()=>{h$1(false),s(f);},children:jsx("span",{className:"fk:capitalize",children:u(f)})},f.name))})]})]})})]})]})]})}export{yt as a,bt as b,vt as c};//# sourceMappingURL=chunk-WYVXSLB7.js.map
|
|
2
|
-
//# sourceMappingURL=chunk-
|
|
1
|
+
import'./index.css';import {e,c,b,a,g,h as h$1,m,k as k$2,n}from'./chunk-4JG3OWQW.js';import {e as e$3}from'./chunk-NPO7ISWV.js';import {b as b$2}from'./chunk-DSLPTDZX.js';import {j as j$1}from'./chunk-X5QKLF63.js';import {c as c$4}from'./chunk-2IJWBRN2.js';import {t,s,u,q as q$2,v,k as k$1,i,o as o$1,r as r$1,p as p$2}from'./chunk-7KLXWCDS.js';import {s as s$3,b as b$5}from'./chunk-HOAVEDVI.js';import {f}from'./chunk-Y7VBTUNI.js';import {ja,o,p as p$1,q as q$1,r,s as s$2,t as t$3,ma}from'./chunk-RULCANNM.js';import {t as t$1}from'./chunk-A4DPLZZF.js';import {b as b$4}from'./chunk-G5N6HEPW.js';import {b as b$1,c as c$3,e as e$2,f as f$1,g as g$1,h,j}from'./chunk-5JUG4BEF.js';import {k,p,q,s as s$1,t as t$2}from'./chunk-S7Z6KKIN.js';import {a as a$1,b as b$3,c as c$2,e as e$1}from'./chunk-N33S7BSG.js';import {c as c$1}from'./chunk-X3SHNHHM.js';import {useState,useMemo,useDeferredValue}from'react';import {BookOpenTextIcon,PaperclipIcon,ChevronRightIcon,LayersIcon,XIcon,PlusIcon,Unlink2Icon,LoaderCircle,SearchIcon}from'lucide-react';import {Link}from'react-router-dom';import H from'swr';import Qe from'swr/infinite';import {jsxs,Fragment,jsx}from'react/jsx-runtime';var Be=50;function fe({disabled:n,label:l,onClick:o}){return jsxs(b$3,{children:[jsx(c$2,{asChild:true,children:jsx(c$1,{"aria-label":l,className:"fk:size-7 fk:shrink-0",disabled:n,size:"icon",variant:"ghost",onClick:o,children:jsx(Unlink2Icon,{className:"fk:size-4"})})}),jsx(e$1,{children:l})]})}function Xe({api:n$1,attachedIds:l,onAttached:o,onOpenChange:a,open:s,projectId:u,target:r,targetLabel:c$1}){let[p$1,h]=useState(""),m$1=useDeferredValue(p$1.trim()),[y,f]=useState(null),b$1=(k,K)=>!s||K&&!K.hasMore?null:c(u).sources({limit:Be,offset:k*Be,search:m$1||void 0}),{data:v,error:w,isLoading:x,setSize:i$1,size:d}=Qe(b$1,b,{keepPreviousData:true}),g=useMemo(()=>r$1(v?.flatMap(k=>k.sources)??[],l),[l,v]),L=v?.[v.length-1]?.hasMore??false,C=v!==void 0&&d>v.length;async function A(k){f(k.id);try{let K=await n$1.linkSource(k.id,r);ma.success(K.linked?`Attached "${k.title}".`:`"${k.title}" was already attached.`),o(k),a(!1);}catch(K){ma.error(h$1(K,"The document could not be attached."));}finally{f(null);}}let R;return w?R=jsx("p",{className:"fk:py-6 fk:text-center fk:text-sm fk:text-destructive",children:"The documents could not be loaded."}):x&&!v?R=jsxs("div",{"aria-busy":"true",className:"fk:flex fk:flex-col fk:gap-3 fk:py-2",children:[jsx(t$1,{className:"fk:h-10 fk:w-full"}),jsx(t$1,{className:"fk:h-10 fk:w-full"}),jsx(t$1,{className:"fk:h-10 fk:w-full"})]}):g.length===0&&!L?R=jsx("p",{className:"fk:py-6 fk:text-center fk:text-sm fk:text-muted-foreground",children:m$1?"No documents match your search.":"Every document is attached already, or there are none yet. Add documents in Knowledge first."}):R=jsxs("ul",{className:"fk:flex fk:max-h-80 fk:flex-col fk:overflow-y-auto fk:-mx-2",children:[g.map(k=>{let K=k$1(k),B=y===k.id;return jsx("li",{children:jsxs("button",{className:"fk:flex fk:w-full fk:min-w-0 fk:items-center fk:gap-3 fk:rounded-lg fk:px-2 fk:py-2 fk:text-left fk:transition-colors fk:hover:bg-accent fk:focus-visible:bg-accent fk:focus-visible:outline-none fk:disabled:opacity-60 fk:corner-squircle",disabled:y!==null,type:"button",onClick:()=>{A(k);},children:[jsx(m,{source:k}),jsxs("span",{className:"fk:min-w-0 fk:flex-1",children:[jsx("span",{className:"fk:block fk:truncate fk:text-sm fk:font-medium",children:k.title}),jsxs("span",{className:"fk:block fk:truncate fk:text-xs fk:text-muted-foreground",children:[i(k)," \xB7 ",K.detail]})]}),B?jsx(LoaderCircle,{className:"fk:size-4 fk:shrink-0 fk:animate-spin fk:text-muted-foreground"}):jsx(k$2,{label:K.label,tone:K.tone})]})},k.id)}),L&&!C?jsx("li",{"aria-hidden":true,children:jsx(n,{onVisible:()=>{i$1(k=>k+1);}})}):null,C?jsx("li",{className:"fk:flex fk:justify-center fk:py-2",children:jsx(LoaderCircle,{className:"fk:size-4 fk:animate-spin fk:text-muted-foreground"})}):null]}),jsx(k,{open:s,onOpenChange:a,children:jsxs(p,{className:"fk:sm:max-w-lg",children:[jsxs(q,{children:[jsx(s$1,{children:"Attach a document"}),jsx(t$2,{children:r.recordId===void 0?`Documents attached to every ${c$1} are searched before the rest of Knowledge when a question is about one of them, or about ${c$1} in general.`:`Documents attached to ${c$1} are searched before the rest of Knowledge when a question is about it.`})]}),jsxs("div",{className:"fk:relative",children:[jsx(SearchIcon,{className:"fk:pointer-events-none fk:absolute fk:left-2.5 fk:top-1/2 fk:size-4 fk:-translate-y-1/2 fk:text-muted-foreground"}),jsx(b$4,{"aria-label":"Search documents",autoFocus:true,className:"fk:pl-8",placeholder:"Search documents by title",value:p$1,onChange:k=>h(k.target.value)})]}),R]})})}function re({projectId:n,renderAction:l,sources:o}){return jsx("ul",{className:"fk:flex fk:flex-col fk:gap-1 fk:-mx-2",children:o.map(a=>{let s=k$1(a);return jsxs("li",{className:"fk:flex fk:min-w-0 fk:items-center fk:gap-2 fk:rounded-lg fk:px-2 fk:py-1.5 fk:corner-squircle",children:[jsxs(Link,{className:"fk:flex fk:min-w-0 fk:flex-1 fk:items-center fk:gap-3 fk:rounded-md fk:hover:underline fk:underline-offset-2",to:o$1(n,a.id),children:[jsx(m,{source:a}),jsxs("span",{className:"fk:min-w-0 fk:flex-1",children:[jsx("span",{className:"fk:block fk:truncate fk:text-sm fk:font-medium",children:a.title}),jsxs("span",{className:"fk:block fk:truncate fk:text-xs fk:text-muted-foreground",children:[i(a)," \xB7 ",s.detail]})]})]}),jsx(k$2,{label:s.label,tone:s.tone}),l?.(a)]},a.id)})})}function yt({entityName:n}){let{api:l,projectId:o}=e(),{currentProject:a$1}=f(),[s$1,u$1]=useState(false),r=t(a$1?.schema??[],n),c$2=!!r&&s(n),{data:p,error:h}=H(o&&c$2?c(o).entitySources(n):null,b);if(!l||!o||!r||!c$2||h instanceof a&&h.status===404)return null;let m=p?.sources.length??0;return jsxs(Fragment,{children:[jsxs(c$1,{"aria-label":`Knowledge for every ${u(r)}`,className:"fk:mr-2 fk:h-8","data-knowledge-entity-button":true,size:"sm",variant:"outline",onClick:()=>u$1(true),children:[jsx(BookOpenTextIcon,{}),"Knowledge",m>0?jsx(b$1,{className:"fk:corner-squircle",variant:"secondary",children:m}):null]}),jsx(Ue,{api:l,entityLabel:u(r),entityName:n,open:s$1,projectId:o,onOpenChange:u$1})]})}function Ue({api:n,entityLabel:l,entityName:o,onOpenChange:a,open:s,projectId:u}){let r=b$2(),[c$2,p$1]=useState(false),[h,m]=useState(null),{data:y,error:f,isLoading:b$3,mutate:v}=H(c(u).entitySources(o),b),w=y?.sources??[],x=useMemo(()=>({entity:o}),[o]);async function i(g$1){m(g$1.id);try{await n.unlinkSource(g$1.id,x),ma.success(`"${g$1.title}" no longer applies to every ${l}.`),await v({sources:w.filter(L=>L.id!==g$1.id)},{revalidate:!1}),g();}catch(L){ma.error(h$1(L,"The document could not be detached."));}finally{m(null);}}let d;return f?d=jsx("p",{className:"fk:text-sm fk:text-destructive",children:"The documents could not be loaded."}):b$3&&!y?d=jsxs("div",{"aria-busy":"true",className:"fk:flex fk:flex-col fk:gap-2",children:[jsx(t$1,{className:"fk:h-9 fk:w-full"}),jsx(t$1,{className:"fk:h-9 fk:w-2/3"})]}):w.length===0?d=jsxs("p",{className:"fk:text-sm fk:text-muted-foreground",children:["No documents apply to every ",l," yet. Attach a guide, a policy or a spec that holds for all of them and the agent searches it first when asked about any ",l,", or about ",l," in general."]}):d=jsx(re,{projectId:u,sources:w,renderAction:g=>r?jsx(fe,{disabled:h!==null,label:`Detach ${g.title}`,onClick:()=>{i(g);}}):null}),jsx(k,{open:s,onOpenChange:a,children:jsxs(p,{className:"fk:sm:max-w-lg","data-knowledge-entity-dialog":true,children:[jsxs(q,{children:[jsxs(s$1,{className:"fk:flex fk:items-center fk:gap-2",children:[jsx(BookOpenTextIcon,{className:"fk:size-4 fk:text-muted-foreground"}),"Knowledge for every ",l,y?jsx(b$1,{className:"fk:corner-squircle",variant:"outline",children:w.length}):null]}),jsxs(t$2,{children:["Documents attached here apply to every ",l,"; each record can hold its own on top."]})]}),jsx("div",{className:"fk:max-h-80 fk:overflow-y-auto",children:d}),jsx("div",{className:"fk:flex fk:justify-end",children:jsx(ja,{disabled:!r,children:jsxs(c$1,{disabled:!r,size:"sm",variant:"outline",onClick:()=>p$1(true),children:[jsx(PaperclipIcon,{}),"Attach document"]})})}),jsx(Xe,{api:n,attachedIds:w.map(g=>g.id),open:c$2,projectId:u,target:x,targetLabel:l,onAttached:g$1=>{v({sources:w.some(L=>L.id===g$1.id)?w:[...w,g$1]},{revalidate:false}),g();},onOpenChange:p$1})]})})}function bt({entityName:n,recordId:l,recordLabel:o$1}){let{api:a$2,projectId:s$1}=e(),{currentProject:u$1}=f(),r=b$2(),[c$2,p]=useState(false),[h,m]=useState(false),[y,f$1]=useState(null),b$3=useMemo(()=>({entity:n,recordId:l}),[n,l]),v=t(u$1?.schema??[],n),w=v?u(v):n,x=s(n),{data:i,error:d,isLoading:g$1,mutate:L}=H(s$1&&x?c(s$1).recordSources(b$3):null,b);if(!a$2||!s$1||!x||d instanceof a&&d.status===404)return null;let C=i?.sources??[],A=i?.inherited??[],R=C.map(N=>N.id),k=a$2;async function K(N){f$1(N.id);try{await k.unlinkSource(N.id,b$3),ma.success(`Detached "${N.title}".`),await L({sources:C.filter($=>$.id!==N.id),inherited:A},{revalidate:!1}),g();}catch($){ma.error(h$1($,"The document could not be detached."));}finally{f$1(null);}}let B;return d?B=jsx("p",{className:"fk:text-sm fk:text-destructive",children:"The attached documents could not be loaded."}):g$1&&!i?B=jsxs("div",{"aria-busy":"true",className:"fk:flex fk:flex-col fk:gap-2",children:[jsx(t$1,{className:"fk:h-9 fk:w-full"}),jsx(t$1,{className:"fk:h-9 fk:w-2/3"})]}):B=jsxs("div",{className:"fk:flex fk:flex-col fk:gap-4",children:[C.length===0?jsx("p",{className:"fk:text-sm fk:text-muted-foreground",children:A.length>0?"No documents attached to this record itself; the ones below apply to every record of its type.":"No documents attached. Attach a manual, spec or contract and the agent will use it alongside the record's data when asked about this record."}):jsx(re,{projectId:s$1,sources:C,renderAction:N=>r?jsx(fe,{disabled:y!==null,label:`Detach ${N.title}`,onClick:()=>{K(N);}}):null}),A.length>0?jsxs("div",{className:"fk:flex fk:flex-col fk:gap-1","data-knowledge-inherited":true,children:[jsxs("span",{className:"fk:text-xs fk:font-medium fk:uppercase fk:tracking-wide fk:text-muted-foreground",children:["Applies to every ",w]}),jsx(re,{projectId:s$1,sources:A})]}):null]}),jsx(a$1,{children:jsxs(o,{className:`fk:z-10 fk:flex fk:shrink-0 fk:flex-col fk:border-t fk:bg-background ${c$2?"fk:h-1/2":""}`,"data-knowledge-record-panel":true,open:c$2,onOpenChange:p,children:[jsxs("div",{className:"fk:flex fk:shrink-0 fk:items-center fk:gap-2 fk:pl-4 fk:pr-10 fk:py-2",children:[jsx(p$1,{asChild:true,children:jsxs("button",{className:"fk:flex fk:min-w-0 fk:flex-1 fk:items-center fk:gap-2 fk:rounded-md fk:py-1 fk:text-left fk:text-sm fk:font-semibold fk:tracking-tight fk:hover:text-foreground/80 fk:focus-visible:outline-none fk:focus-visible:ring-2 fk:focus-visible:ring-ring",type:"button",children:[jsx(ChevronRightIcon,{className:`fk:size-4 fk:shrink-0 fk:text-muted-foreground fk:transition-transform ${c$2?"fk:rotate-90":""}`}),jsx(BookOpenTextIcon,{className:"fk:size-4 fk:shrink-0 fk:text-muted-foreground"}),"Knowledge",i?jsx(b$1,{className:"fk:corner-squircle",variant:"outline",children:C.length+A.length}):null]})}),c$2?jsx(ja,{disabled:!r,children:jsxs(c$1,{disabled:!r,size:"sm",variant:"outline",onClick:()=>m(true),children:[jsx(PaperclipIcon,{}),"Attach document"]})}):null]}),jsx(q$1,{className:"fk:min-h-0 fk:flex-1 fk:overflow-y-auto fk:px-10 fk:pb-6",children:B}),jsx(Xe,{api:a$2,attachedIds:R,open:h,projectId:s$1,target:b$3,targetLabel:o$1||`this ${n}`,onAttached:N=>{L({sources:C.some($=>$.id===N.id)?C:[...C,N],inherited:A.filter($=>$.id!==N.id)},{revalidate:false}),g();},onOpenChange:m})]})})}function Ze(n,l,o){let{scope:a}=c$4(),s=n.links.map(r=>r.recordId),{data:u}=e$3({entityNamePlural:n.entityPlural,schema:l,scope:a,selection:"display",includeCount:false,variables:{where:{_id:{in:s}},limit:s.length}});return useMemo(()=>{let r={};for(let c of u??[]){let p=c[o.name];typeof p=="string"&&p.trim()&&(r[c._id]=p);}return r},[u,o])}function Ye(n){let{currentProject:l}=f(),o=useMemo(()=>l?.schema??[],[l]),a=s$3(o,n.group.entityPlural),s=b$5(a);return !a||!s?jsx(Je,{...n,entityLabel:a?u(a):n.group.entityPlural,labels:{}}):jsx(et,{...n,displayAttribute:s,schema:o,entityLabel:u(a)})}function et({displayAttribute:n,entityLabel:l,schema:o,...a}){let s=Ze(a.group,o,n);return jsx(Je,{...a,entityLabel:l,labels:s})}function Je({canMutate:n,detachingKey:l,entityLabel:o,group:a,labels:s,onDetach:u}){let r=j$1();return jsxs("div",{className:"fk:flex fk:flex-col fk:gap-1",children:[jsx("span",{className:"fk:text-xs fk:font-medium fk:uppercase fk:tracking-wide fk:text-muted-foreground",children:o}),jsx("ul",{className:"fk:flex fk:flex-col fk:-mx-2",children:a.links.map(c=>{let p=p$2(c,s[c.recordId]),h=`${c.entity}:${c.recordId}`;return jsxs("li",{className:"fk:flex fk:min-w-0 fk:items-center fk:gap-2 fk:rounded-lg fk:px-2 fk:py-1 fk:corner-squircle",children:[jsx("button",{className:"fk:min-w-0 fk:flex-1 fk:truncate fk:text-left fk:text-sm fk:hover:underline fk:underline-offset-2",title:c.recordId,type:"button",onClick:()=>r({type:"EditEntity",payload:{entityId:c.recordId,entityNamePlural:a.entityPlural}}),children:p}),n?jsx(fe,{disabled:l!==null,label:`Detach from ${p}`,onClick:()=>u(c)}):null]},h)})})]})}function vt({api:n,projectId:l,source:o}){let a=b$2(),[s,u$1]=useState(null),{data:r,error:c$1,isLoading:p,mutate:h}=H(c(l).links(o.id),b),m=useMemo(()=>r?.links??[],[r]),y=useMemo(()=>r?.entities??[],[r]),f=useMemo(()=>q$2(m),[m]);async function b$3(i){u$1(`${i.entity}:${i.recordId}`);try{await n.unlinkSource(o.id,{entity:i.entity,recordId:i.recordId}),ma.success("Detached."),await h({links:m.filter(d=>d.entity!==i.entity||d.recordId!==i.recordId),entities:y},{revalidate:!1}),g();}catch(d){ma.error(h$1(d,"The document could not be detached."));}finally{u$1(null);}}async function v(i){u$1(`${i.entity}:*`);try{await n.unlinkSource(o.id,{entity:i.entity}),ma.success("Detached."),await h({links:m,entities:y.filter(d=>d.entity!==i.entity)},{revalidate:!1}),g();}catch(d){ma.error(h$1(d,"The document could not be detached."));}finally{u$1(null);}}async function w(i){u$1(`${i.name}:+`);try{let d=await n.linkSource(o.id,{entity:i.name});ma.success(d.linked?`Applies to every ${u(i)} now.`:`Already applied to every ${u(i)}.`),await h({links:m,entities:y.some(g=>g.entity===i.name)?y:[...y,{entity:i.name,entityPlural:i.plural}]},{revalidate:!1}),g();}catch(d){ma.error(h$1(d,"The document could not be attached."));}finally{u$1(null);}}let x;return c$1?x=jsx("p",{className:"fk:text-sm fk:text-destructive",children:"The linked records could not be loaded."}):p&&!r?x=jsxs("div",{"aria-busy":"true",className:"fk:flex fk:flex-col fk:gap-2",children:[jsx(t$1,{className:"fk:h-6 fk:w-1/2"}),jsx(t$1,{className:"fk:h-6 fk:w-1/3"})]}):f.length===0?x=jsx("p",{className:"fk:text-sm fk:text-muted-foreground",children:'Not attached to any record. Open a record in the Desk and use "Attach document" so the agent searches this document before the rest of Knowledge when asked about that record.'}):x=jsx("div",{className:"fk:flex fk:flex-col fk:gap-4",children:f.map(i=>jsx(Ye,{canMutate:a,detachingKey:s,group:i,onDetach:d=>{b$3(d);}},i.entityPlural))}),jsxs(Fragment,{children:[jsx(tt,{busy:s!==null,canMutate:a,entities:y,isLoading:p&&!r,onAttach:i=>{w(i);},onDetach:i=>{v(i);}}),jsxs("div",{className:"fk:mt-2 fk:flex fk:items-center fk:gap-2",children:[jsx(PaperclipIcon,{className:"fk:size-4 fk:text-muted-foreground"}),jsx("h3",{className:"fk:text-sm fk:font-semibold fk:tracking-tight",children:"Linked records"}),m.length>0?jsx(b$1,{className:"fk:corner-squircle",variant:"outline",children:m.length}):null]}),jsx("p",{className:"fk:text-sm fk:text-muted-foreground",children:"When a question is about one of these records, the agent searches this document before the rest."}),x]})}function tt({busy:n,canMutate:l,entities:o,isLoading:a,onAttach:s,onDetach:u$1}){let{currentProject:r$1}=f(),c=useMemo(()=>r$1?.schema??[],[r$1]),[p,h$1]=useState(false),m=useMemo(()=>v(c,o),[o,c]),y=f=>{let b=t(c,f.entity);return b?u(b):f.entityPlural};return jsxs("div",{className:"fk:flex fk:flex-col fk:gap-3","data-knowledge-applies-to":true,children:[jsxs("div",{className:"fk:flex fk:items-center fk:gap-2",children:[jsx(LayersIcon,{className:"fk:size-4 fk:text-muted-foreground"}),jsx("h3",{className:"fk:text-sm fk:font-semibold fk:tracking-tight",children:"Applies to"}),o.length>0?jsx(b$1,{className:"fk:corner-squircle",variant:"outline",children:o.length}):null]}),jsx("p",{className:"fk:text-sm fk:text-muted-foreground",children:"Attach this document to a whole entity type and the agent searches it before the rest of Knowledge for every record of that type, and for questions about the type in general."}),a?jsx(t$1,{className:"fk:h-7 fk:w-1/3"}):jsxs("div",{className:"fk:flex fk:flex-wrap fk:items-center fk:gap-2",children:[o.map(f=>{let b=y(f);return jsxs(b$1,{className:"fk:gap-1 fk:py-1 fk:pl-2.5 fk:pr-1 fk:corner-squircle",variant:"secondary",children:[jsx("span",{className:"fk:capitalize",children:b}),l?jsxs(b$3,{children:[jsx(c$2,{asChild:true,children:jsx("button",{"aria-label":`No longer apply to every ${b}`,className:"fk:rounded-sm fk:p-0.5 fk:text-muted-foreground fk:hover:text-foreground fk:focus-visible:outline-none fk:focus-visible:ring-2 fk:focus-visible:ring-ring fk:disabled:opacity-50",disabled:n,type:"button",onClick:()=>u$1(f),children:jsx(XIcon,{className:"fk:size-3"})})}),jsxs(e$1,{children:["No longer apply to every ",b]})]}):null]},f.entity)}),jsxs(r,{open:p,onOpenChange:h$1,children:[jsx(ja,{disabled:!l,children:jsx(s$2,{asChild:true,children:jsxs(c$1,{className:"fk:h-7",disabled:!l||m.length===0,size:"sm",variant:"outline",children:[jsx(PlusIcon,{}),"Add entity type"]})})}),jsx(t$3,{align:"start",className:"fk:w-64 fk:p-0",children:jsxs(c$3,{children:[jsx(e$2,{placeholder:"Search entity types"}),jsxs(f$1,{children:[jsx(g$1,{children:"No entity type matches."}),jsx(h,{children:m.map(f=>jsx(j,{keywords:[u(f),f.name,f.plural],value:f.name,onSelect:()=>{h$1(false),s(f);},children:jsx("span",{className:"fk:capitalize",children:u(f)})},f.name))})]})]})})]})]})]})}export{yt as a,bt as b,vt as c};//# sourceMappingURL=chunk-CQS6AIOX.js.map
|
|
2
|
+
//# sourceMappingURL=chunk-CQS6AIOX.js.map
|