@flexkit/studio 0.2.25 → 0.2.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{activity-nav-button-4VTYGP4T.js → activity-nav-button-DIYOSLHR.js} +2 -2
- package/dist/{activity-nav-button-4VTYGP4T.js.map → activity-nav-button-DIYOSLHR.js.map} +1 -1
- package/dist/chat-page-4YW4GADV.js +4 -0
- package/dist/chat-page-4YW4GADV.js.map +1 -0
- package/dist/chunk-2IFBQNWA.js +2 -0
- package/dist/chunk-2IFBQNWA.js.map +1 -0
- package/dist/chunk-32M62H3K.js +8 -0
- package/dist/chunk-32M62H3K.js.map +1 -0
- package/dist/{chunk-T7N3WUV2.js → chunk-4ZRVKNBI.js} +2 -2
- package/dist/{chunk-T7N3WUV2.js.map → chunk-4ZRVKNBI.js.map} +1 -1
- package/dist/{chunk-PJ3ZOCQ3.js → chunk-54WDEDM4.js} +2 -2
- package/dist/{chunk-PJ3ZOCQ3.js.map → chunk-54WDEDM4.js.map} +1 -1
- package/dist/{chunk-IPQYDKPP.js → chunk-DZTBKBD6.js} +3 -3
- package/dist/{chunk-IPQYDKPP.js.map → chunk-DZTBKBD6.js.map} +1 -1
- package/dist/{chunk-2XQHISFR.js → chunk-FVNVNXEV.js} +2 -2
- package/dist/{chunk-2XQHISFR.js.map → chunk-FVNVNXEV.js.map} +1 -1
- package/dist/{chunk-SRFTSMZD.js → chunk-HAU76X63.js} +3 -3
- package/dist/{chunk-SRFTSMZD.js.map → chunk-HAU76X63.js.map} +1 -1
- package/dist/{chunk-JTUOTP5S.js → chunk-I4UFLN53.js} +3 -3
- package/dist/{chunk-JTUOTP5S.js.map → chunk-I4UFLN53.js.map} +1 -1
- package/dist/chunk-IA5Z6LYD.js +3 -0
- package/dist/chunk-IA5Z6LYD.js.map +1 -0
- package/dist/{chunk-SKHHYRVA.js → chunk-JPZFJHZP.js} +2 -2
- package/dist/{chunk-SKHHYRVA.js.map → chunk-JPZFJHZP.js.map} +1 -1
- package/dist/{chunk-5OGT6WGZ.js → chunk-KOAZBC6O.js} +2 -2
- package/dist/{chunk-5OGT6WGZ.js.map → chunk-KOAZBC6O.js.map} +1 -1
- package/dist/{chunk-WO5OQNAN.js → chunk-LG2KGSQ4.js} +2 -2
- package/dist/{chunk-WO5OQNAN.js.map → chunk-LG2KGSQ4.js.map} +1 -1
- package/dist/{chunk-QW6H7OZ6.js → chunk-OM2SSOTB.js} +3 -3
- package/dist/{chunk-QW6H7OZ6.js.map → chunk-OM2SSOTB.js.map} +1 -1
- package/dist/{chunk-OCWM45Z2.js → chunk-RP2CTEIL.js} +3 -3
- package/dist/{chunk-OCWM45Z2.js.map → chunk-RP2CTEIL.js.map} +1 -1
- package/dist/{chunk-SK7C7CGH.js → chunk-TWALS64F.js} +3 -3
- package/dist/{chunk-SK7C7CGH.js.map → chunk-TWALS64F.js.map} +1 -1
- package/dist/{chunk-X452A7C3.js → chunk-ZA2LLGNZ.js} +2 -2
- package/dist/{chunk-X452A7C3.js.map → chunk-ZA2LLGNZ.js.map} +1 -1
- package/dist/{entry-ZII6ECS5.js → entry-XXLNSL6Q.js} +2 -2
- package/dist/{entry-ZII6ECS5.js.map → entry-XXLNSL6Q.js.map} +1 -1
- package/dist/index.js +7 -7
- package/dist/index.js.map +1 -1
- package/dist/{list-YIIXASZF.js → list-52ORZRD5.js} +3 -3
- package/dist/{list-YIIXASZF.js.map → list-52ORZRD5.js.map} +1 -1
- package/dist/{list-76SBWKGF.js → list-EFL32GDI.js} +2 -2
- package/dist/{list-76SBWKGF.js.map → list-EFL32GDI.js.map} +1 -1
- package/dist/{pages-N3IGHP7Y.js → pages-VIE6KUBE.js} +3 -3
- package/dist/{pages-N3IGHP7Y.js.map → pages-VIE6KUBE.js.map} +1 -1
- package/dist/{plugin-pages-MLF2FUBT.js → plugin-pages-HTXOLHG2.js} +2 -2
- package/dist/{plugin-pages-MLF2FUBT.js.map → plugin-pages-HTXOLHG2.js.map} +1 -1
- package/dist/record-links-NPBFSAHR.js +2 -0
- package/dist/{record-links-66T2CJRM.js.map → record-links-NPBFSAHR.js.map} +1 -1
- package/dist/{root-RD5VRALH.js → root-27HUK3RU.js} +2 -2
- package/dist/{root-RD5VRALH.js.map → root-27HUK3RU.js.map} +1 -1
- package/dist/{root-MDKGJJB4.js → root-2AXD4MNR.js} +2 -2
- package/dist/{root-MDKGJJB4.js.map → root-2AXD4MNR.js.map} +1 -1
- package/dist/{root-6Y5RN4PW.js → root-2QPYALTV.js} +3 -3
- package/dist/{root-6Y5RN4PW.js.map → root-2QPYALTV.js.map} +1 -1
- package/dist/{root-UKGHRHON.js → root-7ZAUENIS.js} +3 -3
- package/dist/{root-UKGHRHON.js.map → root-7ZAUENIS.js.map} +1 -1
- package/dist/{root-FGVYUZZ6.js → root-K7JKAYLS.js} +2 -2
- package/dist/{root-FGVYUZZ6.js.map → root-K7JKAYLS.js.map} +1 -1
- package/dist/{root-BRC7XSCT.js → root-M62U2FKR.js} +3 -3
- package/dist/{root-BRC7XSCT.js.map → root-M62U2FKR.js.map} +1 -1
- package/dist/{search-IM2VPW6O.js → search-FJUNXO53.js} +2 -2
- package/dist/{search-IM2VPW6O.js.map → search-FJUNXO53.js.map} +1 -1
- package/dist/{skills-pages-LZCCHOJB.js → skills-pages-Q6NGTRVW.js} +2 -2
- package/dist/{skills-pages-LZCCHOJB.js.map → skills-pages-Q6NGTRVW.js.map} +1 -1
- package/dist/{source-ZLZHE7TL.js → source-INDEOHP7.js} +2 -2
- package/dist/{source-ZLZHE7TL.js.map → source-INDEOHP7.js.map} +1 -1
- package/package.json +5 -5
- package/dist/chat-page-Z7HA3GSH.js +0 -4
- package/dist/chat-page-Z7HA3GSH.js.map +0 -1
- package/dist/chunk-D6NOMUTD.js +0 -8
- package/dist/chunk-D6NOMUTD.js.map +0 -1
- package/dist/chunk-MNLYE7DK.js +0 -3
- package/dist/chunk-MNLYE7DK.js.map +0 -1
- package/dist/chunk-U6E7GNQW.js +0 -2
- package/dist/chunk-U6E7GNQW.js.map +0 -1
- package/dist/record-links-66T2CJRM.js +0 -2
|
@@ -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-WO5OQNAN.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-LG2KGSQ4.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 {a}from'./chunk-HKN6BX5U.js';import {c}from'./chunk-WPCPL2TQ.js';import {b,c as c$1}from'./chunk-5CVDMZUI.js';import {useState,useEffect}from'react';var d="0.2.
|
|
1
|
+
import'./index.css';import {a}from'./chunk-HKN6BX5U.js';import {c}from'./chunk-WPCPL2TQ.js';import {b,c as c$1}from'./chunk-5CVDMZUI.js';import {useState,useEffect}from'react';var d="0.2.27",L={current:d,latest:d,isCurrent:true};function le(){let e=b(),[t,r]=useState(null);return useEffect(()=>{if(e)return e.onUpdateDownloaded(o=>{r(o.version);})},[e]),e?t===null?{current:e.version,latest:e.version,isCurrent:true}:{current:e.version,latest:t,isCurrent:false,upgrade:()=>e.installUpdate()}:L}var U="flexkit:telemetry",V="flexkit:error-reporting",B=/^(localhost|127\.0\.0\.1|\[::1\]|0\.0\.0\.0)$|\.(localhost|test|local)$/i;function M(e){return e.override==="on"?true:e.override==="off"||!e.hosted||e.domain!=="flexkit.io"||e.version==="0.0.0"?false:e.isDesktop||!B.test(e.hostname)}function Y(){try{let e=a();return e?.getItem(U)??e?.getItem(V)??null}catch{return null}}function k({hosted:e}){return typeof window>"u"?false:M({hosted:e,isDesktop:!!b(),domain:c$1,hostname:window.location.hostname,version:d,override:Y()})}async function v(e,t,{keepalive:r=false}={}){return (await fetch(e,{body:t,credentials:"same-origin",headers:{"Content-Type":"application/json"},keepalive:r,method:"POST"})).status}var f={componentStack:4e3,message:2e3,name:200,path:500,stack:8e3,userAgent:500},$=10,G=6e4,K=50,z=5e3,R=/^[a-z0-9]{1,64}$/;function g(e,t){return e.length>t?e.slice(0,t):e}function J(e){let t=e;try{/^[a-z][a-z0-9+.-]*:/i.test(e)&&(t=new URL(e).pathname);}catch{}return g(t.split(/[?#]/)[0]??"",f.path)}function H(e){if(e instanceof Error)return {name:e.name||"Error",message:typeof e.message=="string"?e.message:"",stack:typeof e.stack=="string"?e.stack:void 0};if(typeof e=="string")return {name:"Error",message:e};if(e==null)return {name:"Error",message:`Non-Error thrown: ${String(e)}`};if(typeof e=="object"){let t=e.constructor?.name;return {name:"Error",message:`Non-Error thrown: ${typeof t=="string"&&t?t:"object"}`}}return {name:"Error",message:`Non-Error thrown: ${typeof e}`}}var X=[/ResizeObserver loop (limit exceeded|completed with undelivered notifications)/i,/^Script error\.?$/i,/The (operation|user) (was )?aborted/i,/signal is aborted without reason/i],A=/\b(chrome|moz|safari(-web)?|ms-browser)-extension:\/\//i,F=/[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/gi;function Z(e){return e.replace(F,"<email>")}function q(e,t){return e.name==="AbortError"||X.some(r=>r.test(e.message))||t&&A.test(t)?true:!!(e.stack&&A.test(e.stack))}function W(e,t){let r=H(e);if(q(r,t.sourceUrl))return null;let o={source:t.source,name:g(r.name,f.name),message:g(Z(r.message),f.message),occurredAt:(t.now??new Date).toISOString()};return r.stack&&(o.stack=g(r.stack,f.stack)),t.componentStack&&(o.componentStack=g(t.componentStack,f.componentStack)),t.path&&(o.path=J(t.path)),t.projectId&&R.test(t.projectId)&&(o.projectId=t.projectId),o}function Q(e){return `${e.name}
|
|
2
2
|
${e.message}
|
|
3
|
-
${e.stack??""}`}var ee=new TextEncoder;function P(e){return ee.encode(e).length}function te(e,t,r=G){let o=P(JSON.stringify({app:e,errors:[]})),s=[];for(let i of t.slice(0,$)){let n=P(JSON.stringify(i))+(s.length?1:0);if(o+n>r)break;o+=n,s.push(i);}return s.length===0?null:{body:JSON.stringify({app:e,errors:s}),count:s.length}}function re({app:e,send:t,getPath:r,now:o=()=>new Date,setTimer:s=(n,u)=>setTimeout(n,u),clearTimer:i=n=>clearTimeout(n)}){let n=[],u=new Set,_=0,y=null,a=null,E=false;function T(){a===null&&n.length>0&&!E&&(a=s(()=>{a=null,x();},z));}function D(l){let S=te(e,n);return S?(n.splice(0,S.count),t(S.body,{unloading:l}).then(p=>{(p===401||p===403||p===429)&&(E=true,n.length=0);}).catch(()=>{}),n.length>0):(n.shift(),n.length>0)}function x({unloading:l=false}={}){try{if(E)return;a!==null&&l&&(i(a),a=null),n.length>0&&D(l),T();}catch{}}return {report(l,S){try{if(E||_>=K)return;let p=W(l,{...S,now:o(),path:r?.(),projectId:y});if(!p)return;let b=Q(p);if(u.has(b))return;u.add(b),_+=1,n.push(p),T();}catch{}},setProjectId(l){y=l;},flush:x,pending:()=>n,dispose(){a!==null&&(i(a),a=null),E=true,n.length=0;}}}var ne=async(e,{unloading:t})=>{let r=c.clientErrors;if(t&&!b()&&typeof navigator<"u"&&typeof navigator.sendBeacon=="function")try{if(navigator.sendBeacon(r,new Blob([e],{type:"text/plain"})))return null}catch{}return v(r,e,{keepalive:t})},m=null;function we(e,{source:t="manual",componentStack:r}={}){m?.report(e,{source:t,componentStack:r});}function Re(e){m?.setProjectId(e);}function _e({hosted:e}){if(typeof window>"u"||m)return ()=>{};if(!k({hosted:e}))return ()=>{};let t=b(),r=re({app:{platform:t?"desktop":"web",version:d,userAgent:g(navigator.userAgent,f.userAgent)},send:ne,getPath:()=>window.location.pathname});function o(n){r.report(n.error??n.message,{source:"window",sourceUrl:n.filename});}function s(n){r.report(n.reason,{source:"unhandledrejection"});}function i(){r.flush({unloading:true});}return window.addEventListener("error",o),window.addEventListener("unhandledrejection",s),window.addEventListener("pagehide",i),m=r,()=>{window.removeEventListener("error",o),window.removeEventListener("unhandledrejection",s),window.removeEventListener("pagehide",i),r.flush({unloading:true}),r.dispose(),m===r&&(m=null);}}function oe(e){return e.event==="graph_opened"?`graph_opened:${e.projectId}`:e.event}function ie(e){let t=new Set,r=new Set;return {track(o,{onDelivered:s}={}){let i=oe(o);if(t.has(i)||r.has(i))return;t.add(i);let n=u=>{t.delete(i),u!==null&&u>=200&&u<300&&(r.add(i),s?.());};try{e(JSON.stringify(o)).then(n,()=>n(null));}catch{n(null);}}}}var w=null;function Oe(e){e.event==="graph_opened"&&!R.test(e.projectId)||w?.track(e);}var C="flexkit:desktop-launch-recorded";function se(e){try{return sessionStorage.getItem(e)==="1"}catch{return false}}function ae(e){try{sessionStorage.setItem(e,"1");}catch{}}function Ae({hosted:e}){if(!k({hosted:e}))return ()=>{};let t=ie(o=>v(c.productEvents,o,{keepalive:true})),r=b();return w=t,r&&!se(C)&&t.track({appVersion:r.version,event:"desktop_app_opened",os:r.platform},{onDelivered:()=>ae(C)}),()=>{w===t&&(w=null);}}export{le as a,we as b,Re as c,_e as d,Oe as e,Ae as f};//# sourceMappingURL=chunk-
|
|
4
|
-
//# sourceMappingURL=chunk-
|
|
3
|
+
${e.stack??""}`}var ee=new TextEncoder;function P(e){return ee.encode(e).length}function te(e,t,r=G){let o=P(JSON.stringify({app:e,errors:[]})),s=[];for(let i of t.slice(0,$)){let n=P(JSON.stringify(i))+(s.length?1:0);if(o+n>r)break;o+=n,s.push(i);}return s.length===0?null:{body:JSON.stringify({app:e,errors:s}),count:s.length}}function re({app:e,send:t,getPath:r,now:o=()=>new Date,setTimer:s=(n,u)=>setTimeout(n,u),clearTimer:i=n=>clearTimeout(n)}){let n=[],u=new Set,_=0,y=null,a=null,E=false;function T(){a===null&&n.length>0&&!E&&(a=s(()=>{a=null,x();},z));}function D(l){let S=te(e,n);return S?(n.splice(0,S.count),t(S.body,{unloading:l}).then(p=>{(p===401||p===403||p===429)&&(E=true,n.length=0);}).catch(()=>{}),n.length>0):(n.shift(),n.length>0)}function x({unloading:l=false}={}){try{if(E)return;a!==null&&l&&(i(a),a=null),n.length>0&&D(l),T();}catch{}}return {report(l,S){try{if(E||_>=K)return;let p=W(l,{...S,now:o(),path:r?.(),projectId:y});if(!p)return;let b=Q(p);if(u.has(b))return;u.add(b),_+=1,n.push(p),T();}catch{}},setProjectId(l){y=l;},flush:x,pending:()=>n,dispose(){a!==null&&(i(a),a=null),E=true,n.length=0;}}}var ne=async(e,{unloading:t})=>{let r=c.clientErrors;if(t&&!b()&&typeof navigator<"u"&&typeof navigator.sendBeacon=="function")try{if(navigator.sendBeacon(r,new Blob([e],{type:"text/plain"})))return null}catch{}return v(r,e,{keepalive:t})},m=null;function we(e,{source:t="manual",componentStack:r}={}){m?.report(e,{source:t,componentStack:r});}function Re(e){m?.setProjectId(e);}function _e({hosted:e}){if(typeof window>"u"||m)return ()=>{};if(!k({hosted:e}))return ()=>{};let t=b(),r=re({app:{platform:t?"desktop":"web",version:d,userAgent:g(navigator.userAgent,f.userAgent)},send:ne,getPath:()=>window.location.pathname});function o(n){r.report(n.error??n.message,{source:"window",sourceUrl:n.filename});}function s(n){r.report(n.reason,{source:"unhandledrejection"});}function i(){r.flush({unloading:true});}return window.addEventListener("error",o),window.addEventListener("unhandledrejection",s),window.addEventListener("pagehide",i),m=r,()=>{window.removeEventListener("error",o),window.removeEventListener("unhandledrejection",s),window.removeEventListener("pagehide",i),r.flush({unloading:true}),r.dispose(),m===r&&(m=null);}}function oe(e){return e.event==="graph_opened"?`graph_opened:${e.projectId}`:e.event}function ie(e){let t=new Set,r=new Set;return {track(o,{onDelivered:s}={}){let i=oe(o);if(t.has(i)||r.has(i))return;t.add(i);let n=u=>{t.delete(i),u!==null&&u>=200&&u<300&&(r.add(i),s?.());};try{e(JSON.stringify(o)).then(n,()=>n(null));}catch{n(null);}}}}var w=null;function Oe(e){e.event==="graph_opened"&&!R.test(e.projectId)||w?.track(e);}var C="flexkit:desktop-launch-recorded";function se(e){try{return sessionStorage.getItem(e)==="1"}catch{return false}}function ae(e){try{sessionStorage.setItem(e,"1");}catch{}}function Ae({hosted:e}){if(!k({hosted:e}))return ()=>{};let t=ie(o=>v(c.productEvents,o,{keepalive:true})),r=b();return w=t,r&&!se(C)&&t.track({appVersion:r.version,event:"desktop_app_opened",os:r.platform},{onDelivered:()=>ae(C)}),()=>{w===t&&(w=null);}}export{le as a,we as b,Re as c,_e as d,Oe as e,Ae as f};//# sourceMappingURL=chunk-OM2SSOTB.js.map
|
|
4
|
+
//# sourceMappingURL=chunk-OM2SSOTB.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/use-studio-version.ts","../src/core/telemetry.ts","../src/core/error/error-reporter.ts","../src/core/analytics/product-events.ts"],"names":["STUDIO_VERSION","WEB_VERSION","useStudioVersion","desktop","getDesktop","downloaded","setDownloaded","useState","useEffect","update","TELEMETRY_STORAGE_KEY","LEGACY_TELEMETRY_STORAGE_KEY","LOCAL_HOSTNAME","isTelemetryEnabled","env","readOverride","storage","getLocalStorage","isStudioTelemetryEnabled","hosted","flexkitDomain","postToUserApi","path","body","keepalive","LIMITS","MAX_ERRORS_PER_REPORT","MAX_REPORT_BYTES","MAX_ERRORS_PER_SESSION","FLUSH_INTERVAL_MS","PROJECT_ID_PATTERN","truncate","value","max","toReportPath","pathOrUrl","describeError","error","constructorName","NOISE_MESSAGES","EXTENSION_URL","EMAIL_ADDRESS","maskMessage","message","isNoiseError","details","sourceUrl","pattern","buildClientError","options","entry","errorKey","encoder","byteLength","buildReportBody","app","queue","maxBytes","size","errors","errorSize","createErrorReporter","send","getPath","now","setTimer","callback","ms","clearTimer","timer","seen","accepted","projectId","stopped","schedule","flush","sendNext","unloading","next","status","key","id","sendReportToBff","url","userApiPaths","installed","reportStudioError","source","componentStack","setErrorReportingProjectId","installErrorReporter","reporter","onError","event","onUnhandledRejection","onPageHide","productEventKey","studioEvent","createProductEventTracker","pending","delivered","onDelivered","settle","tracker","trackStudioEvent","DESKTOP_LAUNCH_STORAGE_KEY","readSessionFlag","writeSessionFlag","installProductEvents","current"],"mappings":"gLAeO,IAAMA,CAAAA,CAA0D,QAAA,CACjEC,CAAAA,CAA6B,CAAE,OAAA,CAASD,CAAAA,CAAgB,MAAA,CAAQA,CAAAA,CAAgB,SAAA,CAAW,IAAK,CAAA,CAO/F,SAASE,EAAAA,EAAkC,CAChD,IAAMC,CAAAA,CAAUC,CAAAA,EAAW,CACrB,CAACC,CAAAA,CAAYC,CAAa,CAAA,CAAIC,SAAwB,IAAI,CAAA,CAYhE,OAVAC,SAAAA,CAAU,IAAM,CACd,GAAKL,CAAAA,CAIL,OAAOA,CAAAA,CAAQ,kBAAA,CAAoBM,CAAAA,EAAW,CAC5CH,CAAAA,CAAcG,CAAAA,CAAO,OAAO,EAC9B,CAAC,CACH,CAAA,CAAG,CAACN,CAAO,CAAC,CAAA,CAEPA,CAAAA,CAIDE,CAAAA,GAAe,IAAA,CACV,CAAE,OAAA,CAASF,CAAAA,CAAQ,OAAA,CAAS,MAAA,CAAQA,CAAAA,CAAQ,QAAS,SAAA,CAAW,IAAK,CAAA,CAGvE,CAAE,OAAA,CAASA,CAAAA,CAAQ,OAAA,CAAS,MAAA,CAAQE,CAAAA,CAAY,SAAA,CAAW,KAAA,CAAO,OAAA,CAAS,IAAMF,CAAAA,CAAQ,aAAA,EAAgB,CAAA,CAPvGF,CAQX,CClCO,IAAMS,CAAAA,CAAwB,mBAAA,CAExBC,CAAAA,CAA+B,yBAAA,CAatCC,CAAAA,CAAiB,0EAAA,CAQhB,SAASC,CAAAA,CAAmBC,CAAAA,CAAoC,CACrE,OAAIA,CAAAA,CAAI,WAAa,IAAA,CACZ,IAAA,CAGLA,CAAAA,CAAI,QAAA,GAAa,KAAA,EAIjB,CAACA,CAAAA,CAAI,MAAA,EAAUA,CAAAA,CAAI,MAAA,GAAW,YAAA,EAAgBA,CAAAA,CAAI,OAAA,GAAY,OAAA,CACzD,KAAA,CAGFA,CAAAA,CAAI,WAAa,CAACF,CAAAA,CAAe,IAAA,CAAKE,CAAAA,CAAI,QAAQ,CAC3D,CAEA,SAASC,CAAAA,EAA8B,CACrC,GAAI,CACF,IAAMC,CAAAA,CAAUC,CAAAA,EAAgB,CAEhC,OAAOD,CAAAA,EAAS,OAAA,CAAQN,CAAqB,CAAA,EAAKM,CAAAA,EAAS,OAAA,CAAQL,CAA4B,CAAA,EAAK,IACtG,CAAA,KAAQ,CACN,OAAO,IACT,CACF,CAGO,SAASO,CAAAA,CAAyB,CAAE,MAAA,CAAAC,CAAO,CAAA,CAAiC,CACjF,OAAI,OAAO,MAAA,CAAW,GAAA,CACb,KAAA,CAGFN,CAAAA,CAAmB,CACxB,MAAA,CAAAM,CAAAA,CACA,SAAA,CAAW,EAAQf,CAAAA,EAAW,CAC9B,MAAA,CAAQgB,GAAAA,CACR,QAAA,CAAU,MAAA,CAAO,QAAA,CAAS,QAAA,CAC1B,OAAA,CAASpB,CAAAA,CACT,QAAA,CAAUe,CAAAA,EACZ,CAAC,CACH,CAOA,eAAsBM,CAAAA,CAAcC,CAAAA,CAAcC,CAAAA,CAAc,CAAE,SAAA,CAAAC,CAAAA,CAAY,KAAM,CAAA,CAAI,EAAC,CAAoB,CAS3G,OAAA,CARiB,MAAM,KAAA,CAAMF,CAAAA,CAAM,CACjC,KAAAC,CAAAA,CACA,WAAA,CAAa,aAAA,CACb,OAAA,CAAS,CAAE,cAAA,CAAgB,kBAAmB,CAAA,CAC9C,SAAA,CAAAC,CAAAA,CACA,MAAA,CAAQ,MACV,CAAC,CAAA,EAEe,MAClB,CCpDA,IAAMC,CAAAA,CAAS,CACb,cAAA,CAAgB,GAAA,CAChB,OAAA,CAAS,GAAA,CACT,IAAA,CAAM,GAAA,CACN,IAAA,CAAM,GAAA,CACN,KAAA,CAAO,GAAA,CACP,SAAA,CAAW,GACb,CAAA,CAGaC,CAAAA,CAAwB,GAExBC,CAAAA,CAAmB,GAAA,CAEnBC,CAAAA,CAAyB,EAAA,CAEzBC,CAAAA,CAAoB,GAAA,CASpBC,CAAAA,CAAqB,kBAAA,CAElC,SAASC,CAAAA,CAASC,CAAAA,CAAeC,CAAAA,CAAqB,CACpD,OAAOD,CAAAA,CAAM,MAAA,CAASC,EAAMD,CAAAA,CAAM,KAAA,CAAM,CAAA,CAAGC,CAAG,CAAA,CAAID,CACpD,CAGO,SAASE,CAAAA,CAAaC,CAAAA,CAA2B,CACtD,IAAIb,CAAAA,CAAOa,CAAAA,CAEX,GAAI,CACE,uBAAuB,IAAA,CAAKA,CAAS,CAAA,GACvCb,CAAAA,CAAO,IAAI,GAAA,CAAIa,CAAS,CAAA,CAAE,QAAA,EAE9B,CAAA,KAAQ,CAER,CAEA,OAAOJ,CAAAA,CAAST,CAAAA,CAAK,KAAA,CAAM,MAAM,CAAA,CAAE,CAAC,CAAA,EAAK,EAAA,CAAIG,CAAAA,CAAO,IAAI,CAC1D,CAaO,SAASW,CAAAA,CAAcC,CAAAA,CAA8B,CAC1D,GAAIA,CAAAA,YAAiB,KAAA,CACnB,OAAO,CACL,IAAA,CAAMA,CAAAA,CAAM,IAAA,EAAQ,OAAA,CACpB,OAAA,CAAS,OAAOA,CAAAA,CAAM,OAAA,EAAY,QAAA,CAAWA,CAAAA,CAAM,OAAA,CAAU,EAAA,CAC7D,KAAA,CAAO,OAAOA,CAAAA,CAAM,OAAU,QAAA,CAAWA,CAAAA,CAAM,KAAA,CAAQ,MACzD,CAAA,CAGF,GAAI,OAAOA,CAAAA,EAAU,QAAA,CACnB,OAAO,CAAE,IAAA,CAAM,OAAA,CAAS,OAAA,CAASA,CAAM,CAAA,CAGzC,GAAIA,CAAAA,EAAU,IAAA,CACZ,OAAO,CAAE,IAAA,CAAM,OAAA,CAAS,OAAA,CAAS,CAAA,kBAAA,EAAqB,MAAA,CAAOA,CAAK,CAAC,CAAA,CAAG,CAAA,CAGxE,GAAI,OAAOA,CAAAA,EAAU,QAAA,CAAU,CAC7B,IAAMC,CAAAA,CAAmBD,CAAAA,CAA+C,WAAA,EAAa,IAAA,CAErF,OAAO,CACL,IAAA,CAAM,OAAA,CACN,OAAA,CAAS,CAAA,kBAAA,EAAqB,OAAOC,CAAAA,EAAoB,QAAA,EAAYA,EAAkBA,CAAAA,CAAkB,QAAQ,CAAA,CACnH,CACF,CAEA,OAAO,CAAE,IAAA,CAAM,OAAA,CAAS,OAAA,CAAS,CAAA,kBAAA,EAAqB,OAAOD,CAAK,CAAA,CAAG,CACvE,CAEA,IAAME,CAAAA,CAAiB,CACrB,gFAAA,CAEA,oBAAA,CACA,sCAAA,CACA,mCACF,CAAA,CAEMC,CAAAA,CAAgB,yDAAA,CAEhBC,CAAAA,CAAgB,yCAAA,CAGf,SAASC,CAAAA,CAAYC,CAAAA,CAAyB,CACnD,OAAOA,EAAQ,OAAA,CAAQF,CAAAA,CAAe,SAAS,CACjD,CAGO,SAASG,CAAAA,CAAaC,CAAAA,CAAuBC,CAAAA,CAA6B,CAS/E,OARID,CAAAA,CAAQ,IAAA,GAAS,YAAA,EAIjBN,CAAAA,CAAe,IAAA,CAAMQ,CAAAA,EAAYA,CAAAA,CAAQ,IAAA,CAAKF,CAAAA,CAAQ,OAAO,CAAC,CAAA,EAI9DC,CAAAA,EAAaN,CAAAA,CAAc,IAAA,CAAKM,CAAS,CAAA,CACpC,IAAA,CAGF,CAAA,EAAQD,CAAAA,CAAQ,KAAA,EAASL,EAAc,IAAA,CAAKK,CAAAA,CAAQ,KAAK,CAAA,CAClE,CAaO,SAASG,CAAAA,CAAiBX,CAAAA,CAAgBY,CAAAA,CAAsD,CACrG,IAAMJ,CAAAA,CAAUT,CAAAA,CAAcC,CAAK,CAAA,CAEnC,GAAIO,EAAaC,CAAAA,CAASI,CAAAA,CAAQ,SAAS,CAAA,CACzC,OAAO,IAAA,CAGT,IAAMC,CAAAA,CAAqB,CACzB,MAAA,CAAQD,CAAAA,CAAQ,MAAA,CAChB,IAAA,CAAMlB,CAAAA,CAASc,CAAAA,CAAQ,IAAA,CAAMpB,EAAO,IAAI,CAAA,CACxC,OAAA,CAASM,CAAAA,CAASW,CAAAA,CAAYG,CAAAA,CAAQ,OAAO,CAAA,CAAGpB,CAAAA,CAAO,OAAO,CAAA,CAC9D,UAAA,CAAA,CAAawB,CAAAA,CAAQ,GAAA,EAAO,IAAI,IAAA,EAAQ,aAC1C,CAAA,CAEA,OAAIJ,CAAAA,CAAQ,KAAA,GACVK,CAAAA,CAAM,KAAA,CAAQnB,CAAAA,CAASc,CAAAA,CAAQ,KAAA,CAAOpB,CAAAA,CAAO,KAAK,CAAA,CAAA,CAGhDwB,CAAAA,CAAQ,cAAA,GACVC,CAAAA,CAAM,eAAiBnB,CAAAA,CAASkB,CAAAA,CAAQ,cAAA,CAAgBxB,CAAAA,CAAO,cAAc,CAAA,CAAA,CAG3EwB,CAAAA,CAAQ,IAAA,GACVC,CAAAA,CAAM,IAAA,CAAOhB,CAAAA,CAAae,CAAAA,CAAQ,IAAI,CAAA,CAAA,CAGpCA,CAAAA,CAAQ,SAAA,EAAanB,EAAmB,IAAA,CAAKmB,CAAAA,CAAQ,SAAS,CAAA,GAChEC,CAAAA,CAAM,SAAA,CAAYD,CAAAA,CAAQ,SAAA,CAAA,CAGrBC,CACT,CAGO,SAASC,CAAAA,CAASd,CAAAA,CAAgE,CACvF,OAAO,CAAA,EAAGA,EAAM,IAAI;AAAA,EAAKA,EAAM,OAAO;AAAA,EAAKA,CAAAA,CAAM,OAAS,EAAE,CAAA,CAC9D,CAEA,IAAMe,EAAAA,CAAU,IAAI,WAAA,CAEpB,SAASC,EAAWrB,CAAAA,CAAuB,CACzC,OAAOoB,EAAAA,CAAQ,MAAA,CAAOpB,CAAK,CAAA,CAAE,MAC/B,CAMO,SAASsB,EAAAA,CACdC,CAAAA,CACAC,EACAC,CAAAA,CAAW9B,CAAAA,CAC6B,CAExC,IAAI+B,CAAAA,CAAOL,EAAW,IAAA,CAAK,SAAA,CAAU,CAAE,GAAA,CAAAE,CAAAA,CAAK,MAAA,CAAQ,EAAG,CAA6B,CAAC,CAAA,CAC/EI,CAAAA,CAAwB,EAAC,CAE/B,IAAA,IAAWtB,CAAAA,IAASmB,CAAAA,CAAM,KAAA,CAAM,CAAA,CAAG9B,CAAqB,CAAA,CAAG,CACzD,IAAMkC,CAAAA,CAAYP,CAAAA,CAAW,KAAK,SAAA,CAAUhB,CAAK,CAAC,CAAA,EAAKsB,CAAAA,CAAO,OAAS,CAAA,CAAI,CAAA,CAAA,CAE3E,GAAID,CAAAA,CAAOE,CAAAA,CAAYH,EACrB,MAGFC,CAAAA,EAAQE,CAAAA,CACRD,CAAAA,CAAO,IAAA,CAAKtB,CAAK,EACnB,CAEA,OAAIsB,EAAO,MAAA,GAAW,CAAA,CACb,KAGF,CAAE,IAAA,CAAM,IAAA,CAAK,SAAA,CAAU,CAAE,GAAA,CAAAJ,EAAK,MAAA,CAAAI,CAAO,CAA6B,CAAA,CAAG,KAAA,CAAOA,EAAO,MAAO,CACnG,CAyBO,SAASE,EAAAA,CAAoB,CAClC,IAAAN,CAAAA,CACA,IAAA,CAAAO,EACA,OAAA,CAAAC,CAAAA,CACA,IAAAC,CAAAA,CAAM,IAAM,IAAI,IAAA,CAChB,QAAA,CAAAC,EAAW,CAACC,CAAAA,CAAUC,IAAO,UAAA,CAAWD,CAAAA,CAAUC,CAAE,CAAA,CACpD,UAAA,CAAAC,CAAAA,CAAcC,CAAAA,EAAU,YAAA,CAAaA,CAAsC,CAC7E,CAAA,CAAwC,CACtC,IAAMb,CAAAA,CAAuB,GACvBc,CAAAA,CAAO,IAAI,GAAA,CACbC,CAAAA,CAAW,CAAA,CACXC,CAAAA,CAA2B,KAC3BH,CAAAA,CAAiB,IAAA,CACjBI,EAAU,KAAA,CAEd,SAASC,GAAiB,CACpBL,CAAAA,GAAU,IAAA,EAAQb,CAAAA,CAAM,MAAA,CAAS,CAAA,EAAK,CAACiB,CAAAA,GACzCJ,CAAAA,CAAQJ,EAAS,IAAM,CACrBI,EAAQ,IAAA,CACRM,CAAAA,GACF,CAAA,CAAG9C,CAAiB,CAAA,EAExB,CAEA,SAAS+C,CAAAA,CAASC,EAA6B,CAC7C,IAAMC,EAAOxB,EAAAA,CAAgBC,CAAAA,CAAKC,CAAK,CAAA,CAEvC,OAAKsB,CAAAA,EAOLtB,EAAM,MAAA,CAAO,CAAA,CAAGsB,EAAK,KAAK,CAAA,CAC1BhB,EAAKgB,CAAAA,CAAK,IAAA,CAAM,CAAE,SAAA,CAAAD,CAAU,CAAC,EAC1B,IAAA,CAAME,CAAAA,EAAW,EAEZA,CAAAA,GAAW,GAAA,EAAOA,IAAW,GAAA,EAAOA,CAAAA,GAAW,GAAA,IACjDN,CAAAA,CAAU,IAAA,CACVjB,CAAAA,CAAM,OAAS,CAAA,EAEnB,CAAC,EACA,KAAA,CAAM,IAAM,CAEb,CAAC,CAAA,CAEIA,EAAM,MAAA,CAAS,CAAA,GAlBpBA,EAAM,KAAA,EAAM,CAELA,EAAM,MAAA,CAAS,CAAA,CAiB1B,CAEA,SAASmB,CAAAA,CAAM,CAAE,SAAA,CAAAE,CAAAA,CAAY,KAAM,EAA6B,EAAC,CAAS,CACxE,GAAI,CACF,GAAIJ,CAAAA,CACF,OAGEJ,CAAAA,GAAU,IAAA,EAAQQ,CAAAA,GACpBT,CAAAA,CAAWC,CAAK,CAAA,CAChBA,CAAAA,CAAQ,MAKNb,CAAAA,CAAM,MAAA,CAAS,GACjBoB,CAAAA,CAASC,CAAS,CAAA,CAGpBH,CAAAA,GACF,CAAA,KAAQ,CAER,CACF,CAEA,OAAO,CACL,MAAA,CAAOrC,EAAOY,CAAAA,CAAS,CACrB,GAAI,CACF,GAAIwB,GAAWF,CAAAA,EAAY3C,CAAAA,CACzB,OAGF,IAAMsB,CAAAA,CAAQF,EAAiBX,CAAAA,CAAO,CACpC,GAAGY,CAAAA,CACH,GAAA,CAAKe,CAAAA,GACL,IAAA,CAAMD,CAAAA,KACN,SAAA,CAAAS,CACF,CAAC,CAAA,CAED,GAAI,CAACtB,CAAAA,CACH,OAGF,IAAM8B,EAAM7B,CAAAA,CAASD,CAAK,EAE1B,GAAIoB,CAAAA,CAAK,IAAIU,CAAG,CAAA,CACd,OAGFV,CAAAA,CAAK,GAAA,CAAIU,CAAG,EACZT,CAAAA,EAAY,CAAA,CACZf,EAAM,IAAA,CAAKN,CAAK,EAChBwB,CAAAA,GACF,MAAQ,CAER,CACF,EACA,YAAA,CAAaO,CAAAA,CAAI,CACfT,CAAAA,CAAYS,EACd,EACA,KAAA,CAAAN,CAAAA,CACA,OAAA,CAAS,IAAMnB,CAAAA,CACf,OAAA,EAAU,CACJa,CAAAA,GAAU,IAAA,GACZD,EAAWC,CAAK,CAAA,CAChBA,EAAQ,IAAA,CAAA,CAGVI,CAAAA,CAAU,IAAA,CACVjB,CAAAA,CAAM,MAAA,CAAS,EACjB,CACF,CACF,CAGO,IAAM0B,EAAAA,CAA8B,MAAO3D,EAAM,CAAE,SAAA,CAAAsD,CAAU,CAAA,GAAM,CACxE,IAAMM,EAAMC,CAAAA,CAAa,YAAA,CAKzB,GAAIP,CAAAA,EAAa,CAACzE,GAAW,EAAK,OAAO,SAAA,CAAc,GAAA,EAAe,OAAO,SAAA,CAAU,YAAe,UAAA,CACpG,GAAI,CAEF,GAAI,SAAA,CAAU,WAAW+E,CAAAA,CAAK,IAAI,IAAA,CAAK,CAAC5D,CAAI,CAAA,CAAG,CAAE,IAAA,CAAM,YAAa,CAAC,CAAC,CAAA,CACpE,OAAO,IAEX,CAAA,KAAQ,CAER,CAGF,OAAOF,CAAAA,CAAc8D,EAAK5D,CAAAA,CAAM,CAAE,UAAWsD,CAAU,CAAC,CAC1D,CAAA,CAEIQ,CAAAA,CAAkC,IAAA,CAG/B,SAASC,EAAAA,CACdjD,CAAAA,CACA,CAAE,MAAA,CAAAkD,CAAAA,CAAS,SAAU,cAAA,CAAAC,CAAe,EAA6D,EAAC,CAC5F,CACNH,CAAAA,EAAW,MAAA,CAAOhD,EAAO,CAAE,MAAA,CAAAkD,EAAQ,cAAA,CAAAC,CAAe,CAAC,EACrD,CAGO,SAASC,EAAAA,CAA2BjB,CAAAA,CAAgC,CACzEa,GAAW,YAAA,CAAab,CAAS,EACnC,CAMO,SAASkB,GAAqB,CAAE,MAAA,CAAAvE,CAAO,CAAA,CAAoC,CAChF,GAAI,OAAO,MAAA,CAAW,GAAA,EAAekE,EACnC,OAAO,IAAG,GAGZ,GAAI,CAACnE,CAAAA,CAAyB,CAAE,MAAA,CAAAC,CAAO,CAAC,CAAA,CACtC,OAAO,IAAG,CAAA,CAAA,CAGZ,IAAMhB,EAAUC,CAAAA,EAAW,CAErBuF,EAAW9B,EAAAA,CAAoB,CACnC,IAAK,CACH,QAAA,CAAU1D,EAAU,SAAA,CAAY,KAAA,CAChC,QAASH,CAAAA,CACT,SAAA,CAAW+B,CAAAA,CAAS,SAAA,CAAU,SAAA,CAAWN,CAAAA,CAAO,SAAS,CAC3D,CAAA,CACA,KAAMyD,EAAAA,CACN,OAAA,CAAS,IAAM,MAAA,CAAO,QAAA,CAAS,QACjC,CAAC,CAAA,CAED,SAASU,EAAQC,CAAAA,CAAyB,CACxCF,EAAS,MAAA,CAAOE,CAAAA,CAAM,OAASA,CAAAA,CAAM,OAAA,CAAS,CAAE,MAAA,CAAQ,QAAA,CAAU,SAAA,CAAWA,EAAM,QAAS,CAAC,EAC/F,CAEA,SAASC,EAAqBD,CAAAA,CAAoC,CAChEF,EAAS,MAAA,CAAOE,CAAAA,CAAM,OAAQ,CAAE,MAAA,CAAQ,oBAAqB,CAAC,EAChE,CAEA,SAASE,CAAAA,EAAmB,CAC1BJ,CAAAA,CAAS,KAAA,CAAM,CAAE,UAAW,IAAK,CAAC,EACpC,CAEA,OAAA,MAAA,CAAO,iBAAiB,OAAA,CAASC,CAAO,CAAA,CACxC,MAAA,CAAO,gBAAA,CAAiB,oBAAA,CAAsBE,CAAoB,CAAA,CAClE,MAAA,CAAO,iBAAiB,UAAA,CAAYC,CAAU,EAC9CV,CAAAA,CAAYM,CAAAA,CAEL,IAAM,CACX,MAAA,CAAO,mBAAA,CAAoB,QAASC,CAAO,CAAA,CAC3C,OAAO,mBAAA,CAAoB,oBAAA,CAAsBE,CAAoB,CAAA,CACrE,MAAA,CAAO,mBAAA,CAAoB,UAAA,CAAYC,CAAU,CAAA,CACjDJ,EAAS,KAAA,CAAM,CAAE,UAAW,IAAK,CAAC,EAClCA,CAAAA,CAAS,OAAA,EAAQ,CAEbN,CAAAA,GAAcM,CAAAA,GAChBN,CAAAA,CAAY,MAEhB,CACF,CC/cO,SAASW,EAAAA,CAAgBC,CAAAA,CAAyC,CACvE,OAAOA,CAAAA,CAAY,KAAA,GAAU,cAAA,CAAiB,CAAA,aAAA,EAAgBA,CAAAA,CAAY,SAAS,CAAA,CAAA,CAAKA,CAAAA,CAAY,KACtG,CAcO,SAASC,GAA0BpC,CAAAA,CAA6C,CACrF,IAAMqC,CAAAA,CAAU,IAAI,GAAA,CACdC,EAAY,IAAI,GAAA,CAEtB,OAAO,CACL,KAAA,CAAMH,EAAa,CAAE,WAAA,CAAAI,CAAY,CAAA,CAAI,GAAI,CACvC,IAAMrB,EAAMgB,EAAAA,CAAgBC,CAAW,EAEvC,GAAIE,CAAAA,CAAQ,GAAA,CAAInB,CAAG,CAAA,EAAKoB,CAAAA,CAAU,IAAIpB,CAAG,CAAA,CACvC,OAGFmB,CAAAA,CAAQ,GAAA,CAAInB,CAAG,CAAA,CAEf,IAAMsB,CAAAA,CAAUvB,CAAAA,EAAgC,CAC9CoB,CAAAA,CAAQ,OAAOnB,CAAG,CAAA,CAEdD,IAAW,IAAA,EAAQA,CAAAA,EAAU,KAAOA,CAAAA,CAAS,GAAA,GAC/CqB,CAAAA,CAAU,GAAA,CAAIpB,CAAG,CAAA,CACjBqB,KAAc,EAElB,CAAA,CAEA,GAAI,CACFvC,CAAAA,CAAK,KAAK,SAAA,CAAUmC,CAAW,CAAC,CAAA,CAAE,IAAA,CAAKK,CAAAA,CAAQ,IAAMA,CAAAA,CAAO,IAAI,CAAC,EACnE,CAAA,KAAQ,CACNA,CAAAA,CAAO,IAAI,EACb,CACF,CACF,CACF,CAEA,IAAIC,CAAAA,CAAsC,KAGnC,SAASC,EAAAA,CAAiBP,EAAuC,CAClEA,CAAAA,CAAY,KAAA,GAAU,cAAA,EAAkB,CAACnE,CAAAA,CAAmB,KAAKmE,CAAAA,CAAY,SAAS,GAI1FM,CAAAA,EAAS,KAAA,CAAMN,CAAW,EAC5B,CAGO,IAAMQ,CAAAA,CAA6B,iCAAA,CAE1C,SAASC,GAAgB1B,CAAAA,CAAsB,CAC7C,GAAI,CACF,OAAO,eAAe,OAAA,CAAQA,CAAG,IAAM,GACzC,CAAA,KAAQ,CACN,OAAO,MACT,CACF,CAEA,SAAS2B,GAAiB3B,CAAAA,CAAmB,CAC3C,GAAI,CACF,cAAA,CAAe,OAAA,CAAQA,EAAK,GAAG,EACjC,MAAQ,CAER,CACF,CAOO,SAAS4B,EAAAA,CAAqB,CAAE,MAAA,CAAAzF,CAAO,CAAA,CAAoC,CAChF,GAAI,CAACD,EAAyB,CAAE,MAAA,CAAAC,CAAO,CAAC,CAAA,CACtC,OAAO,IAAG,CAAA,CAAA,CAGZ,IAAM0F,EAAUX,EAAAA,CAA2B3E,CAAAA,EACzCF,EAAc+D,CAAAA,CAAa,aAAA,CAAe7D,EAAM,CAAE,SAAA,CAAW,IAAK,CAAC,CACrE,CAAA,CACMpB,EAAUC,CAAAA,EAAW,CAE3B,OAAAmG,CAAAA,CAAUM,CAAAA,CAEN1G,GAAW,CAACuG,EAAAA,CAAgBD,CAA0B,CAAA,EACxDI,CAAAA,CAAQ,KAAA,CACN,CAAE,UAAA,CAAY1G,CAAAA,CAAQ,QAAS,KAAA,CAAO,oBAAA,CAAsB,GAAIA,CAAAA,CAAQ,QAAS,CAAA,CACjF,CAAE,WAAA,CAAa,IAAMwG,GAAiBF,CAA0B,CAAE,CACpE,CAAA,CAGK,IAAM,CACPF,CAAAA,GAAYM,CAAAA,GACdN,CAAAA,CAAU,IAAA,EAEd,CACF","file":"chunk-QW6H7OZ6.js","sourcesContent":["'use client';\n\nimport { useEffect, useState } from 'react';\nimport { getDesktop } from './desktop';\n\nexport interface StudioVersion {\n current: string;\n latest: string;\n isCurrent: boolean;\n /** Applies the newer version (the desktop app restarts into it); undefined when there is nothing to apply. */\n upgrade?: () => void;\n}\n\n// `@flexkit/studio`'s own version, inlined at build time; a build without the\n// define (tests, tooling) shows a placeholder.\nexport const STUDIO_VERSION = typeof __STUDIO_VERSION__ === 'string' ? __STUDIO_VERSION__ : '0.0.0';\nconst WEB_VERSION: StudioVersion = { current: STUDIO_VERSION, latest: STUDIO_VERSION, isCurrent: true };\n\n/**\n * The Studio version shown in the app bar. The web Studio is always current\n * (the hosted Studio deploys with the packages); the desktop app reports its\n * own version and the update it has downloaded, if any.\n */\nexport function useStudioVersion(): StudioVersion {\n const desktop = getDesktop();\n const [downloaded, setDownloaded] = useState<string | null>(null);\n\n useEffect(() => {\n if (!desktop) {\n return;\n }\n\n return desktop.onUpdateDownloaded((update) => {\n setDownloaded(update.version);\n });\n }, [desktop]);\n\n if (!desktop) {\n return WEB_VERSION;\n }\n\n if (downloaded === null) {\n return { current: desktop.version, latest: desktop.version, isCurrent: true };\n }\n\n return { current: desktop.version, latest: downloaded, isCurrent: false, upgrade: () => desktop.installUpdate() };\n}\n","import { getDesktop } from './desktop';\nimport { flexkitDomain } from './domains';\nimport { getLocalStorage } from './local-storage';\nimport { STUDIO_VERSION } from './use-studio-version';\n\n/**\n * The on/off decision and the transport shared by the Studio's error reports\n * (core/error/error-reporter.ts) and product events\n * (core/analytics/product-events.ts).\n */\n\n/** Turns error reports and product events on (`on`) or off (`off`) in this browser, whatever the environment. */\nexport const TELEMETRY_STORAGE_KEY = 'flexkit:telemetry';\n/** The key error reporting shipped with; still honoured. */\nexport const LEGACY_TELEMETRY_STORAGE_KEY = 'flexkit:error-reporting';\n\nexport interface TelemetryEnvironment {\n /** The Studio lists the signed-in user's projects (hosted Studio, desktop app). */\n hosted: boolean;\n isDesktop: boolean;\n domain: string;\n hostname: string;\n version: string;\n /** The local storage setting in this browser, if any. */\n override: string | null;\n}\n\nconst LOCAL_HOSTNAME = /^(localhost|127\\.0\\.0\\.1|\\[::1\\]|0\\.0\\.0\\.0)$|\\.(localhost|test|local)$/i;\n\n/**\n * On for the hosted Studio and the desktop app against the production\n * backend, and off in development: a local backend (`flexkit.test`), a local\n * host, or a build without a version. The local storage setting forces it\n * `on` or `off`.\n */\nexport function isTelemetryEnabled(env: TelemetryEnvironment): boolean {\n if (env.override === 'on') {\n return true;\n }\n\n if (env.override === 'off') {\n return false;\n }\n\n if (!env.hosted || env.domain !== 'flexkit.io' || env.version === '0.0.0') {\n return false;\n }\n\n return env.isDesktop || !LOCAL_HOSTNAME.test(env.hostname);\n}\n\nfunction readOverride(): string | null {\n try {\n const storage = getLocalStorage();\n\n return storage?.getItem(TELEMETRY_STORAGE_KEY) ?? storage?.getItem(LEGACY_TELEMETRY_STORAGE_KEY) ?? null;\n } catch {\n return null;\n }\n}\n\n/** Whether this Studio sends error reports and product events to Flexkit. */\nexport function isStudioTelemetryEnabled({ hosted }: { hosted: boolean }): boolean {\n if (typeof window === 'undefined') {\n return false;\n }\n\n return isTelemetryEnabled({\n hosted,\n isDesktop: Boolean(getDesktop()),\n domain: flexkitDomain,\n hostname: window.location.hostname,\n version: STUDIO_VERSION,\n override: readOverride(),\n });\n}\n\n/**\n * POSTs JSON to a user-level backend route through the Studio's server proxy,\n * which adds the session. `keepalive` lets the request outlive the page.\n * Returns the response status.\n */\nexport async function postToUserApi(path: string, body: string, { keepalive = false } = {}): Promise<number> {\n const response = await fetch(path, {\n body,\n credentials: 'same-origin',\n headers: { 'Content-Type': 'application/json' },\n keepalive,\n method: 'POST',\n });\n\n return response.status;\n}\n","import { userApiPaths } from '../api-paths';\nimport { getDesktop } from '../desktop';\nimport { STUDIO_VERSION } from '../use-studio-version';\nimport { isStudioTelemetryEnabled, postToUserApi } from '../telemetry';\n\n/**\n * Reports unexpected Studio errors (uncaught errors, unhandled rejections and\n * errors caught by the error boundaries) to Flexkit through the Studio's own\n * BFF (`/api/flexkit/-/client-errors`), which forwards the session so the\n * report is attributed to the signed-in user.\n *\n * Reports carry the error, the Studio path (no query string or hash) and the\n * current project id; never request bodies, form values or record data.\n */\n\nexport type ClientErrorSource = 'window' | 'unhandledrejection' | 'react' | 'manual';\n\nexport interface ClientError {\n source: ClientErrorSource;\n name: string;\n message: string;\n stack?: string;\n componentStack?: string;\n path?: string;\n projectId?: string;\n occurredAt: string;\n}\n\nexport interface ClientErrorApp {\n platform: 'web' | 'desktop';\n version: string;\n userAgent?: string;\n}\n\nexport interface ClientErrorReport {\n app: ClientErrorApp;\n errors: ClientError[];\n}\n\n/** Field limits of the backend schema. */\nconst LIMITS = {\n componentStack: 4_000,\n message: 2_000,\n name: 200,\n path: 500,\n stack: 8_000,\n userAgent: 500,\n} as const;\n\n/** The backend accepts 1 to 10 errors per report. */\nexport const MAX_ERRORS_PER_REPORT = 10;\n/** The backend refuses bodies over 64 KB; `keepalive` requests share a 64 KB budget too. */\nexport const MAX_REPORT_BYTES = 60_000;\n/** Reports kept per page session; anything after that is dropped. */\nexport const MAX_ERRORS_PER_SESSION = 50;\n/** At most one report is sent per interval; errors in between are batched. */\nexport const FLUSH_INTERVAL_MS = 5_000;\n\n/** Kept for callers and tests that name the gate after error reporting. */\nexport {\n isTelemetryEnabled as isErrorReportingEnabled,\n LEGACY_TELEMETRY_STORAGE_KEY as ERROR_REPORTING_STORAGE_KEY,\n type TelemetryEnvironment as ErrorReportingEnvironment,\n} from '../telemetry';\n\nexport const PROJECT_ID_PATTERN = /^[a-z0-9]{1,64}$/;\n\nfunction truncate(value: string, max: number): string {\n return value.length > max ? value.slice(0, max) : value;\n}\n\n/** The pathname of a path or URL, without query string or hash. */\nexport function toReportPath(pathOrUrl: string): string {\n let path = pathOrUrl;\n\n try {\n if (/^[a-z][a-z0-9+.-]*:/i.test(pathOrUrl)) {\n path = new URL(pathOrUrl).pathname;\n }\n } catch {\n // Not a URL; strip by hand below.\n }\n\n return truncate(path.split(/[?#]/)[0] ?? '', LIMITS.path);\n}\n\nexport interface ErrorDetails {\n name: string;\n message: string;\n stack?: string;\n}\n\n/**\n * Name, message and stack of anything thrown. A non-Error value (a rejected\n * promise with a plain object) is described by its type only, so record data\n * someone rejected with never leaves the browser.\n */\nexport function describeError(error: unknown): ErrorDetails {\n if (error instanceof Error) {\n return {\n name: error.name || 'Error',\n message: typeof error.message === 'string' ? error.message : '',\n stack: typeof error.stack === 'string' ? error.stack : undefined,\n };\n }\n\n if (typeof error === 'string') {\n return { name: 'Error', message: error };\n }\n\n if (error === null || error === undefined) {\n return { name: 'Error', message: `Non-Error thrown: ${String(error)}` };\n }\n\n if (typeof error === 'object') {\n const constructorName = (error as { constructor?: { name?: unknown } }).constructor?.name;\n\n return {\n name: 'Error',\n message: `Non-Error thrown: ${typeof constructorName === 'string' && constructorName ? constructorName : 'object'}`,\n };\n }\n\n return { name: 'Error', message: `Non-Error thrown: ${typeof error}` };\n}\n\nconst NOISE_MESSAGES = [\n /ResizeObserver loop (limit exceeded|completed with undelivered notifications)/i,\n // Cross-origin script errors carry nothing to act on.\n /^Script error\\.?$/i,\n /The (operation|user) (was )?aborted/i,\n /signal is aborted without reason/i,\n];\n\nconst EXTENSION_URL = /\\b(chrome|moz|safari(-web)?|ms-browser)-extension:\\/\\//i;\n\nconst EMAIL_ADDRESS = /[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,}/gi;\n\n/** Masks email addresses an error message may quote from a record or form. */\nexport function maskMessage(message: string): string {\n return message.replace(EMAIL_ADDRESS, '<email>');\n}\n\n/** Errors that are not Studio bugs: browser quirks, aborted requests, browser extensions. */\nexport function isNoiseError(details: ErrorDetails, sourceUrl?: string): boolean {\n if (details.name === 'AbortError') {\n return true;\n }\n\n if (NOISE_MESSAGES.some((pattern) => pattern.test(details.message))) {\n return true;\n }\n\n if (sourceUrl && EXTENSION_URL.test(sourceUrl)) {\n return true;\n }\n\n return Boolean(details.stack && EXTENSION_URL.test(details.stack));\n}\n\nexport interface BuildClientErrorOptions {\n source: ClientErrorSource;\n componentStack?: string;\n path?: string;\n projectId?: string | null;\n /** The script the error came from (`ErrorEvent.filename`), checked for browser extensions. */\n sourceUrl?: string;\n now?: Date;\n}\n\n/** The report entry for an error, or null when it is noise. */\nexport function buildClientError(error: unknown, options: BuildClientErrorOptions): ClientError | null {\n const details = describeError(error);\n\n if (isNoiseError(details, options.sourceUrl)) {\n return null;\n }\n\n const entry: ClientError = {\n source: options.source,\n name: truncate(details.name, LIMITS.name),\n message: truncate(maskMessage(details.message), LIMITS.message),\n occurredAt: (options.now ?? new Date()).toISOString(),\n };\n\n if (details.stack) {\n entry.stack = truncate(details.stack, LIMITS.stack);\n }\n\n if (options.componentStack) {\n entry.componentStack = truncate(options.componentStack, LIMITS.componentStack);\n }\n\n if (options.path) {\n entry.path = toReportPath(options.path);\n }\n\n if (options.projectId && PROJECT_ID_PATTERN.test(options.projectId)) {\n entry.projectId = options.projectId;\n }\n\n return entry;\n}\n\n/** Identity of an error within a page session: the same message and stack are reported once. */\nexport function errorKey(error: Pick<ClientError, 'message' | 'name' | 'stack'>): string {\n return `${error.name}\\n${error.message}\\n${error.stack ?? ''}`;\n}\n\nconst encoder = new TextEncoder();\n\nfunction byteLength(value: string): number {\n return encoder.encode(value).length;\n}\n\n/**\n * Takes the errors that fit one report (at most 10 and `maxBytes` of JSON)\n * off the front of the queue. Returns the request body and how many errors it holds.\n */\nexport function buildReportBody(\n app: ClientErrorApp,\n queue: readonly ClientError[],\n maxBytes = MAX_REPORT_BYTES\n): { body: string; count: number } | null {\n // The envelope plus each error once, joined by commas.\n let size = byteLength(JSON.stringify({ app, errors: [] } satisfies ClientErrorReport));\n const errors: ClientError[] = [];\n\n for (const error of queue.slice(0, MAX_ERRORS_PER_REPORT)) {\n const errorSize = byteLength(JSON.stringify(error)) + (errors.length ? 1 : 0);\n\n if (size + errorSize > maxBytes) {\n break;\n }\n\n size += errorSize;\n errors.push(error);\n }\n\n if (errors.length === 0) {\n return null;\n }\n\n return { body: JSON.stringify({ app, errors } satisfies ClientErrorReport), count: errors.length };\n}\n\nexport type SendReport = (body: string, options: { unloading: boolean }) => Promise<number | null>;\n\nexport interface ErrorReporterOptions {\n app: ClientErrorApp;\n send: SendReport;\n /** The current Studio path; only its pathname is sent. */\n getPath?: () => string | undefined;\n now?: () => Date;\n setTimer?: (callback: () => void, ms: number) => unknown;\n clearTimer?: (timer: unknown) => void;\n}\n\nexport interface ErrorReporter {\n report: (error: unknown, options: Omit<BuildClientErrorOptions, 'path' | 'projectId' | 'now'>) => void;\n setProjectId: (projectId: string | null) => void;\n /** Sends the next report now; `unloading` uses a beacon or keepalive request that outlives the page. */\n flush: (options?: { unloading?: boolean }) => void;\n /** Errors waiting to be sent (tests). */\n pending: () => readonly ClientError[];\n dispose: () => void;\n}\n\n/** The queue, dedupe, cap and batching; the transport and the clock are injected. */\nexport function createErrorReporter({\n app,\n send,\n getPath,\n now = () => new Date(),\n setTimer = (callback, ms) => setTimeout(callback, ms),\n clearTimer = (timer) => clearTimeout(timer as ReturnType<typeof setTimeout>),\n}: ErrorReporterOptions): ErrorReporter {\n const queue: ClientError[] = [];\n const seen = new Set<string>();\n let accepted = 0;\n let projectId: string | null = null;\n let timer: unknown = null;\n let stopped = false;\n\n function schedule(): void {\n if (timer === null && queue.length > 0 && !stopped) {\n timer = setTimer(() => {\n timer = null;\n flush();\n }, FLUSH_INTERVAL_MS);\n }\n }\n\n function sendNext(unloading: boolean): boolean {\n const next = buildReportBody(app, queue);\n\n if (!next) {\n // An error that cannot fit a report on its own; drop it.\n queue.shift();\n\n return queue.length > 0;\n }\n\n queue.splice(0, next.count);\n send(next.body, { unloading })\n .then((status) => {\n // Rate limited or not allowed: stop for this page session rather than retry.\n if (status === 401 || status === 403 || status === 429) {\n stopped = true;\n queue.length = 0;\n }\n })\n .catch(() => {\n // Never report the reporter's own failures.\n });\n\n return queue.length > 0;\n }\n\n function flush({ unloading = false }: { unloading?: boolean } = {}): void {\n try {\n if (stopped) {\n return;\n }\n\n if (timer !== null && unloading) {\n clearTimer(timer);\n timer = null;\n }\n\n // One report per flush, also when the page goes away: beacons and\n // keepalive requests share a 64 KB budget, so a second would be refused.\n if (queue.length > 0) {\n sendNext(unloading);\n }\n\n schedule();\n } catch {\n // Error reporting must never break the Studio.\n }\n }\n\n return {\n report(error, options) {\n try {\n if (stopped || accepted >= MAX_ERRORS_PER_SESSION) {\n return;\n }\n\n const entry = buildClientError(error, {\n ...options,\n now: now(),\n path: getPath?.(),\n projectId,\n });\n\n if (!entry) {\n return;\n }\n\n const key = errorKey(entry);\n\n if (seen.has(key)) {\n return;\n }\n\n seen.add(key);\n accepted += 1;\n queue.push(entry);\n schedule();\n } catch {\n // Error reporting must never break the Studio.\n }\n },\n setProjectId(id) {\n projectId = id;\n },\n flush,\n pending: () => queue,\n dispose() {\n if (timer !== null) {\n clearTimer(timer);\n timer = null;\n }\n\n stopped = true;\n queue.length = 0;\n },\n };\n}\n\n/** Sends a report through the BFF; a beacon when the page is going away on the web. */\nexport const sendReportToBff: SendReport = async (body, { unloading }) => {\n const url = userApiPaths.clientErrors;\n\n // A beacon outlives the page. The BFF reads its JSON body like a fetch's\n // and the browser sends the session cookie with it (same origin). The\n // desktop app's BFF only answers script requests, so it uses `keepalive`.\n if (unloading && !getDesktop() && typeof navigator !== 'undefined' && typeof navigator.sendBeacon === 'function') {\n try {\n // text/plain is CORS-safelisted, so no browser refuses the beacon; the body is still JSON.\n if (navigator.sendBeacon(url, new Blob([body], { type: 'text/plain' }))) {\n return null;\n }\n } catch {\n // Fall back to a keepalive fetch.\n }\n }\n\n return postToUserApi(url, body, { keepalive: unloading });\n};\n\nlet installed: ErrorReporter | null = null;\n\n/** Reports an error caught by the Studio (an error boundary, for example). Does nothing when reporting is off. */\nexport function reportStudioError(\n error: unknown,\n { source = 'manual', componentStack }: { source?: ClientErrorSource; componentStack?: string } = {}\n): void {\n installed?.report(error, { source, componentStack });\n}\n\n/** The project the Studio shows, added to reports; null outside a project. */\nexport function setErrorReportingProjectId(projectId: string | null): void {\n installed?.setProjectId(projectId);\n}\n\n/**\n * Starts reporting uncaught errors and unhandled rejections when reporting is\n * enabled for this environment. Returns the function that stops it.\n */\nexport function installErrorReporter({ hosted }: { hosted: boolean }): () => void {\n if (typeof window === 'undefined' || installed) {\n return () => undefined;\n }\n\n if (!isStudioTelemetryEnabled({ hosted })) {\n return () => undefined;\n }\n\n const desktop = getDesktop();\n\n const reporter = createErrorReporter({\n app: {\n platform: desktop ? 'desktop' : 'web',\n version: STUDIO_VERSION,\n userAgent: truncate(navigator.userAgent, LIMITS.userAgent),\n },\n send: sendReportToBff,\n getPath: () => window.location.pathname,\n });\n\n function onError(event: ErrorEvent): void {\n reporter.report(event.error ?? event.message, { source: 'window', sourceUrl: event.filename });\n }\n\n function onUnhandledRejection(event: PromiseRejectionEvent): void {\n reporter.report(event.reason, { source: 'unhandledrejection' });\n }\n\n function onPageHide(): void {\n reporter.flush({ unloading: true });\n }\n\n window.addEventListener('error', onError);\n window.addEventListener('unhandledrejection', onUnhandledRejection);\n window.addEventListener('pagehide', onPageHide);\n installed = reporter;\n\n return () => {\n window.removeEventListener('error', onError);\n window.removeEventListener('unhandledrejection', onUnhandledRejection);\n window.removeEventListener('pagehide', onPageHide);\n reporter.flush({ unloading: true });\n reporter.dispose();\n\n if (installed === reporter) {\n installed = null;\n }\n };\n}\n","import { userApiPaths } from '../api-paths';\nimport { getDesktop } from '../desktop';\nimport { PROJECT_ID_PATTERN } from '../error/error-reporter';\nimport { isStudioTelemetryEnabled, postToUserApi } from '../telemetry';\n\n/**\n * Product events only the Studio can see, sent to Flexkit through the\n * Studio's own server proxy (`/api/flexkit/-/product-events`) with the\n * session: the Graph app opened, the desktop app launched. They follow the\n * Studio's telemetry setting (see core/telemetry.ts) and carry ids, the\n * desktop app version and the OS only.\n */\nexport type StudioProductEvent =\n | { event: 'graph_opened'; projectId: string }\n | { event: 'desktop_app_opened'; appVersion: string; os: 'darwin' | 'linux' | 'win32' };\n\n/** Identity of an event within a page session; the backend also counts each once per day. */\nexport function productEventKey(studioEvent: StudioProductEvent): string {\n return studioEvent.event === 'graph_opened' ? `graph_opened:${studioEvent.projectId}` : studioEvent.event;\n}\n\n/** Sends the event body; resolves with the response status. */\nexport type SendProductEvent = (body: string) => Promise<number>;\n\nexport interface ProductEventTracker {\n track: (studioEvent: StudioProductEvent, options?: { onDelivered?: () => void }) => void;\n}\n\n/**\n * Sends each event once per page session through `send`. An event counts as\n * sent only once the backend accepted it, so one sent while offline or signed\n * out is sent again next time. Never throws.\n */\nexport function createProductEventTracker(send: SendProductEvent): ProductEventTracker {\n const pending = new Set<string>();\n const delivered = new Set<string>();\n\n return {\n track(studioEvent, { onDelivered } = {}) {\n const key = productEventKey(studioEvent);\n\n if (pending.has(key) || delivered.has(key)) {\n return;\n }\n\n pending.add(key);\n\n const settle = (status: number | null): void => {\n pending.delete(key);\n\n if (status !== null && status >= 200 && status < 300) {\n delivered.add(key);\n onDelivered?.();\n }\n };\n\n try {\n send(JSON.stringify(studioEvent)).then(settle, () => settle(null));\n } catch {\n settle(null);\n }\n },\n };\n}\n\nlet tracker: ProductEventTracker | null = null;\n\n/** Records an event when product events are on (see `installProductEvents`); otherwise does nothing. */\nexport function trackStudioEvent(studioEvent: StudioProductEvent): void {\n if (studioEvent.event === 'graph_opened' && !PROJECT_ID_PATTERN.test(studioEvent.projectId)) {\n return;\n }\n\n tracker?.track(studioEvent);\n}\n\n/** Session storage flag: this desktop app launch was recorded (page reloads keep it, a relaunch does not). */\nexport const DESKTOP_LAUNCH_STORAGE_KEY = 'flexkit:desktop-launch-recorded';\n\nfunction readSessionFlag(key: string): boolean {\n try {\n return sessionStorage.getItem(key) === '1';\n } catch {\n return false;\n }\n}\n\nfunction writeSessionFlag(key: string): void {\n try {\n sessionStorage.setItem(key, '1');\n } catch {\n // Without session storage the backend's once-per-day count still applies.\n }\n}\n\n/**\n * Turns product events on for this environment and records the desktop app\n * launch (once per launch, once the user is signed in). Returns the function\n * that turns them off again.\n */\nexport function installProductEvents({ hosted }: { hosted: boolean }): () => void {\n if (!isStudioTelemetryEnabled({ hosted })) {\n return () => undefined;\n }\n\n const current = createProductEventTracker((body) =>\n postToUserApi(userApiPaths.productEvents, body, { keepalive: true })\n );\n const desktop = getDesktop();\n\n tracker = current;\n\n if (desktop && !readSessionFlag(DESKTOP_LAUNCH_STORAGE_KEY)) {\n current.track(\n { appVersion: desktop.version, event: 'desktop_app_opened', os: desktop.platform },\n { onDelivered: () => writeSessionFlag(DESKTOP_LAUNCH_STORAGE_KEY) }\n );\n }\n\n return () => {\n if (tracker === current) {\n tracker = null;\n }\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/core/use-studio-version.ts","../src/core/telemetry.ts","../src/core/error/error-reporter.ts","../src/core/analytics/product-events.ts"],"names":["STUDIO_VERSION","WEB_VERSION","useStudioVersion","desktop","getDesktop","downloaded","setDownloaded","useState","useEffect","update","TELEMETRY_STORAGE_KEY","LEGACY_TELEMETRY_STORAGE_KEY","LOCAL_HOSTNAME","isTelemetryEnabled","env","readOverride","storage","getLocalStorage","isStudioTelemetryEnabled","hosted","flexkitDomain","postToUserApi","path","body","keepalive","LIMITS","MAX_ERRORS_PER_REPORT","MAX_REPORT_BYTES","MAX_ERRORS_PER_SESSION","FLUSH_INTERVAL_MS","PROJECT_ID_PATTERN","truncate","value","max","toReportPath","pathOrUrl","describeError","error","constructorName","NOISE_MESSAGES","EXTENSION_URL","EMAIL_ADDRESS","maskMessage","message","isNoiseError","details","sourceUrl","pattern","buildClientError","options","entry","errorKey","encoder","byteLength","buildReportBody","app","queue","maxBytes","size","errors","errorSize","createErrorReporter","send","getPath","now","setTimer","callback","ms","clearTimer","timer","seen","accepted","projectId","stopped","schedule","flush","sendNext","unloading","next","status","key","id","sendReportToBff","url","userApiPaths","installed","reportStudioError","source","componentStack","setErrorReportingProjectId","installErrorReporter","reporter","onError","event","onUnhandledRejection","onPageHide","productEventKey","studioEvent","createProductEventTracker","pending","delivered","onDelivered","settle","tracker","trackStudioEvent","DESKTOP_LAUNCH_STORAGE_KEY","readSessionFlag","writeSessionFlag","installProductEvents","current"],"mappings":"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","file":"chunk-OM2SSOTB.js","sourcesContent":["'use client';\n\nimport { useEffect, useState } from 'react';\nimport { getDesktop } from './desktop';\n\nexport interface StudioVersion {\n current: string;\n latest: string;\n isCurrent: boolean;\n /** Applies the newer version (the desktop app restarts into it); undefined when there is nothing to apply. */\n upgrade?: () => void;\n}\n\n// `@flexkit/studio`'s own version, inlined at build time; a build without the\n// define (tests, tooling) shows a placeholder.\nexport const STUDIO_VERSION = typeof __STUDIO_VERSION__ === 'string' ? __STUDIO_VERSION__ : '0.0.0';\nconst WEB_VERSION: StudioVersion = { current: STUDIO_VERSION, latest: STUDIO_VERSION, isCurrent: true };\n\n/**\n * The Studio version shown in the app bar. The web Studio is always current\n * (the hosted Studio deploys with the packages); the desktop app reports its\n * own version and the update it has downloaded, if any.\n */\nexport function useStudioVersion(): StudioVersion {\n const desktop = getDesktop();\n const [downloaded, setDownloaded] = useState<string | null>(null);\n\n useEffect(() => {\n if (!desktop) {\n return;\n }\n\n return desktop.onUpdateDownloaded((update) => {\n setDownloaded(update.version);\n });\n }, [desktop]);\n\n if (!desktop) {\n return WEB_VERSION;\n }\n\n if (downloaded === null) {\n return { current: desktop.version, latest: desktop.version, isCurrent: true };\n }\n\n return { current: desktop.version, latest: downloaded, isCurrent: false, upgrade: () => desktop.installUpdate() };\n}\n","import { getDesktop } from './desktop';\nimport { flexkitDomain } from './domains';\nimport { getLocalStorage } from './local-storage';\nimport { STUDIO_VERSION } from './use-studio-version';\n\n/**\n * The on/off decision and the transport shared by the Studio's error reports\n * (core/error/error-reporter.ts) and product events\n * (core/analytics/product-events.ts).\n */\n\n/** Turns error reports and product events on (`on`) or off (`off`) in this browser, whatever the environment. */\nexport const TELEMETRY_STORAGE_KEY = 'flexkit:telemetry';\n/** The key error reporting shipped with; still honoured. */\nexport const LEGACY_TELEMETRY_STORAGE_KEY = 'flexkit:error-reporting';\n\nexport interface TelemetryEnvironment {\n /** The Studio lists the signed-in user's projects (hosted Studio, desktop app). */\n hosted: boolean;\n isDesktop: boolean;\n domain: string;\n hostname: string;\n version: string;\n /** The local storage setting in this browser, if any. */\n override: string | null;\n}\n\nconst LOCAL_HOSTNAME = /^(localhost|127\\.0\\.0\\.1|\\[::1\\]|0\\.0\\.0\\.0)$|\\.(localhost|test|local)$/i;\n\n/**\n * On for the hosted Studio and the desktop app against the production\n * backend, and off in development: a local backend (`flexkit.test`), a local\n * host, or a build without a version. The local storage setting forces it\n * `on` or `off`.\n */\nexport function isTelemetryEnabled(env: TelemetryEnvironment): boolean {\n if (env.override === 'on') {\n return true;\n }\n\n if (env.override === 'off') {\n return false;\n }\n\n if (!env.hosted || env.domain !== 'flexkit.io' || env.version === '0.0.0') {\n return false;\n }\n\n return env.isDesktop || !LOCAL_HOSTNAME.test(env.hostname);\n}\n\nfunction readOverride(): string | null {\n try {\n const storage = getLocalStorage();\n\n return storage?.getItem(TELEMETRY_STORAGE_KEY) ?? storage?.getItem(LEGACY_TELEMETRY_STORAGE_KEY) ?? null;\n } catch {\n return null;\n }\n}\n\n/** Whether this Studio sends error reports and product events to Flexkit. */\nexport function isStudioTelemetryEnabled({ hosted }: { hosted: boolean }): boolean {\n if (typeof window === 'undefined') {\n return false;\n }\n\n return isTelemetryEnabled({\n hosted,\n isDesktop: Boolean(getDesktop()),\n domain: flexkitDomain,\n hostname: window.location.hostname,\n version: STUDIO_VERSION,\n override: readOverride(),\n });\n}\n\n/**\n * POSTs JSON to a user-level backend route through the Studio's server proxy,\n * which adds the session. `keepalive` lets the request outlive the page.\n * Returns the response status.\n */\nexport async function postToUserApi(path: string, body: string, { keepalive = false } = {}): Promise<number> {\n const response = await fetch(path, {\n body,\n credentials: 'same-origin',\n headers: { 'Content-Type': 'application/json' },\n keepalive,\n method: 'POST',\n });\n\n return response.status;\n}\n","import { userApiPaths } from '../api-paths';\nimport { getDesktop } from '../desktop';\nimport { STUDIO_VERSION } from '../use-studio-version';\nimport { isStudioTelemetryEnabled, postToUserApi } from '../telemetry';\n\n/**\n * Reports unexpected Studio errors (uncaught errors, unhandled rejections and\n * errors caught by the error boundaries) to Flexkit through the Studio's own\n * BFF (`/api/flexkit/-/client-errors`), which forwards the session so the\n * report is attributed to the signed-in user.\n *\n * Reports carry the error, the Studio path (no query string or hash) and the\n * current project id; never request bodies, form values or record data.\n */\n\nexport type ClientErrorSource = 'window' | 'unhandledrejection' | 'react' | 'manual';\n\nexport interface ClientError {\n source: ClientErrorSource;\n name: string;\n message: string;\n stack?: string;\n componentStack?: string;\n path?: string;\n projectId?: string;\n occurredAt: string;\n}\n\nexport interface ClientErrorApp {\n platform: 'web' | 'desktop';\n version: string;\n userAgent?: string;\n}\n\nexport interface ClientErrorReport {\n app: ClientErrorApp;\n errors: ClientError[];\n}\n\n/** Field limits of the backend schema. */\nconst LIMITS = {\n componentStack: 4_000,\n message: 2_000,\n name: 200,\n path: 500,\n stack: 8_000,\n userAgent: 500,\n} as const;\n\n/** The backend accepts 1 to 10 errors per report. */\nexport const MAX_ERRORS_PER_REPORT = 10;\n/** The backend refuses bodies over 64 KB; `keepalive` requests share a 64 KB budget too. */\nexport const MAX_REPORT_BYTES = 60_000;\n/** Reports kept per page session; anything after that is dropped. */\nexport const MAX_ERRORS_PER_SESSION = 50;\n/** At most one report is sent per interval; errors in between are batched. */\nexport const FLUSH_INTERVAL_MS = 5_000;\n\n/** Kept for callers and tests that name the gate after error reporting. */\nexport {\n isTelemetryEnabled as isErrorReportingEnabled,\n LEGACY_TELEMETRY_STORAGE_KEY as ERROR_REPORTING_STORAGE_KEY,\n type TelemetryEnvironment as ErrorReportingEnvironment,\n} from '../telemetry';\n\nexport const PROJECT_ID_PATTERN = /^[a-z0-9]{1,64}$/;\n\nfunction truncate(value: string, max: number): string {\n return value.length > max ? value.slice(0, max) : value;\n}\n\n/** The pathname of a path or URL, without query string or hash. */\nexport function toReportPath(pathOrUrl: string): string {\n let path = pathOrUrl;\n\n try {\n if (/^[a-z][a-z0-9+.-]*:/i.test(pathOrUrl)) {\n path = new URL(pathOrUrl).pathname;\n }\n } catch {\n // Not a URL; strip by hand below.\n }\n\n return truncate(path.split(/[?#]/)[0] ?? '', LIMITS.path);\n}\n\nexport interface ErrorDetails {\n name: string;\n message: string;\n stack?: string;\n}\n\n/**\n * Name, message and stack of anything thrown. A non-Error value (a rejected\n * promise with a plain object) is described by its type only, so record data\n * someone rejected with never leaves the browser.\n */\nexport function describeError(error: unknown): ErrorDetails {\n if (error instanceof Error) {\n return {\n name: error.name || 'Error',\n message: typeof error.message === 'string' ? error.message : '',\n stack: typeof error.stack === 'string' ? error.stack : undefined,\n };\n }\n\n if (typeof error === 'string') {\n return { name: 'Error', message: error };\n }\n\n if (error === null || error === undefined) {\n return { name: 'Error', message: `Non-Error thrown: ${String(error)}` };\n }\n\n if (typeof error === 'object') {\n const constructorName = (error as { constructor?: { name?: unknown } }).constructor?.name;\n\n return {\n name: 'Error',\n message: `Non-Error thrown: ${typeof constructorName === 'string' && constructorName ? constructorName : 'object'}`,\n };\n }\n\n return { name: 'Error', message: `Non-Error thrown: ${typeof error}` };\n}\n\nconst NOISE_MESSAGES = [\n /ResizeObserver loop (limit exceeded|completed with undelivered notifications)/i,\n // Cross-origin script errors carry nothing to act on.\n /^Script error\\.?$/i,\n /The (operation|user) (was )?aborted/i,\n /signal is aborted without reason/i,\n];\n\nconst EXTENSION_URL = /\\b(chrome|moz|safari(-web)?|ms-browser)-extension:\\/\\//i;\n\nconst EMAIL_ADDRESS = /[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,}/gi;\n\n/** Masks email addresses an error message may quote from a record or form. */\nexport function maskMessage(message: string): string {\n return message.replace(EMAIL_ADDRESS, '<email>');\n}\n\n/** Errors that are not Studio bugs: browser quirks, aborted requests, browser extensions. */\nexport function isNoiseError(details: ErrorDetails, sourceUrl?: string): boolean {\n if (details.name === 'AbortError') {\n return true;\n }\n\n if (NOISE_MESSAGES.some((pattern) => pattern.test(details.message))) {\n return true;\n }\n\n if (sourceUrl && EXTENSION_URL.test(sourceUrl)) {\n return true;\n }\n\n return Boolean(details.stack && EXTENSION_URL.test(details.stack));\n}\n\nexport interface BuildClientErrorOptions {\n source: ClientErrorSource;\n componentStack?: string;\n path?: string;\n projectId?: string | null;\n /** The script the error came from (`ErrorEvent.filename`), checked for browser extensions. */\n sourceUrl?: string;\n now?: Date;\n}\n\n/** The report entry for an error, or null when it is noise. */\nexport function buildClientError(error: unknown, options: BuildClientErrorOptions): ClientError | null {\n const details = describeError(error);\n\n if (isNoiseError(details, options.sourceUrl)) {\n return null;\n }\n\n const entry: ClientError = {\n source: options.source,\n name: truncate(details.name, LIMITS.name),\n message: truncate(maskMessage(details.message), LIMITS.message),\n occurredAt: (options.now ?? new Date()).toISOString(),\n };\n\n if (details.stack) {\n entry.stack = truncate(details.stack, LIMITS.stack);\n }\n\n if (options.componentStack) {\n entry.componentStack = truncate(options.componentStack, LIMITS.componentStack);\n }\n\n if (options.path) {\n entry.path = toReportPath(options.path);\n }\n\n if (options.projectId && PROJECT_ID_PATTERN.test(options.projectId)) {\n entry.projectId = options.projectId;\n }\n\n return entry;\n}\n\n/** Identity of an error within a page session: the same message and stack are reported once. */\nexport function errorKey(error: Pick<ClientError, 'message' | 'name' | 'stack'>): string {\n return `${error.name}\\n${error.message}\\n${error.stack ?? ''}`;\n}\n\nconst encoder = new TextEncoder();\n\nfunction byteLength(value: string): number {\n return encoder.encode(value).length;\n}\n\n/**\n * Takes the errors that fit one report (at most 10 and `maxBytes` of JSON)\n * off the front of the queue. Returns the request body and how many errors it holds.\n */\nexport function buildReportBody(\n app: ClientErrorApp,\n queue: readonly ClientError[],\n maxBytes = MAX_REPORT_BYTES\n): { body: string; count: number } | null {\n // The envelope plus each error once, joined by commas.\n let size = byteLength(JSON.stringify({ app, errors: [] } satisfies ClientErrorReport));\n const errors: ClientError[] = [];\n\n for (const error of queue.slice(0, MAX_ERRORS_PER_REPORT)) {\n const errorSize = byteLength(JSON.stringify(error)) + (errors.length ? 1 : 0);\n\n if (size + errorSize > maxBytes) {\n break;\n }\n\n size += errorSize;\n errors.push(error);\n }\n\n if (errors.length === 0) {\n return null;\n }\n\n return { body: JSON.stringify({ app, errors } satisfies ClientErrorReport), count: errors.length };\n}\n\nexport type SendReport = (body: string, options: { unloading: boolean }) => Promise<number | null>;\n\nexport interface ErrorReporterOptions {\n app: ClientErrorApp;\n send: SendReport;\n /** The current Studio path; only its pathname is sent. */\n getPath?: () => string | undefined;\n now?: () => Date;\n setTimer?: (callback: () => void, ms: number) => unknown;\n clearTimer?: (timer: unknown) => void;\n}\n\nexport interface ErrorReporter {\n report: (error: unknown, options: Omit<BuildClientErrorOptions, 'path' | 'projectId' | 'now'>) => void;\n setProjectId: (projectId: string | null) => void;\n /** Sends the next report now; `unloading` uses a beacon or keepalive request that outlives the page. */\n flush: (options?: { unloading?: boolean }) => void;\n /** Errors waiting to be sent (tests). */\n pending: () => readonly ClientError[];\n dispose: () => void;\n}\n\n/** The queue, dedupe, cap and batching; the transport and the clock are injected. */\nexport function createErrorReporter({\n app,\n send,\n getPath,\n now = () => new Date(),\n setTimer = (callback, ms) => setTimeout(callback, ms),\n clearTimer = (timer) => clearTimeout(timer as ReturnType<typeof setTimeout>),\n}: ErrorReporterOptions): ErrorReporter {\n const queue: ClientError[] = [];\n const seen = new Set<string>();\n let accepted = 0;\n let projectId: string | null = null;\n let timer: unknown = null;\n let stopped = false;\n\n function schedule(): void {\n if (timer === null && queue.length > 0 && !stopped) {\n timer = setTimer(() => {\n timer = null;\n flush();\n }, FLUSH_INTERVAL_MS);\n }\n }\n\n function sendNext(unloading: boolean): boolean {\n const next = buildReportBody(app, queue);\n\n if (!next) {\n // An error that cannot fit a report on its own; drop it.\n queue.shift();\n\n return queue.length > 0;\n }\n\n queue.splice(0, next.count);\n send(next.body, { unloading })\n .then((status) => {\n // Rate limited or not allowed: stop for this page session rather than retry.\n if (status === 401 || status === 403 || status === 429) {\n stopped = true;\n queue.length = 0;\n }\n })\n .catch(() => {\n // Never report the reporter's own failures.\n });\n\n return queue.length > 0;\n }\n\n function flush({ unloading = false }: { unloading?: boolean } = {}): void {\n try {\n if (stopped) {\n return;\n }\n\n if (timer !== null && unloading) {\n clearTimer(timer);\n timer = null;\n }\n\n // One report per flush, also when the page goes away: beacons and\n // keepalive requests share a 64 KB budget, so a second would be refused.\n if (queue.length > 0) {\n sendNext(unloading);\n }\n\n schedule();\n } catch {\n // Error reporting must never break the Studio.\n }\n }\n\n return {\n report(error, options) {\n try {\n if (stopped || accepted >= MAX_ERRORS_PER_SESSION) {\n return;\n }\n\n const entry = buildClientError(error, {\n ...options,\n now: now(),\n path: getPath?.(),\n projectId,\n });\n\n if (!entry) {\n return;\n }\n\n const key = errorKey(entry);\n\n if (seen.has(key)) {\n return;\n }\n\n seen.add(key);\n accepted += 1;\n queue.push(entry);\n schedule();\n } catch {\n // Error reporting must never break the Studio.\n }\n },\n setProjectId(id) {\n projectId = id;\n },\n flush,\n pending: () => queue,\n dispose() {\n if (timer !== null) {\n clearTimer(timer);\n timer = null;\n }\n\n stopped = true;\n queue.length = 0;\n },\n };\n}\n\n/** Sends a report through the BFF; a beacon when the page is going away on the web. */\nexport const sendReportToBff: SendReport = async (body, { unloading }) => {\n const url = userApiPaths.clientErrors;\n\n // A beacon outlives the page. The BFF reads its JSON body like a fetch's\n // and the browser sends the session cookie with it (same origin). The\n // desktop app's BFF only answers script requests, so it uses `keepalive`.\n if (unloading && !getDesktop() && typeof navigator !== 'undefined' && typeof navigator.sendBeacon === 'function') {\n try {\n // text/plain is CORS-safelisted, so no browser refuses the beacon; the body is still JSON.\n if (navigator.sendBeacon(url, new Blob([body], { type: 'text/plain' }))) {\n return null;\n }\n } catch {\n // Fall back to a keepalive fetch.\n }\n }\n\n return postToUserApi(url, body, { keepalive: unloading });\n};\n\nlet installed: ErrorReporter | null = null;\n\n/** Reports an error caught by the Studio (an error boundary, for example). Does nothing when reporting is off. */\nexport function reportStudioError(\n error: unknown,\n { source = 'manual', componentStack }: { source?: ClientErrorSource; componentStack?: string } = {}\n): void {\n installed?.report(error, { source, componentStack });\n}\n\n/** The project the Studio shows, added to reports; null outside a project. */\nexport function setErrorReportingProjectId(projectId: string | null): void {\n installed?.setProjectId(projectId);\n}\n\n/**\n * Starts reporting uncaught errors and unhandled rejections when reporting is\n * enabled for this environment. Returns the function that stops it.\n */\nexport function installErrorReporter({ hosted }: { hosted: boolean }): () => void {\n if (typeof window === 'undefined' || installed) {\n return () => undefined;\n }\n\n if (!isStudioTelemetryEnabled({ hosted })) {\n return () => undefined;\n }\n\n const desktop = getDesktop();\n\n const reporter = createErrorReporter({\n app: {\n platform: desktop ? 'desktop' : 'web',\n version: STUDIO_VERSION,\n userAgent: truncate(navigator.userAgent, LIMITS.userAgent),\n },\n send: sendReportToBff,\n getPath: () => window.location.pathname,\n });\n\n function onError(event: ErrorEvent): void {\n reporter.report(event.error ?? event.message, { source: 'window', sourceUrl: event.filename });\n }\n\n function onUnhandledRejection(event: PromiseRejectionEvent): void {\n reporter.report(event.reason, { source: 'unhandledrejection' });\n }\n\n function onPageHide(): void {\n reporter.flush({ unloading: true });\n }\n\n window.addEventListener('error', onError);\n window.addEventListener('unhandledrejection', onUnhandledRejection);\n window.addEventListener('pagehide', onPageHide);\n installed = reporter;\n\n return () => {\n window.removeEventListener('error', onError);\n window.removeEventListener('unhandledrejection', onUnhandledRejection);\n window.removeEventListener('pagehide', onPageHide);\n reporter.flush({ unloading: true });\n reporter.dispose();\n\n if (installed === reporter) {\n installed = null;\n }\n };\n}\n","import { userApiPaths } from '../api-paths';\nimport { getDesktop } from '../desktop';\nimport { PROJECT_ID_PATTERN } from '../error/error-reporter';\nimport { isStudioTelemetryEnabled, postToUserApi } from '../telemetry';\n\n/**\n * Product events only the Studio can see, sent to Flexkit through the\n * Studio's own server proxy (`/api/flexkit/-/product-events`) with the\n * session: the Graph app opened, the desktop app launched. They follow the\n * Studio's telemetry setting (see core/telemetry.ts) and carry ids, the\n * desktop app version and the OS only.\n */\nexport type StudioProductEvent =\n | { event: 'graph_opened'; projectId: string }\n | { event: 'desktop_app_opened'; appVersion: string; os: 'darwin' | 'linux' | 'win32' };\n\n/** Identity of an event within a page session; the backend also counts each once per day. */\nexport function productEventKey(studioEvent: StudioProductEvent): string {\n return studioEvent.event === 'graph_opened' ? `graph_opened:${studioEvent.projectId}` : studioEvent.event;\n}\n\n/** Sends the event body; resolves with the response status. */\nexport type SendProductEvent = (body: string) => Promise<number>;\n\nexport interface ProductEventTracker {\n track: (studioEvent: StudioProductEvent, options?: { onDelivered?: () => void }) => void;\n}\n\n/**\n * Sends each event once per page session through `send`. An event counts as\n * sent only once the backend accepted it, so one sent while offline or signed\n * out is sent again next time. Never throws.\n */\nexport function createProductEventTracker(send: SendProductEvent): ProductEventTracker {\n const pending = new Set<string>();\n const delivered = new Set<string>();\n\n return {\n track(studioEvent, { onDelivered } = {}) {\n const key = productEventKey(studioEvent);\n\n if (pending.has(key) || delivered.has(key)) {\n return;\n }\n\n pending.add(key);\n\n const settle = (status: number | null): void => {\n pending.delete(key);\n\n if (status !== null && status >= 200 && status < 300) {\n delivered.add(key);\n onDelivered?.();\n }\n };\n\n try {\n send(JSON.stringify(studioEvent)).then(settle, () => settle(null));\n } catch {\n settle(null);\n }\n },\n };\n}\n\nlet tracker: ProductEventTracker | null = null;\n\n/** Records an event when product events are on (see `installProductEvents`); otherwise does nothing. */\nexport function trackStudioEvent(studioEvent: StudioProductEvent): void {\n if (studioEvent.event === 'graph_opened' && !PROJECT_ID_PATTERN.test(studioEvent.projectId)) {\n return;\n }\n\n tracker?.track(studioEvent);\n}\n\n/** Session storage flag: this desktop app launch was recorded (page reloads keep it, a relaunch does not). */\nexport const DESKTOP_LAUNCH_STORAGE_KEY = 'flexkit:desktop-launch-recorded';\n\nfunction readSessionFlag(key: string): boolean {\n try {\n return sessionStorage.getItem(key) === '1';\n } catch {\n return false;\n }\n}\n\nfunction writeSessionFlag(key: string): void {\n try {\n sessionStorage.setItem(key, '1');\n } catch {\n // Without session storage the backend's once-per-day count still applies.\n }\n}\n\n/**\n * Turns product events on for this environment and records the desktop app\n * launch (once per launch, once the user is signed in). Returns the function\n * that turns them off again.\n */\nexport function installProductEvents({ hosted }: { hosted: boolean }): () => void {\n if (!isStudioTelemetryEnabled({ hosted })) {\n return () => undefined;\n }\n\n const current = createProductEventTracker((body) =>\n postToUserApi(userApiPaths.productEvents, body, { keepalive: true })\n );\n const desktop = getDesktop();\n\n tracker = current;\n\n if (desktop && !readSessionFlag(DESKTOP_LAUNCH_STORAGE_KEY)) {\n current.track(\n { appVersion: desktop.version, event: 'desktop_app_opened', os: desktop.platform },\n { onDelivered: () => writeSessionFlag(DESKTOP_LAUNCH_STORAGE_KEY) }\n );\n }\n\n return () => {\n if (tracker === current) {\n tracker = null;\n }\n };\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import'./index.css';import {f as f$1,e as e$2}from'./chunk-
|
|
1
|
+
import'./index.css';import {f as f$1,e as e$2}from'./chunk-DZTBKBD6.js';import {p,o as o$1,h as h$1,i}from'./chunk-HAU76X63.js';import {b}from'./chunk-V7C4EHK3.js';import {j}from'./chunk-I4UFLN53.js';import {d,c}from'./chunk-XMOSCJOI.js';import {s}from'./chunk-7KLXWCDS.js';import {f}from'./chunk-TWALS64F.js';import {na}from'./chunk-DGIY4SKN.js';import {e,g,h,j as j$1,o,n,k}from'./chunk-SZEGGBOC.js';import {a,d as d$1,c as c$1,e as e$1,g as g$1}from'./chunk-HDOIOXMP.js';import {b as b$1}from'./chunk-6NRQMG26.js';import {PencilIcon,Trash2Icon,Ellipsis,Settings2,RefreshCw,Loader2,Trash2}from'lucide-react';import {jsxs,jsx}from'react/jsx-runtime';import {lazy,useState,Suspense}from'react';import {find,propEq}from'ramda';import {gql}from'@apollo/client';import {useApolloClient}from'@apollo/client/react';import {toast}from'sonner';function Be({entityName:e$1,entityNamePlural:a,row:c,options:i={canDelete:true,canEdit:true}}){let m=j(),N=b(),p=c.original._id,D=(i.canDelete??true)&&N,f=i.canEdit??true;function h$1(){m({type:"EditEntity",payload:{entityId:p,entityNamePlural:a}});}function d(){m({type:"DeleteEntity",payload:{entityId:p,entityName:e$1}});}return jsxs("div",{className:"fk:flex",children:[f&&jsxs(b$1,{className:"fk:flex fk:h-7 fk:w-7 fk:p-0 fk:mr-1",onClick:h$1,variant:"ghost",children:[jsx(PencilIcon,{className:"fk:h-4 fk:w-4"}),jsx("span",{className:"fk:sr-only",children:"Edit"})]}),D&&!f&&jsxs(b$1,{className:"fk:flex fk:h-7 fk:w-7 fk:p-0 fk:mr-1",onClick:d,variant:"ghost",children:[jsx(Trash2Icon,{className:"fk:h-4 fk:w-4"}),jsx("span",{className:"fk:sr-only",children:"Delete"})]}),f&&D&&jsxs(e,{children:[jsx(g,{asChild:true,children:jsxs(b$1,{className:"fk:flex fk:h-7 fk:w-7 fk:p-0",variant:"ghost",children:[jsx(Ellipsis,{className:"fk:h-4 fk:w-4"}),jsx("span",{className:"fk:sr-only",children:"Additional actions"})]})}),jsxs(h,{align:"end",className:"w-[160px]",children:[jsxs(j$1,{onClick:h$1,children:[jsx(PencilIcon,{className:"fk:mr-2 fk:h-4 fk:w-4"}),"Edit"]}),jsx(o,{}),jsxs(j$1,{className:"fk:text-destructive",onClick:d,children:[jsx(Trash2Icon,{className:"fk:mr-2 fk:h-4 fk:w-4"}),"Delete"]})]})]})]})}function Z({table:e$1}){return jsxs(e,{children:[jsx(g,{asChild:true,children:jsxs(b$1,{className:"fk:hidden fk:h-8 fk:lg:flex",size:"sm",variant:"outline",children:[jsx(Settings2,{className:"fk:mr-2 fk:h-4 fk:w-4"}),"View"]})}),jsxs(h,{align:"end",className:"fk:w-[150px]",children:[jsx(n,{children:"Toggle columns"}),jsx(o,{}),e$1.getAllColumns().filter(a=>typeof a.accessorFn<"u"&&a.getCanHide()).map(a=>jsx(k,{checked:a.getIsVisible(),className:"capitalize",onCheckedChange:c=>{a.toggleVisibility(!!c);},children:a.id},a.id))]})]})}var Ce=lazy(()=>import('./record-links-NPBFSAHR.js').then(e=>({default:e.EntityKnowledgeButton}))),ve=lazy(()=>import('./entry-XXLNSL6Q.js').then(e=>({default:e.EntityGraphButton})));function at({entityName:e,isReloading:a$1=false,onReload:c$2,table:i$1}){let m=j(),N=d(),p$1=c(),D=useApolloClient(),{currentProject:f$2,currentProjectId:h}=f(),d$2=f$2?.schema??[],w=f$2?.scopes,[ae,ne,le]=f$1(),[b$2,P]=useState(false),y=b(),r=i$1.getSelectedRowModel().rows.map(t=>t.original._id);function se(){m({type:"AddEntity",payload:{entityName:e}});}function ie(t){N({type:"setScope",payload:{projectId:h,scope:t}});}async function re(t){if(t.length===0)return;let u=h$1(e,d$2,t);await new Promise((pe,fe)=>{ne(gql`
|
|
2
2
|
${u}
|
|
3
|
-
`),le({variables:{where:i(t)},update(x){for(let me of t)x.evict({id:me});},onCompleted:()=>{pe();},onError:x=>{fe(x);}}),ae(true);});}function ce(){let t=e==="_asset"?"asset":e.toLowerCase();m({type:"AlertDialog",payload:{options:{dialogTitle:`Delete ${r.length} ${t}${r.length>1?"s":""}`,dialogMessage:r.length>1?`Are you sure you want to delete the selected ${t}s? They will be deleted permanently.`:`Are you sure you want to delete the selected ${t}? The item will be deleted permanently.`,dialogCancelTitle:"Cancel",dialogActionLabel:"Delete",isDestructive:true,dialogActionSubmit:async()=>{P(true);try{let u=[...r];await re(u),i$1.resetRowSelection(),await p(D,o$1(e,d$2),u),toast.success(u.length>1?"Items successfully deleted.":"Item successfully deleted.");}catch{toast.error("Failed to delete selected items.");}finally{P(false);}},dialogActionCancel:()=>{}}}});}return jsxs("div",{className:"fk:flex fk:items-center fk:justify-between",children:[jsxs("div",{className:"fk:flex fk:flex-1 fk:items-center fk:space-x-2",children:[w&&w.length>0?jsxs(a,{defaultValue:p$1.scope,onValueChange:t=>{ie(t);},value:p$1.scope,children:[jsxs(d$1,{className:"fk:w-48!",id:"project",size:"sm",children:[jsx("span",{className:"fk:text-muted-foreground",children:"Scope:"}),jsx(c$1,{children:(find(propEq(p$1.scope??"","name"))(w)||null)?.label})]}),jsx(e$1,{children:w.map(t=>jsx(g$1,{value:t.name,children:t.label},t.name))})]}):null,jsx(Z,{table:i$1}),c$2?jsx(b$1,{"aria-label":"Reload",className:"fk:h-8",disabled:b$2||a$1,onClick:c$2,size:"icon-sm",variant:"outline",children:jsx(RefreshCw,{className:a$1?"fk:animate-spin":void 0})}):null,jsx(e$2,{table:i$1})]}),r.length>0?jsx(na,{disabled:!y,children:jsxs(b$1,{className:"fk:h-8 fk:mr-2 fk:lg:flex",disabled:b$2||!y,onClick:ce,size:"sm",variant:"destructive",children:[b$2?jsx(Loader2,{className:"fk:mr-2 fk:h-4 fk:w-4 fk:animate-spin"}):jsx(Trash2,{className:"fk:mr-2 fk:h-4 fk:w-4"}),"Delete (",r.length,")"]})}):null,e&&s(e)?jsx(Suspense,{fallback:null,children:jsx(Ce,{entityName:e})}):null,e?jsx(Suspense,{fallback:null,children:jsx(ve,{entityName:e,selectedIds:r})}):null,jsx(na,{disabled:!y,children:jsx(b$1,{className:"fk:h-8 fk:lg:flex",disabled:b$2||!y,onClick:se,size:"sm",variant:"default",children:"Create"})})]})}export{Be as a,Z as b,at as c};//# sourceMappingURL=chunk-
|
|
4
|
-
//# sourceMappingURL=chunk-
|
|
3
|
+
`),le({variables:{where:i(t)},update(x){for(let me of t)x.evict({id:me});},onCompleted:()=>{pe();},onError:x=>{fe(x);}}),ae(true);});}function ce(){let t=e==="_asset"?"asset":e.toLowerCase();m({type:"AlertDialog",payload:{options:{dialogTitle:`Delete ${r.length} ${t}${r.length>1?"s":""}`,dialogMessage:r.length>1?`Are you sure you want to delete the selected ${t}s? They will be deleted permanently.`:`Are you sure you want to delete the selected ${t}? The item will be deleted permanently.`,dialogCancelTitle:"Cancel",dialogActionLabel:"Delete",isDestructive:true,dialogActionSubmit:async()=>{P(true);try{let u=[...r];await re(u),i$1.resetRowSelection(),await p(D,o$1(e,d$2),u),toast.success(u.length>1?"Items successfully deleted.":"Item successfully deleted.");}catch{toast.error("Failed to delete selected items.");}finally{P(false);}},dialogActionCancel:()=>{}}}});}return jsxs("div",{className:"fk:flex fk:items-center fk:justify-between",children:[jsxs("div",{className:"fk:flex fk:flex-1 fk:items-center fk:space-x-2",children:[w&&w.length>0?jsxs(a,{defaultValue:p$1.scope,onValueChange:t=>{ie(t);},value:p$1.scope,children:[jsxs(d$1,{className:"fk:w-48!",id:"project",size:"sm",children:[jsx("span",{className:"fk:text-muted-foreground",children:"Scope:"}),jsx(c$1,{children:(find(propEq(p$1.scope??"","name"))(w)||null)?.label})]}),jsx(e$1,{children:w.map(t=>jsx(g$1,{value:t.name,children:t.label},t.name))})]}):null,jsx(Z,{table:i$1}),c$2?jsx(b$1,{"aria-label":"Reload",className:"fk:h-8",disabled:b$2||a$1,onClick:c$2,size:"icon-sm",variant:"outline",children:jsx(RefreshCw,{className:a$1?"fk:animate-spin":void 0})}):null,jsx(e$2,{table:i$1})]}),r.length>0?jsx(na,{disabled:!y,children:jsxs(b$1,{className:"fk:h-8 fk:mr-2 fk:lg:flex",disabled:b$2||!y,onClick:ce,size:"sm",variant:"destructive",children:[b$2?jsx(Loader2,{className:"fk:mr-2 fk:h-4 fk:w-4 fk:animate-spin"}):jsx(Trash2,{className:"fk:mr-2 fk:h-4 fk:w-4"}),"Delete (",r.length,")"]})}):null,e&&s(e)?jsx(Suspense,{fallback:null,children:jsx(Ce,{entityName:e})}):null,e?jsx(Suspense,{fallback:null,children:jsx(ve,{entityName:e,selectedIds:r})}):null,jsx(na,{disabled:!y,children:jsx(b$1,{className:"fk:h-8 fk:lg:flex",disabled:b$2||!y,onClick:se,size:"sm",variant:"default",children:"Create"})})]})}export{Be as a,Z as b,at as c};//# sourceMappingURL=chunk-RP2CTEIL.js.map
|
|
4
|
+
//# sourceMappingURL=chunk-RP2CTEIL.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/data-grid/data-table-row-actions.tsx","../src/data-grid/data-table-view-options.tsx","../src/data-grid/data-table-toolbar.tsx"],"names":["DataTableRowActions","entityName","entityNamePlural","row","options","actionDispatch","useDispatch","canMutate","useCanMutate","entityId","canDelete","canEdit","handleEdit","handleDelete","jsxs","Button","jsx","PencilIcon","Trash2Icon","DropdownMenu","DropdownMenuTrigger","Ellipsis","DropdownMenuContent","DropdownMenuItem","DropdownMenuSeparator","DataTableViewOptions","table","Settings2","DropdownMenuLabel","column","DropdownMenuCheckboxItem","value","EntityKnowledgeButton","lazy","m","EntityGraphButton","DataTableToolbar","isReloading","onReload","appDispatch","useAppDispatch","appContext","useAppContext","apolloClient","useApolloClient","currentProject","currentProjectId","useConfig","schema","scopes","runMutation","setMutation","setOptions","useEntityMutation","isDeleting","setIsDeleting","useState","selectedIds","handleCreate","handleScopeChange","deleteSelected","ids","mutation","getEntityDeleteMutation","resolve","reject","gql","getEntityDeleteWhere","cache","id","error","handleBatchDelete","itemLabel","idsToDelete","scheduleEntityListRemoval","getEntityListQueryName","toast","Select","SelectTrigger","SelectValue","find","propEq","SelectContent","scopeItem","SelectItem","RefreshCw","DataTableSortedBy","PermissionTooltip","Loader2","Trash2","isKnowledgeLinkableEntity","Suspense"],"mappings":"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","file":"chunk-OCWM45Z2.js","sourcesContent":["'use client';\n\nimport type { JSX } from 'react';\nimport { Ellipsis, PencilIcon, Trash2Icon } from 'lucide-react';\nimport type { Row } from '@tanstack/react-table';\nimport { Button } from '../ui/primitives/button';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from '../ui/primitives/dropdown-menu';\nimport { useDispatch } from '../entities/actions-context';\nimport { useCanMutate } from '../core/permissions';\n\ninterface DataTableRowActionsProps<TData> {\n entityName: string;\n entityNamePlural: string;\n row: Row<TData>;\n options?: {\n canDelete?: boolean;\n canEdit?: boolean;\n };\n}\n\nexport function DataTableRowActions<TData>({\n entityName,\n entityNamePlural,\n row,\n options = { canDelete: true, canEdit: true },\n}: DataTableRowActionsProps<TData>): JSX.Element {\n const actionDispatch = useDispatch();\n const canMutate = useCanMutate();\n // @ts-expect-error -- the DataGrid's original type doesn't know about the _id property\n const entityId = row.original._id;\n // Read-only roles keep the pencil (the drawer doubles as their read view)\n // but lose the delete affordance entirely.\n const canDelete = (options.canDelete ?? true) && canMutate;\n const canEdit = options.canEdit ?? true;\n\n function handleEdit(): void {\n actionDispatch({ type: 'EditEntity', payload: { entityId, entityNamePlural } });\n }\n\n function handleDelete(): void {\n actionDispatch({ type: 'DeleteEntity', payload: { entityId, entityName } });\n }\n\n return (\n <div className=\"fk:flex\">\n {canEdit && (\n <Button className=\"fk:flex fk:h-7 fk:w-7 fk:p-0 fk:mr-1\" onClick={handleEdit} variant=\"ghost\">\n <PencilIcon className=\"fk:h-4 fk:w-4\" />\n <span className=\"fk:sr-only\">Edit</span>\n </Button>\n )}\n {canDelete && !canEdit && (\n <Button className=\"fk:flex fk:h-7 fk:w-7 fk:p-0 fk:mr-1\" onClick={handleDelete} variant=\"ghost\">\n <Trash2Icon className=\"fk:h-4 fk:w-4\" />\n <span className=\"fk:sr-only\">Delete</span>\n </Button>\n )}\n {canEdit && canDelete && (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button className=\"fk:flex fk:h-7 fk:w-7 fk:p-0\" variant=\"ghost\">\n <Ellipsis className=\"fk:h-4 fk:w-4\" />\n <span className=\"fk:sr-only\">Additional actions</span>\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" className=\"w-[160px]\">\n <DropdownMenuItem onClick={handleEdit}>\n <PencilIcon className=\"fk:mr-2 fk:h-4 fk:w-4\" />\n Edit\n </DropdownMenuItem>\n <DropdownMenuSeparator />\n <DropdownMenuItem className=\"fk:text-destructive\" onClick={handleDelete}>\n <Trash2Icon className=\"fk:mr-2 fk:h-4 fk:w-4\" />\n Delete\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n )}\n </div>\n );\n}\n","'use client';\n\nimport type { JSX } from 'react';\nimport { Settings2 } from 'lucide-react';\nimport type { Table } from '@tanstack/react-table';\nimport { Button } from '../ui/primitives/button';\nimport {\n DropdownMenu,\n DropdownMenuCheckboxItem,\n DropdownMenuContent,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from '../ui/primitives/dropdown-menu';\n\ninterface DataTableViewOptionsProps<TData> {\n table: Table<TData>;\n}\n\nexport function DataTableViewOptions<TData>({ table }: DataTableViewOptionsProps<TData>): JSX.Element {\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button className=\"fk:hidden fk:h-8 fk:lg:flex\" size=\"sm\" variant=\"outline\">\n <Settings2 className=\"fk:mr-2 fk:h-4 fk:w-4\" />\n View\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" className=\"fk:w-[150px]\">\n <DropdownMenuLabel>Toggle columns</DropdownMenuLabel>\n <DropdownMenuSeparator />\n {table\n .getAllColumns()\n .filter((column) => typeof column.accessorFn !== 'undefined' && column.getCanHide())\n .map((column) => {\n return (\n <DropdownMenuCheckboxItem\n checked={column.getIsVisible()}\n className=\"capitalize\"\n key={column.id}\n onCheckedChange={(value) => {\n column.toggleVisibility(Boolean(value));\n }}\n >\n {column.id}\n </DropdownMenuCheckboxItem>\n );\n })}\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n","'use client';\n\nimport { lazy, Suspense, useState } from 'react';\nimport type { JSX } from 'react';\nimport { find, propEq } from 'ramda';\nimport type { Table } from '@tanstack/react-table';\nimport { Loader2, RefreshCw, Trash2 } from 'lucide-react';\nimport { gql } from '@apollo/client';\nimport { useApolloClient } from '@apollo/client/react';\nimport { toast } from 'sonner';\nimport { Button } from '../ui/primitives/button';\nimport { PermissionTooltip } from '../ui/components/permission-tooltip';\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../ui/primitives/select';\nimport { useDispatch } from '../entities/actions-context';\nimport { useAppContext, useAppDispatch } from '../core/app-context';\nimport { useCanMutate } from '../core/permissions';\nimport { useConfig } from '../core/config/config-context';\nimport { DataTableViewOptions } from './data-table-view-options';\nimport { DataTableSortedBy } from './data-table-sorted-by';\nimport { useEntityMutation } from '../graphql-client/use-entity-mutation';\nimport { getEntityDeleteMutation, getEntityDeleteWhere } from '../graphql-client/queries';\nimport { getEntityListQueryName, scheduleEntityListRemoval } from '../graphql-client/refetch-entity-lists';\nimport { isKnowledgeLinkableEntity } from '../apps/knowledge/knowledge';\n\n// Loaded on demand: the Knowledge module should only download when a list of\n// a linkable entity is in view, the way the record drawer loads its panel.\nconst EntityKnowledgeButton = lazy(() =>\n import('../apps/knowledge/record-links').then((m) => ({ default: m.EntityKnowledgeButton }))\n);\nconst EntityGraphButton = lazy(() => import('../apps/graph/entry').then((m) => ({ default: m.EntityGraphButton })));\n\ninterface DataTableToolbarProps<TData> {\n entityName: string;\n isReloading?: boolean;\n onReload?: () => void;\n table: Table<TData>;\n}\n\nexport function DataTableToolbar<TData>({\n entityName,\n isReloading = false,\n onReload,\n table,\n}: DataTableToolbarProps<TData>): JSX.Element {\n const actionDispatch = useDispatch();\n const appDispatch = useAppDispatch();\n const appContext = useAppContext();\n const apolloClient = useApolloClient();\n const { currentProject, currentProjectId } = useConfig();\n const schema = currentProject?.schema ?? [];\n const scopes = currentProject?.scopes;\n const [runMutation, setMutation, setOptions] = useEntityMutation();\n const [isDeleting, setIsDeleting] = useState(false);\n const canMutate = useCanMutate();\n\n // Collect selected entity ids from the table\n // @ts-expect-error -- the DataGrid's original type doesn't know about the _id property\n const selectedIds: string[] = table.getSelectedRowModel().rows.map((row) => row.original._id as string);\n\n function handleCreate(): void {\n actionDispatch({ type: 'AddEntity', payload: { entityName } });\n }\n\n function handleScopeChange(value: string): void {\n appDispatch({ type: 'setScope', payload: { projectId: currentProjectId, scope: value } });\n }\n\n async function deleteSelected(ids: string[]): Promise<void> {\n if (ids.length === 0) {\n return;\n }\n\n const mutation = getEntityDeleteMutation(entityName, schema, ids);\n\n await new Promise<void>((resolve, reject) => {\n setMutation(gql`\n ${mutation}\n `);\n\n setOptions({\n variables: { where: getEntityDeleteWhere(ids) },\n update(cache: { evict: (arg0: { id: string }) => void }) {\n for (const id of ids) {\n cache.evict({ id });\n }\n },\n onCompleted: () => {\n resolve();\n },\n onError: (error: Error) => {\n reject(error);\n },\n });\n\n runMutation(true);\n });\n }\n\n function handleBatchDelete(): void {\n const itemLabel = entityName === '_asset' ? 'asset' : entityName.toLowerCase();\n\n actionDispatch({\n type: 'AlertDialog',\n payload: {\n options: {\n dialogTitle: `Delete ${selectedIds.length} ${itemLabel}${selectedIds.length > 1 ? 's' : ''}`,\n dialogMessage:\n selectedIds.length > 1\n ? `Are you sure you want to delete the selected ${itemLabel}s? They will be deleted permanently.`\n : `Are you sure you want to delete the selected ${itemLabel}? The item will be deleted permanently.`,\n dialogCancelTitle: 'Cancel',\n dialogActionLabel: 'Delete',\n isDestructive: true,\n dialogActionSubmit: async () => {\n setIsDeleting(true);\n\n try {\n const idsToDelete = [...selectedIds];\n\n await deleteSelected(idsToDelete);\n\n table.resetRowSelection();\n // Drop rows immediately, then soft-refetch counts/pages.\n await scheduleEntityListRemoval(apolloClient, getEntityListQueryName(entityName, schema), idsToDelete);\n toast.success(idsToDelete.length > 1 ? 'Items successfully deleted.' : 'Item successfully deleted.');\n } catch {\n toast.error('Failed to delete selected items.');\n } finally {\n setIsDeleting(false);\n }\n },\n dialogActionCancel: () => {\n // no-op\n },\n },\n },\n });\n }\n\n return (\n <div className=\"fk:flex fk:items-center fk:justify-between\">\n <div className=\"fk:flex fk:flex-1 fk:items-center fk:space-x-2\">\n {scopes && scopes.length > 0 ? (\n <Select\n defaultValue={appContext.scope}\n onValueChange={(value) => {\n handleScopeChange(value);\n }}\n value={appContext.scope}\n >\n <SelectTrigger className=\"fk:w-48!\" id=\"project\" size=\"sm\">\n <span className=\"fk:text-muted-foreground\">Scope:</span>\n <SelectValue>\n {\n ((find(propEq(appContext.scope ?? '', 'name'))(scopes) as { name: string; label: string }) || null)\n ?.label\n }\n </SelectValue>\n </SelectTrigger>\n <SelectContent>\n {scopes.map((scopeItem) => (\n <SelectItem key={scopeItem.name} value={scopeItem.name}>\n {scopeItem.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n ) : null}\n <DataTableViewOptions table={table} />\n {onReload ? (\n <Button\n aria-label=\"Reload\"\n className=\"fk:h-8\"\n disabled={isDeleting || isReloading}\n onClick={onReload}\n size=\"icon-sm\"\n variant=\"outline\"\n >\n <RefreshCw className={isReloading ? 'fk:animate-spin' : undefined} />\n </Button>\n ) : null}\n <DataTableSortedBy table={table} />\n </div>\n {selectedIds.length > 0 ? (\n <PermissionTooltip disabled={!canMutate}>\n <Button\n className=\"fk:h-8 fk:mr-2 fk:lg:flex\"\n disabled={isDeleting || !canMutate}\n onClick={handleBatchDelete}\n size=\"sm\"\n variant=\"destructive\"\n >\n {isDeleting ? (\n <Loader2 className=\"fk:mr-2 fk:h-4 fk:w-4 fk:animate-spin\" />\n ) : (\n <Trash2 className=\"fk:mr-2 fk:h-4 fk:w-4\" />\n )}\n Delete ({selectedIds.length})\n </Button>\n </PermissionTooltip>\n ) : null}\n {entityName && isKnowledgeLinkableEntity(entityName) ? (\n <Suspense fallback={null}>\n <EntityKnowledgeButton entityName={entityName} />\n </Suspense>\n ) : null}\n {entityName ? (\n <Suspense fallback={null}>\n <EntityGraphButton entityName={entityName} selectedIds={selectedIds} />\n </Suspense>\n ) : null}\n <PermissionTooltip disabled={!canMutate}>\n <Button\n className=\"fk:h-8 fk:lg:flex\"\n disabled={isDeleting || !canMutate}\n onClick={handleCreate}\n size=\"sm\"\n variant=\"default\"\n >\n Create\n </Button>\n </PermissionTooltip>\n </div>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/data-grid/data-table-row-actions.tsx","../src/data-grid/data-table-view-options.tsx","../src/data-grid/data-table-toolbar.tsx"],"names":["DataTableRowActions","entityName","entityNamePlural","row","options","actionDispatch","useDispatch","canMutate","useCanMutate","entityId","canDelete","canEdit","handleEdit","handleDelete","jsxs","Button","jsx","PencilIcon","Trash2Icon","DropdownMenu","DropdownMenuTrigger","Ellipsis","DropdownMenuContent","DropdownMenuItem","DropdownMenuSeparator","DataTableViewOptions","table","Settings2","DropdownMenuLabel","column","DropdownMenuCheckboxItem","value","EntityKnowledgeButton","lazy","m","EntityGraphButton","DataTableToolbar","isReloading","onReload","appDispatch","useAppDispatch","appContext","useAppContext","apolloClient","useApolloClient","currentProject","currentProjectId","useConfig","schema","scopes","runMutation","setMutation","setOptions","useEntityMutation","isDeleting","setIsDeleting","useState","selectedIds","handleCreate","handleScopeChange","deleteSelected","ids","mutation","getEntityDeleteMutation","resolve","reject","gql","getEntityDeleteWhere","cache","id","error","handleBatchDelete","itemLabel","idsToDelete","scheduleEntityListRemoval","getEntityListQueryName","toast","Select","SelectTrigger","SelectValue","find","propEq","SelectContent","scopeItem","SelectItem","RefreshCw","DataTableSortedBy","PermissionTooltip","Loader2","Trash2","isKnowledgeLinkableEntity","Suspense"],"mappings":"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","file":"chunk-RP2CTEIL.js","sourcesContent":["'use client';\n\nimport type { JSX } from 'react';\nimport { Ellipsis, PencilIcon, Trash2Icon } from 'lucide-react';\nimport type { Row } from '@tanstack/react-table';\nimport { Button } from '../ui/primitives/button';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from '../ui/primitives/dropdown-menu';\nimport { useDispatch } from '../entities/actions-context';\nimport { useCanMutate } from '../core/permissions';\n\ninterface DataTableRowActionsProps<TData> {\n entityName: string;\n entityNamePlural: string;\n row: Row<TData>;\n options?: {\n canDelete?: boolean;\n canEdit?: boolean;\n };\n}\n\nexport function DataTableRowActions<TData>({\n entityName,\n entityNamePlural,\n row,\n options = { canDelete: true, canEdit: true },\n}: DataTableRowActionsProps<TData>): JSX.Element {\n const actionDispatch = useDispatch();\n const canMutate = useCanMutate();\n // @ts-expect-error -- the DataGrid's original type doesn't know about the _id property\n const entityId = row.original._id;\n // Read-only roles keep the pencil (the drawer doubles as their read view)\n // but lose the delete affordance entirely.\n const canDelete = (options.canDelete ?? true) && canMutate;\n const canEdit = options.canEdit ?? true;\n\n function handleEdit(): void {\n actionDispatch({ type: 'EditEntity', payload: { entityId, entityNamePlural } });\n }\n\n function handleDelete(): void {\n actionDispatch({ type: 'DeleteEntity', payload: { entityId, entityName } });\n }\n\n return (\n <div className=\"fk:flex\">\n {canEdit && (\n <Button className=\"fk:flex fk:h-7 fk:w-7 fk:p-0 fk:mr-1\" onClick={handleEdit} variant=\"ghost\">\n <PencilIcon className=\"fk:h-4 fk:w-4\" />\n <span className=\"fk:sr-only\">Edit</span>\n </Button>\n )}\n {canDelete && !canEdit && (\n <Button className=\"fk:flex fk:h-7 fk:w-7 fk:p-0 fk:mr-1\" onClick={handleDelete} variant=\"ghost\">\n <Trash2Icon className=\"fk:h-4 fk:w-4\" />\n <span className=\"fk:sr-only\">Delete</span>\n </Button>\n )}\n {canEdit && canDelete && (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button className=\"fk:flex fk:h-7 fk:w-7 fk:p-0\" variant=\"ghost\">\n <Ellipsis className=\"fk:h-4 fk:w-4\" />\n <span className=\"fk:sr-only\">Additional actions</span>\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" className=\"w-[160px]\">\n <DropdownMenuItem onClick={handleEdit}>\n <PencilIcon className=\"fk:mr-2 fk:h-4 fk:w-4\" />\n Edit\n </DropdownMenuItem>\n <DropdownMenuSeparator />\n <DropdownMenuItem className=\"fk:text-destructive\" onClick={handleDelete}>\n <Trash2Icon className=\"fk:mr-2 fk:h-4 fk:w-4\" />\n Delete\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n )}\n </div>\n );\n}\n","'use client';\n\nimport type { JSX } from 'react';\nimport { Settings2 } from 'lucide-react';\nimport type { Table } from '@tanstack/react-table';\nimport { Button } from '../ui/primitives/button';\nimport {\n DropdownMenu,\n DropdownMenuCheckboxItem,\n DropdownMenuContent,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from '../ui/primitives/dropdown-menu';\n\ninterface DataTableViewOptionsProps<TData> {\n table: Table<TData>;\n}\n\nexport function DataTableViewOptions<TData>({ table }: DataTableViewOptionsProps<TData>): JSX.Element {\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button className=\"fk:hidden fk:h-8 fk:lg:flex\" size=\"sm\" variant=\"outline\">\n <Settings2 className=\"fk:mr-2 fk:h-4 fk:w-4\" />\n View\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" className=\"fk:w-[150px]\">\n <DropdownMenuLabel>Toggle columns</DropdownMenuLabel>\n <DropdownMenuSeparator />\n {table\n .getAllColumns()\n .filter((column) => typeof column.accessorFn !== 'undefined' && column.getCanHide())\n .map((column) => {\n return (\n <DropdownMenuCheckboxItem\n checked={column.getIsVisible()}\n className=\"capitalize\"\n key={column.id}\n onCheckedChange={(value) => {\n column.toggleVisibility(Boolean(value));\n }}\n >\n {column.id}\n </DropdownMenuCheckboxItem>\n );\n })}\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n","'use client';\n\nimport { lazy, Suspense, useState } from 'react';\nimport type { JSX } from 'react';\nimport { find, propEq } from 'ramda';\nimport type { Table } from '@tanstack/react-table';\nimport { Loader2, RefreshCw, Trash2 } from 'lucide-react';\nimport { gql } from '@apollo/client';\nimport { useApolloClient } from '@apollo/client/react';\nimport { toast } from 'sonner';\nimport { Button } from '../ui/primitives/button';\nimport { PermissionTooltip } from '../ui/components/permission-tooltip';\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../ui/primitives/select';\nimport { useDispatch } from '../entities/actions-context';\nimport { useAppContext, useAppDispatch } from '../core/app-context';\nimport { useCanMutate } from '../core/permissions';\nimport { useConfig } from '../core/config/config-context';\nimport { DataTableViewOptions } from './data-table-view-options';\nimport { DataTableSortedBy } from './data-table-sorted-by';\nimport { useEntityMutation } from '../graphql-client/use-entity-mutation';\nimport { getEntityDeleteMutation, getEntityDeleteWhere } from '../graphql-client/queries';\nimport { getEntityListQueryName, scheduleEntityListRemoval } from '../graphql-client/refetch-entity-lists';\nimport { isKnowledgeLinkableEntity } from '../apps/knowledge/knowledge';\n\n// Loaded on demand: the Knowledge module should only download when a list of\n// a linkable entity is in view, the way the record drawer loads its panel.\nconst EntityKnowledgeButton = lazy(() =>\n import('../apps/knowledge/record-links').then((m) => ({ default: m.EntityKnowledgeButton }))\n);\nconst EntityGraphButton = lazy(() => import('../apps/graph/entry').then((m) => ({ default: m.EntityGraphButton })));\n\ninterface DataTableToolbarProps<TData> {\n entityName: string;\n isReloading?: boolean;\n onReload?: () => void;\n table: Table<TData>;\n}\n\nexport function DataTableToolbar<TData>({\n entityName,\n isReloading = false,\n onReload,\n table,\n}: DataTableToolbarProps<TData>): JSX.Element {\n const actionDispatch = useDispatch();\n const appDispatch = useAppDispatch();\n const appContext = useAppContext();\n const apolloClient = useApolloClient();\n const { currentProject, currentProjectId } = useConfig();\n const schema = currentProject?.schema ?? [];\n const scopes = currentProject?.scopes;\n const [runMutation, setMutation, setOptions] = useEntityMutation();\n const [isDeleting, setIsDeleting] = useState(false);\n const canMutate = useCanMutate();\n\n // Collect selected entity ids from the table\n // @ts-expect-error -- the DataGrid's original type doesn't know about the _id property\n const selectedIds: string[] = table.getSelectedRowModel().rows.map((row) => row.original._id as string);\n\n function handleCreate(): void {\n actionDispatch({ type: 'AddEntity', payload: { entityName } });\n }\n\n function handleScopeChange(value: string): void {\n appDispatch({ type: 'setScope', payload: { projectId: currentProjectId, scope: value } });\n }\n\n async function deleteSelected(ids: string[]): Promise<void> {\n if (ids.length === 0) {\n return;\n }\n\n const mutation = getEntityDeleteMutation(entityName, schema, ids);\n\n await new Promise<void>((resolve, reject) => {\n setMutation(gql`\n ${mutation}\n `);\n\n setOptions({\n variables: { where: getEntityDeleteWhere(ids) },\n update(cache: { evict: (arg0: { id: string }) => void }) {\n for (const id of ids) {\n cache.evict({ id });\n }\n },\n onCompleted: () => {\n resolve();\n },\n onError: (error: Error) => {\n reject(error);\n },\n });\n\n runMutation(true);\n });\n }\n\n function handleBatchDelete(): void {\n const itemLabel = entityName === '_asset' ? 'asset' : entityName.toLowerCase();\n\n actionDispatch({\n type: 'AlertDialog',\n payload: {\n options: {\n dialogTitle: `Delete ${selectedIds.length} ${itemLabel}${selectedIds.length > 1 ? 's' : ''}`,\n dialogMessage:\n selectedIds.length > 1\n ? `Are you sure you want to delete the selected ${itemLabel}s? They will be deleted permanently.`\n : `Are you sure you want to delete the selected ${itemLabel}? The item will be deleted permanently.`,\n dialogCancelTitle: 'Cancel',\n dialogActionLabel: 'Delete',\n isDestructive: true,\n dialogActionSubmit: async () => {\n setIsDeleting(true);\n\n try {\n const idsToDelete = [...selectedIds];\n\n await deleteSelected(idsToDelete);\n\n table.resetRowSelection();\n // Drop rows immediately, then soft-refetch counts/pages.\n await scheduleEntityListRemoval(apolloClient, getEntityListQueryName(entityName, schema), idsToDelete);\n toast.success(idsToDelete.length > 1 ? 'Items successfully deleted.' : 'Item successfully deleted.');\n } catch {\n toast.error('Failed to delete selected items.');\n } finally {\n setIsDeleting(false);\n }\n },\n dialogActionCancel: () => {\n // no-op\n },\n },\n },\n });\n }\n\n return (\n <div className=\"fk:flex fk:items-center fk:justify-between\">\n <div className=\"fk:flex fk:flex-1 fk:items-center fk:space-x-2\">\n {scopes && scopes.length > 0 ? (\n <Select\n defaultValue={appContext.scope}\n onValueChange={(value) => {\n handleScopeChange(value);\n }}\n value={appContext.scope}\n >\n <SelectTrigger className=\"fk:w-48!\" id=\"project\" size=\"sm\">\n <span className=\"fk:text-muted-foreground\">Scope:</span>\n <SelectValue>\n {\n ((find(propEq(appContext.scope ?? '', 'name'))(scopes) as { name: string; label: string }) || null)\n ?.label\n }\n </SelectValue>\n </SelectTrigger>\n <SelectContent>\n {scopes.map((scopeItem) => (\n <SelectItem key={scopeItem.name} value={scopeItem.name}>\n {scopeItem.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n ) : null}\n <DataTableViewOptions table={table} />\n {onReload ? (\n <Button\n aria-label=\"Reload\"\n className=\"fk:h-8\"\n disabled={isDeleting || isReloading}\n onClick={onReload}\n size=\"icon-sm\"\n variant=\"outline\"\n >\n <RefreshCw className={isReloading ? 'fk:animate-spin' : undefined} />\n </Button>\n ) : null}\n <DataTableSortedBy table={table} />\n </div>\n {selectedIds.length > 0 ? (\n <PermissionTooltip disabled={!canMutate}>\n <Button\n className=\"fk:h-8 fk:mr-2 fk:lg:flex\"\n disabled={isDeleting || !canMutate}\n onClick={handleBatchDelete}\n size=\"sm\"\n variant=\"destructive\"\n >\n {isDeleting ? (\n <Loader2 className=\"fk:mr-2 fk:h-4 fk:w-4 fk:animate-spin\" />\n ) : (\n <Trash2 className=\"fk:mr-2 fk:h-4 fk:w-4\" />\n )}\n Delete ({selectedIds.length})\n </Button>\n </PermissionTooltip>\n ) : null}\n {entityName && isKnowledgeLinkableEntity(entityName) ? (\n <Suspense fallback={null}>\n <EntityKnowledgeButton entityName={entityName} />\n </Suspense>\n ) : null}\n {entityName ? (\n <Suspense fallback={null}>\n <EntityGraphButton entityName={entityName} selectedIds={selectedIds} />\n </Suspense>\n ) : null}\n <PermissionTooltip disabled={!canMutate}>\n <Button\n className=\"fk:h-8 fk:lg:flex\"\n disabled={isDeleting || !canMutate}\n onClick={handleCreate}\n size=\"sm\"\n variant=\"default\"\n >\n Create\n </Button>\n </PermissionTooltip>\n </div>\n );\n}\n"]}
|