@arbidocs/blocks 0.4.156 → 0.4.158
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/{ConnectedNativeDocxComparison-S25BPUH5.cjs → ConnectedNativeDocxComparison-64RDIFEI.cjs} +8 -8
- package/dist/{ConnectedNativeDocxComparison-S25BPUH5.cjs.map → ConnectedNativeDocxComparison-64RDIFEI.cjs.map} +1 -1
- package/dist/{ConnectedNativeDocxComparison-2PLOOXSH.js → ConnectedNativeDocxComparison-JOWYEINS.js} +7 -7
- package/dist/{ConnectedNativeDocxComparison-2PLOOXSH.js.map → ConnectedNativeDocxComparison-JOWYEINS.js.map} +1 -1
- package/dist/{ConnectedNativeDocxEditor-JJAGMHZC.js → ConnectedNativeDocxEditor-OT5DLWCM.js} +6 -6
- package/dist/{ConnectedNativeDocxEditor-JJAGMHZC.js.map → ConnectedNativeDocxEditor-OT5DLWCM.js.map} +1 -1
- package/dist/{ConnectedNativeDocxEditor-YA4HWLY4.cjs → ConnectedNativeDocxEditor-UAAICR4X.cjs} +8 -8
- package/dist/{ConnectedNativeDocxEditor-YA4HWLY4.cjs.map → ConnectedNativeDocxEditor-UAAICR4X.cjs.map} +1 -1
- package/dist/{ConnectedStreamedWordArtifact-EXYZAU4Y.cjs → ConnectedStreamedWordArtifact-AJXPNTT3.cjs} +8 -8
- package/dist/ConnectedStreamedWordArtifact-AJXPNTT3.cjs.map +1 -0
- package/dist/{ConnectedStreamedWordArtifact-YAAXY5KY.js → ConnectedStreamedWordArtifact-GYBCBAJZ.js} +7 -7
- package/dist/{ConnectedStreamedWordArtifact-YAAXY5KY.js.map → ConnectedStreamedWordArtifact-GYBCBAJZ.js.map} +1 -1
- package/dist/{WorkspaceTableView-ZFMAYHUD.cjs → WorkspaceTableView-CZEFIAVT.cjs} +22 -13
- package/dist/WorkspaceTableView-CZEFIAVT.cjs.map +1 -0
- package/dist/{WorkspaceTableView-5OWX53R5.js → WorkspaceTableView-FQPJQWUE.js} +20 -11
- package/dist/WorkspaceTableView-FQPJQWUE.js.map +1 -0
- package/dist/agents/index.cjs +239 -239
- package/dist/agents/index.js +5 -5
- package/dist/calls/index.cjs +3 -3
- package/dist/calls/index.js +2 -2
- package/dist/{chunk-6HG56GCT.js → chunk-2DQHFJNP.js} +6 -6
- package/dist/{chunk-6HG56GCT.js.map → chunk-2DQHFJNP.js.map} +1 -1
- package/dist/{chunk-6HMCF4AJ.js → chunk-7KWUQQIB.js} +1033 -5
- package/dist/chunk-7KWUQQIB.js.map +1 -0
- package/dist/{chunk-O3FB62T5.cjs → chunk-AUDUNQO6.cjs} +49 -49
- package/dist/{chunk-O3FB62T5.cjs.map → chunk-AUDUNQO6.cjs.map} +1 -1
- package/dist/{chunk-OTU5KGQ6.cjs → chunk-DVIQWBDM.cjs} +4 -4
- package/dist/{chunk-OTU5KGQ6.cjs.map → chunk-DVIQWBDM.cjs.map} +1 -1
- package/dist/{chunk-VHJHY7TT.js → chunk-ECERC6TI.js} +3 -3
- package/dist/{chunk-VHJHY7TT.js.map → chunk-ECERC6TI.js.map} +1 -1
- package/dist/{chunk-HDJRSCRE.cjs → chunk-FBSIWJSG.cjs} +5 -5
- package/dist/{chunk-HDJRSCRE.cjs.map → chunk-FBSIWJSG.cjs.map} +1 -1
- package/dist/{chunk-W7CWGURO.js → chunk-FGI3YFQH.js} +7 -686
- package/dist/chunk-FGI3YFQH.js.map +1 -0
- package/dist/{chunk-WV4TD2HZ.cjs → chunk-FWIBFGUQ.cjs} +1055 -2
- package/dist/chunk-FWIBFGUQ.cjs.map +1 -0
- package/dist/{chunk-7HHYMDPE.js → chunk-GDRLM2EX.js} +3 -3
- package/dist/{chunk-7HHYMDPE.js.map → chunk-GDRLM2EX.js.map} +1 -1
- package/dist/{chunk-S74QMZVZ.cjs → chunk-GWGUZ5X6.cjs} +4 -4
- package/dist/{chunk-S74QMZVZ.cjs.map → chunk-GWGUZ5X6.cjs.map} +1 -1
- package/dist/{chunk-FEGXFABZ.cjs → chunk-LY37J3AC.cjs} +3 -3
- package/dist/{chunk-FEGXFABZ.cjs.map → chunk-LY37J3AC.cjs.map} +1 -1
- package/dist/{chunk-SN2GZ4ZM.cjs → chunk-NFI46I77.cjs} +3 -3
- package/dist/{chunk-SN2GZ4ZM.cjs.map → chunk-NFI46I77.cjs.map} +1 -1
- package/dist/{chunk-PGOSIJ2I.js → chunk-P6FMKXAB.js} +3 -3
- package/dist/{chunk-PGOSIJ2I.js.map → chunk-P6FMKXAB.js.map} +1 -1
- package/dist/{chunk-IJEISII2.cjs → chunk-RJUXSXBH.cjs} +3 -3
- package/dist/{chunk-IJEISII2.cjs.map → chunk-RJUXSXBH.cjs.map} +1 -1
- package/dist/{chunk-53RCZPMR.cjs → chunk-SCK3GAE5.cjs} +5 -5
- package/dist/{chunk-53RCZPMR.cjs.map → chunk-SCK3GAE5.cjs.map} +1 -1
- package/dist/{chunk-UKT3WH5Z.cjs → chunk-TAWPVD6C.cjs} +3 -3
- package/dist/{chunk-UKT3WH5Z.cjs.map → chunk-TAWPVD6C.cjs.map} +1 -1
- package/dist/{chunk-MUDEL7UL.cjs → chunk-UYC5BJCB.cjs} +5 -704
- package/dist/chunk-UYC5BJCB.cjs.map +1 -0
- package/dist/{chunk-2CWM2CFZ.js → chunk-V3HG3LK3.js} +3 -3
- package/dist/{chunk-2CWM2CFZ.js.map → chunk-V3HG3LK3.js.map} +1 -1
- package/dist/{chunk-UPMADXDU.js → chunk-VE6S6NRQ.js} +3 -3
- package/dist/{chunk-UPMADXDU.js.map → chunk-VE6S6NRQ.js.map} +1 -1
- package/dist/{chunk-UKCCV63X.js → chunk-VMFLWFXK.js} +3 -3
- package/dist/{chunk-UKCCV63X.js.map → chunk-VMFLWFXK.js.map} +1 -1
- package/dist/{chunk-HP2C4MD3.js → chunk-Y73X65FF.js} +3 -3
- package/dist/{chunk-HP2C4MD3.js.map → chunk-Y73X65FF.js.map} +1 -1
- package/dist/{chunk-F3EZDBDJ.js → chunk-Y7PPQ7UT.js} +3 -3
- package/dist/{chunk-F3EZDBDJ.js.map → chunk-Y7PPQ7UT.js.map} +1 -1
- package/dist/{chunk-DWZXSPMB.cjs → chunk-ZAVEMQ37.cjs} +3 -3
- package/dist/{chunk-DWZXSPMB.cjs.map → chunk-ZAVEMQ37.cjs.map} +1 -1
- package/dist/{chunk-YMQDDUKW.js → chunk-ZO7PJMCO.js} +3 -3
- package/dist/{chunk-YMQDDUKW.js.map → chunk-ZO7PJMCO.js.map} +1 -1
- package/dist/collaboration/index.cjs +1 -1
- package/dist/collaboration/index.js +1 -1
- package/dist/connect/docx.cjs +10 -10
- package/dist/connect/docx.js +6 -6
- package/dist/connect/index.cjs +1136 -556
- package/dist/connect/index.cjs.map +1 -1
- package/dist/connect/index.js +639 -64
- package/dist/connect/index.js.map +1 -1
- package/dist/connect/viewer.cjs +48 -48
- package/dist/connect/viewer.js +10 -10
- package/dist/connection/files/index.d.ts +5 -0
- package/dist/connection/files/support.d.ts +2 -0
- package/dist/connection/files/upload/AddFromAccountsButton.d.ts +16 -0
- package/dist/connection/files/upload/ConnectedUpload.d.ts +36 -0
- package/dist/connection/files/upload/ConnectedUploadDropzone.d.ts +36 -0
- package/dist/connection/files/upload/EmptyWorkspaceUpload.d.ts +13 -0
- package/dist/connection/files/upload/useAddFromUrls.d.ts +13 -0
- package/dist/connection/workspace-list/ConnectedWorkspaceList.d.ts +4 -2
- package/dist/connection/workspace-list/WorkspaceCardsView.d.ts +3 -2
- package/dist/connection/workspace-list/WorkspaceTableView.d.ts +3 -2
- package/dist/connection/workspace-list/index.d.ts +1 -1
- package/dist/connection/workspace-list/useConnectedWorkspaceList.d.ts +19 -0
- package/dist/connection/workspace-list/workspaceTable.d.ts +3 -1
- package/dist/connection/workspace-settings/ConnectedWorkspaceSettings.d.ts +3 -1
- package/dist/facts/index.cjs +55 -55
- package/dist/facts/index.js +5 -5
- package/dist/files/PrivacyExplainerModal.d.ts +8 -0
- package/dist/files/ShareToggle.d.ts +8 -0
- package/dist/files/UrlInputDialog.d.ts +24 -0
- package/dist/files/index.cjs +314 -294
- package/dist/files/index.d.ts +4 -0
- package/dist/files/index.js +6 -6
- package/dist/files/media-preview.d.ts +24 -0
- package/dist/home/index.cjs +2 -2
- package/dist/home/index.js +2 -2
- package/dist/index.cjs +434 -434
- package/dist/index.js +11 -11
- package/dist/retrieval/index.cjs +1 -1
- package/dist/retrieval/index.js +1 -1
- package/dist/settings/index.cjs +165 -165
- package/dist/settings/index.js +3 -3
- package/dist/shell/index.cjs +3 -3
- package/dist/shell/index.js +3 -3
- package/dist/studio/index.cjs +2 -2
- package/dist/studio/index.js +2 -2
- package/dist/workflow-canvas/index.cjs +17 -17
- package/dist/workflow-canvas/index.js +5 -5
- package/node_modules/@arbidocs/coedit/package.json +1 -1
- package/package.json +5 -5
- package/dist/ConnectedStreamedWordArtifact-EXYZAU4Y.cjs.map +0 -1
- package/dist/WorkspaceTableView-5OWX53R5.js.map +0 -1
- package/dist/WorkspaceTableView-ZFMAYHUD.cjs.map +0 -1
- package/dist/chunk-6HMCF4AJ.js.map +0 -1
- package/dist/chunk-MUDEL7UL.cjs.map +0 -1
- package/dist/chunk-W7CWGURO.js.map +0 -1
- package/dist/chunk-WV4TD2HZ.cjs.map +0 -1
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { LabelPickerList, DEFAULT_LABEL_MULTI_SELECT_LABELS } from './chunk-SDOEHEJP.js';
|
|
3
3
|
import { ActionLink } from './chunk-VF5EUAIV.js';
|
|
4
|
+
import { ModalHeader } from './chunk-TX2ZICS7.js';
|
|
4
5
|
import { TONE_SURFACE } from './chunk-AUS3KBHJ.js';
|
|
5
6
|
import { testIdOr } from './chunk-7F6CBP3Z.js';
|
|
6
7
|
import { formatCount } from './chunk-OXF2IFXG.js';
|
|
7
|
-
import { AlertCircle, CircleSlash, BrainCircuit, LockKeyholeOpen, DatabaseZap, FileX, BookMarked, ListChevronsUpDown, FolderOpen, ChevronsUpDown, Check, Minus, Plus, X, ChevronDown, FolderPlus, UploadCloud, Mail, Folder, LoaderCircle, Sparkles, MoreHorizontal } from 'lucide-react';
|
|
8
|
-
import { cn, Button, Tooltip, TooltipTrigger, Slider, TooltipContent, Popover, PopoverTrigger, PopoverContent, Command, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, getDocumentTitle, getFileExtension, extensionFromMime, getEntityLabel, isAgent, getUserDisplayName, Checkbox, DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuSeparator, DropdownMenuSub, DropdownMenuSubTrigger, DropdownMenuSubContent, DropdownMenuItem } from '@arbidocs/react/ui';
|
|
8
|
+
import { AlertCircle, CircleSlash, BrainCircuit, LockKeyholeOpen, DatabaseZap, FileX, BookMarked, ListChevronsUpDown, FolderOpen, ChevronsUpDown, Check, Minus, Plus, X, ChevronDown, FolderPlus, UploadCloud, Mail, Folder, LoaderCircle, Sparkles, CopyX, Loader2, Upload, FileText, Globe, Link, Info, ChevronRight, ShieldCheck, KeyRound, Eye, MoreHorizontal } from 'lucide-react';
|
|
9
|
+
import { cn, Button, Tooltip, TooltipTrigger, Slider, TooltipContent, Popover, PopoverTrigger, PopoverContent, Command, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, getDocumentTitle, getFileExtension, extensionFromMime, getEntityLabel, isAgent, getUserDisplayName, Progress, IconToggle, Textarea, Dialog, DialogTrigger, DialogContent, DialogTitle, DialogDescription, Label, Input, DialogHeader, VisibilityToggle, Checkbox, DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuSeparator, DropdownMenuSub, DropdownMenuSubTrigger, DropdownMenuSubContent, DropdownMenuItem } from '@arbidocs/react/ui';
|
|
9
10
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
10
11
|
import { forwardRef, memo, useMemo, useState, useRef, useEffect, useCallback } from 'react';
|
|
11
12
|
import { cva } from 'class-variance-authority';
|
|
@@ -1714,7 +1715,1034 @@ function visibilityToggleTooltip(shared) {
|
|
|
1714
1715
|
const workspace = getEntityLabel("WORKSPACE").toLowerCase();
|
|
1715
1716
|
return shared ? `${visibilityAudience(true)}: everyone in it can see this file. Click to make it private to you.` : `${visibilityAudience(false)}: only you can see this file. Click to share it with the ${workspace}.`;
|
|
1716
1717
|
}
|
|
1718
|
+
var DEFAULT_UPLOAD_PARTS_LABELS = {
|
|
1719
|
+
rejectedReasons: {
|
|
1720
|
+
too_large: "The following files exceed the 1 GB size limit:",
|
|
1721
|
+
unsupported: "The following files are not in a supported format (PDF, DOC(X), PPT(X), XLS(X), RTF, TXT, MD, HTML, images, audio, video, email, Outlook archive (.pst/.ost), or ZIP):",
|
|
1722
|
+
empty: "The following files are empty (0 bytes):",
|
|
1723
|
+
no_extension: "The following files have no file extension:",
|
|
1724
|
+
empty_zip: "The following ZIP archives contain no supported files:",
|
|
1725
|
+
zip_error: "The following ZIP archives could not be processed:"
|
|
1726
|
+
},
|
|
1727
|
+
rejectedFallback: "The following files cannot be uploaded:",
|
|
1728
|
+
clearRejected: "Clear rejected files",
|
|
1729
|
+
selectedFiles: (count) => `Selected Files (${count})`,
|
|
1730
|
+
total: (size) => `Total: ${size}`,
|
|
1731
|
+
clearAll: "Clear All",
|
|
1732
|
+
remove: (fileName) => `Remove ${fileName}`,
|
|
1733
|
+
uploadComplete: (entity) => `Upload complete! Processing ${entity} in the background...`,
|
|
1734
|
+
uploading: (count, entity) => `Uploading ${count} ${entity}...`,
|
|
1735
|
+
uploadedIndexing: "Files uploaded successfully. ARBI is now indexing them in the background.",
|
|
1736
|
+
afterUpload: "After upload completes, ARBI will index files in the background."
|
|
1737
|
+
};
|
|
1738
|
+
function mergeUploadLabels(labels) {
|
|
1739
|
+
return {
|
|
1740
|
+
...DEFAULT_UPLOAD_PARTS_LABELS,
|
|
1741
|
+
...labels,
|
|
1742
|
+
rejectedReasons: {
|
|
1743
|
+
...DEFAULT_UPLOAD_PARTS_LABELS.rejectedReasons,
|
|
1744
|
+
...labels?.rejectedReasons
|
|
1745
|
+
}
|
|
1746
|
+
};
|
|
1747
|
+
}
|
|
1748
|
+
function UploadErrorMessage({
|
|
1749
|
+
message,
|
|
1750
|
+
className,
|
|
1751
|
+
testId
|
|
1752
|
+
}) {
|
|
1753
|
+
return /* @__PURE__ */ jsxs(
|
|
1754
|
+
"div",
|
|
1755
|
+
{
|
|
1756
|
+
role: "alert",
|
|
1757
|
+
className: cn("mt-6 flex items-center gap-2 rounded-lg bg-red-bg p-3", className),
|
|
1758
|
+
"data-testid": testIdOr(testId, { testId: "error-message" }),
|
|
1759
|
+
children: [
|
|
1760
|
+
/* @__PURE__ */ jsx(AlertCircle, { className: "size-5 shrink-0 text-red-text" }),
|
|
1761
|
+
/* @__PURE__ */ jsx("p", { className: "text-base text-red-text", children: message })
|
|
1762
|
+
]
|
|
1763
|
+
}
|
|
1764
|
+
);
|
|
1765
|
+
}
|
|
1766
|
+
function RejectedFilesList({ files, onClear, labels, testIds }) {
|
|
1767
|
+
if (files.length === 0) return null;
|
|
1768
|
+
const l = mergeUploadLabels(labels);
|
|
1769
|
+
const byReason = /* @__PURE__ */ new Map();
|
|
1770
|
+
for (const file of files) {
|
|
1771
|
+
const reason = typeof file === "string" ? "unsupported" : file.reason || "unsupported";
|
|
1772
|
+
const name = typeof file === "string" ? file : file.name;
|
|
1773
|
+
byReason.set(reason, [...byReason.get(reason) ?? [], name]);
|
|
1774
|
+
}
|
|
1775
|
+
return /* @__PURE__ */ jsx(
|
|
1776
|
+
"div",
|
|
1777
|
+
{
|
|
1778
|
+
className: "mt-4 rounded-lg bg-red-bg p-3",
|
|
1779
|
+
"data-testid": testIdOr(testIds?.root, { testId: "rejected-files-list" }),
|
|
1780
|
+
children: /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2", children: [
|
|
1781
|
+
/* @__PURE__ */ jsx(AlertCircle, { className: "mt-0.5 size-5 shrink-0 text-red-text" }),
|
|
1782
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1", children: Array.from(byReason.entries()).map(([reason, names], groupIndex) => /* @__PURE__ */ jsxs("div", { className: groupIndex > 0 ? "mt-3" : "", children: [
|
|
1783
|
+
/* @__PURE__ */ jsx("p", { className: "mb-2 text-sm font-medium text-red-text", children: l.rejectedReasons[reason] ?? l.rejectedFallback }),
|
|
1784
|
+
/* @__PURE__ */ jsx("div", { className: "space-y-1", children: names.map((name, index) => /* @__PURE__ */ jsx(
|
|
1785
|
+
"div",
|
|
1786
|
+
{
|
|
1787
|
+
className: "rounded-md bg-background/60 p-2",
|
|
1788
|
+
"data-testid": testIdOr(testIds?.item?.(groupIndex, index), {
|
|
1789
|
+
testId: `rejected-file-item-${groupIndex}-${index}`
|
|
1790
|
+
}),
|
|
1791
|
+
children: /* @__PURE__ */ jsx("span", { className: "text-sm text-red-text", children: name })
|
|
1792
|
+
},
|
|
1793
|
+
index
|
|
1794
|
+
)) })
|
|
1795
|
+
] }, reason)) }),
|
|
1796
|
+
/* @__PURE__ */ jsx(
|
|
1797
|
+
Button,
|
|
1798
|
+
{
|
|
1799
|
+
variant: "ghost",
|
|
1800
|
+
size: "icon",
|
|
1801
|
+
onClick: onClear,
|
|
1802
|
+
"aria-label": l.clearRejected,
|
|
1803
|
+
className: "size-6 text-red-text hover:text-red-text pointer-coarse:size-11",
|
|
1804
|
+
"data-testid": testIdOr(testIds?.clear, { testId: "clear-rejected-files-button" }),
|
|
1805
|
+
children: /* @__PURE__ */ jsx(X, { className: "size-4" })
|
|
1806
|
+
}
|
|
1807
|
+
)
|
|
1808
|
+
] })
|
|
1809
|
+
}
|
|
1810
|
+
);
|
|
1811
|
+
}
|
|
1812
|
+
function folderPathOf(file) {
|
|
1813
|
+
const rel = file.webkitRelativePath;
|
|
1814
|
+
if (!rel) return null;
|
|
1815
|
+
const slash = rel.lastIndexOf("/");
|
|
1816
|
+
return slash > 0 ? rel.substring(0, slash) : null;
|
|
1817
|
+
}
|
|
1818
|
+
function SelectedFilesList({
|
|
1819
|
+
files,
|
|
1820
|
+
onRemoveFile,
|
|
1821
|
+
onClearAll,
|
|
1822
|
+
formatFileSize,
|
|
1823
|
+
renderFileIcon,
|
|
1824
|
+
labels,
|
|
1825
|
+
testIds
|
|
1826
|
+
}) {
|
|
1827
|
+
if (files.length === 0) return null;
|
|
1828
|
+
const l = mergeUploadLabels(labels);
|
|
1829
|
+
const total = files.reduce((sum, f) => sum + f.size, 0);
|
|
1830
|
+
return /* @__PURE__ */ jsxs(
|
|
1831
|
+
"div",
|
|
1832
|
+
{
|
|
1833
|
+
className: "mt-2 sm:mt-6",
|
|
1834
|
+
"data-testid": testIdOr(testIds?.root, { testId: "selected-files-list" }),
|
|
1835
|
+
children: [
|
|
1836
|
+
/* @__PURE__ */ jsxs("div", { className: "mb-2 flex items-center justify-between gap-3", children: [
|
|
1837
|
+
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col sm:flex-row sm:items-center sm:gap-4", children: [
|
|
1838
|
+
/* @__PURE__ */ jsx("h4", { className: "text-base font-medium", children: l.selectedFiles(files.length) }),
|
|
1839
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: l.total(formatFileSize(total)) })
|
|
1840
|
+
] }),
|
|
1841
|
+
onClearAll && /* @__PURE__ */ jsxs(
|
|
1842
|
+
Button,
|
|
1843
|
+
{
|
|
1844
|
+
variant: "ghost",
|
|
1845
|
+
size: "sm",
|
|
1846
|
+
onClick: onClearAll,
|
|
1847
|
+
className: "h-8 shrink-0 whitespace-nowrap text-muted-foreground hover:text-foreground pointer-coarse:h-11",
|
|
1848
|
+
"data-testid": testIdOr(testIds?.clearAll, { testId: "clear-all-files-button" }),
|
|
1849
|
+
children: [
|
|
1850
|
+
l.clearAll,
|
|
1851
|
+
/* @__PURE__ */ jsx(X, { className: "ml-1 hidden size-4 sm:block" })
|
|
1852
|
+
]
|
|
1853
|
+
}
|
|
1854
|
+
)
|
|
1855
|
+
] }),
|
|
1856
|
+
/* @__PURE__ */ jsx("div", { className: "space-y-1 overflow-y-auto overscroll-contain pr-1 sm:max-h-[300px]", children: files.map((file, index) => {
|
|
1857
|
+
const folder = folderPathOf(file);
|
|
1858
|
+
return /* @__PURE__ */ jsxs(
|
|
1859
|
+
"div",
|
|
1860
|
+
{
|
|
1861
|
+
className: "flex min-w-0 items-center gap-2 rounded-lg bg-muted p-3",
|
|
1862
|
+
"data-testid": testIdOr(testIds?.item?.(index), {
|
|
1863
|
+
testId: `selected-file-item-${index}`
|
|
1864
|
+
}),
|
|
1865
|
+
children: [
|
|
1866
|
+
/* @__PURE__ */ jsx("div", { className: "shrink-0", children: renderFileIcon(file.name) }),
|
|
1867
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
1868
|
+
/* @__PURE__ */ jsx("span", { className: "block truncate text-base", title: file.name, children: file.name }),
|
|
1869
|
+
folder && /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-sm text-muted-foreground", children: [
|
|
1870
|
+
/* @__PURE__ */ jsx(FolderOpen, { className: "size-3" }),
|
|
1871
|
+
folder
|
|
1872
|
+
] })
|
|
1873
|
+
] }),
|
|
1874
|
+
/* @__PURE__ */ jsx(
|
|
1875
|
+
Button,
|
|
1876
|
+
{
|
|
1877
|
+
variant: "ghost",
|
|
1878
|
+
size: "icon",
|
|
1879
|
+
onClick: () => onRemoveFile(index),
|
|
1880
|
+
"aria-label": l.remove(file.name),
|
|
1881
|
+
className: "size-6 shrink-0 pointer-coarse:size-11",
|
|
1882
|
+
"data-testid": testIdOr(testIds?.remove?.(index), {
|
|
1883
|
+
testId: `remove-file-button-${index}`
|
|
1884
|
+
}),
|
|
1885
|
+
children: /* @__PURE__ */ jsx(X, { className: "size-4" })
|
|
1886
|
+
}
|
|
1887
|
+
)
|
|
1888
|
+
]
|
|
1889
|
+
},
|
|
1890
|
+
index
|
|
1891
|
+
);
|
|
1892
|
+
}) })
|
|
1893
|
+
]
|
|
1894
|
+
}
|
|
1895
|
+
);
|
|
1896
|
+
}
|
|
1897
|
+
function UploadProgress({
|
|
1898
|
+
fileCount,
|
|
1899
|
+
entityLabel,
|
|
1900
|
+
percentage,
|
|
1901
|
+
batchInfo,
|
|
1902
|
+
labels,
|
|
1903
|
+
testId
|
|
1904
|
+
}) {
|
|
1905
|
+
const l = mergeUploadLabels(labels);
|
|
1906
|
+
const isComplete = percentage >= 100;
|
|
1907
|
+
return /* @__PURE__ */ jsxs("div", { className: "text-center", "data-testid": testIdOr(testId, { testId: "upload-progress" }), children: [
|
|
1908
|
+
/* @__PURE__ */ jsx("h3", { className: "mb-2 text-lg font-medium", children: isComplete ? l.uploadComplete(entityLabel) : l.uploading(fileCount, entityLabel) }),
|
|
1909
|
+
/* @__PURE__ */ jsxs("div", { className: "mx-auto mb-4 max-w-md", children: [
|
|
1910
|
+
/* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
1911
|
+
/* @__PURE__ */ jsx(Progress, { value: percentage, className: "h-3" }),
|
|
1912
|
+
batchInfo && batchInfo.total > 1 && /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-0", "aria-hidden": "true", children: Array.from({ length: batchInfo.total - 1 }, (_, i) => /* @__PURE__ */ jsx(
|
|
1913
|
+
"span",
|
|
1914
|
+
{
|
|
1915
|
+
className: "absolute top-0 h-full w-px bg-background/50",
|
|
1916
|
+
style: { left: `${(i + 1) / batchInfo.total * 100}%` }
|
|
1917
|
+
},
|
|
1918
|
+
i
|
|
1919
|
+
)) })
|
|
1920
|
+
] }),
|
|
1921
|
+
/* @__PURE__ */ jsx("div", { className: "mt-2 flex items-center justify-center text-sm text-muted-foreground", children: /* @__PURE__ */ jsxs("span", { children: [
|
|
1922
|
+
Math.round(percentage),
|
|
1923
|
+
"%"
|
|
1924
|
+
] }) })
|
|
1925
|
+
] }),
|
|
1926
|
+
/* @__PURE__ */ jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: isComplete ? l.uploadedIndexing : l.afterUpload })
|
|
1927
|
+
] });
|
|
1928
|
+
}
|
|
1929
|
+
var DEFAULT_UPLOAD_FOOTER_LABELS = {
|
|
1930
|
+
skipDuplicates: "Skip duplicates",
|
|
1931
|
+
skipDuplicatesActive: "Skip identical files already in the workspace",
|
|
1932
|
+
skipDuplicatesInactive: "Allow uploading identical files",
|
|
1933
|
+
autoRename: "Auto-rename",
|
|
1934
|
+
autoRenameActive: "Generate a descriptive title via AI instead of using the filename",
|
|
1935
|
+
autoRenameInactive: "Keep the original filename",
|
|
1936
|
+
titleInstruction: "Title instruction",
|
|
1937
|
+
titleInstructionPlaceholder: "Optional: how should AI name these documents?"
|
|
1938
|
+
};
|
|
1939
|
+
function UploadContainer({
|
|
1940
|
+
children,
|
|
1941
|
+
className = "p-4 sm:p-6",
|
|
1942
|
+
testId
|
|
1943
|
+
}) {
|
|
1944
|
+
return /* @__PURE__ */ jsx(
|
|
1945
|
+
"div",
|
|
1946
|
+
{
|
|
1947
|
+
className,
|
|
1948
|
+
"data-slot": "upload-container",
|
|
1949
|
+
"data-testid": testIdOr(testId, { testId: "upload-container" }),
|
|
1950
|
+
children
|
|
1951
|
+
}
|
|
1952
|
+
);
|
|
1953
|
+
}
|
|
1954
|
+
function UploadShareNote({
|
|
1955
|
+
description,
|
|
1956
|
+
children,
|
|
1957
|
+
compact = false,
|
|
1958
|
+
testId
|
|
1959
|
+
}) {
|
|
1960
|
+
const id = testIdOr(testId, { testId: "share-toggle" });
|
|
1961
|
+
if (compact) {
|
|
1962
|
+
return /* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
1963
|
+
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx("div", { "data-testid": id, children }) }),
|
|
1964
|
+
/* @__PURE__ */ jsx(TooltipContent, { side: "top", className: "max-w-xs", children: /* @__PURE__ */ jsx("p", { className: "text-sm", children: description }) })
|
|
1965
|
+
] });
|
|
1966
|
+
}
|
|
1967
|
+
return /* @__PURE__ */ jsx("div", { className: "rounded-lg bg-muted p-4", "data-testid": id, children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
|
|
1968
|
+
children,
|
|
1969
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: description })
|
|
1970
|
+
] }) });
|
|
1971
|
+
}
|
|
1972
|
+
var TOGGLE_COLORS = { text: "text-primary", bg: "bg-primary" };
|
|
1973
|
+
function UploadFooterBar({
|
|
1974
|
+
skipDuplicates,
|
|
1975
|
+
onSkipDuplicatesChange,
|
|
1976
|
+
autoRename,
|
|
1977
|
+
onAutoRenameChange,
|
|
1978
|
+
autoRenameInstruction,
|
|
1979
|
+
onAutoRenameInstructionChange,
|
|
1980
|
+
shareToggle,
|
|
1981
|
+
children,
|
|
1982
|
+
className,
|
|
1983
|
+
labels,
|
|
1984
|
+
testIds
|
|
1985
|
+
}) {
|
|
1986
|
+
const l = { ...DEFAULT_UPLOAD_FOOTER_LABELS, ...labels };
|
|
1987
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1988
|
+
/* @__PURE__ */ jsxs(
|
|
1989
|
+
"div",
|
|
1990
|
+
{
|
|
1991
|
+
className: cn(
|
|
1992
|
+
"flex shrink-0 flex-wrap items-center gap-x-3 gap-y-2 border-t border-border bg-background px-4 py-3 sm:px-6",
|
|
1993
|
+
className
|
|
1994
|
+
),
|
|
1995
|
+
"data-testid": testIdOr(testIds?.bar, { testId: "upload-footer-bar" }),
|
|
1996
|
+
children: [
|
|
1997
|
+
/* @__PURE__ */ jsx(
|
|
1998
|
+
IconToggle,
|
|
1999
|
+
{
|
|
2000
|
+
icon: CopyX,
|
|
2001
|
+
isActive: skipDuplicates,
|
|
2002
|
+
onToggle: onSkipDuplicatesChange,
|
|
2003
|
+
colors: TOGGLE_COLORS,
|
|
2004
|
+
showLabel: true,
|
|
2005
|
+
label: l.skipDuplicates,
|
|
2006
|
+
tooltipActive: l.skipDuplicatesActive,
|
|
2007
|
+
tooltipInactive: l.skipDuplicatesInactive,
|
|
2008
|
+
"data-testid": testIdOr(testIds?.skipDuplicates, { testId: "toggle-skip-duplicates" })
|
|
2009
|
+
}
|
|
2010
|
+
),
|
|
2011
|
+
/* @__PURE__ */ jsx(
|
|
2012
|
+
IconToggle,
|
|
2013
|
+
{
|
|
2014
|
+
icon: Sparkles,
|
|
2015
|
+
isActive: autoRename,
|
|
2016
|
+
onToggle: onAutoRenameChange,
|
|
2017
|
+
colors: TOGGLE_COLORS,
|
|
2018
|
+
showLabel: true,
|
|
2019
|
+
label: l.autoRename,
|
|
2020
|
+
tooltipActive: l.autoRenameActive,
|
|
2021
|
+
tooltipInactive: l.autoRenameInactive,
|
|
2022
|
+
"data-testid": testIdOr(testIds?.autoRename, { testId: "toggle-auto-rename" })
|
|
2023
|
+
}
|
|
2024
|
+
),
|
|
2025
|
+
/* @__PURE__ */ jsx("div", { className: "hidden flex-1 sm:block" }),
|
|
2026
|
+
shareToggle,
|
|
2027
|
+
/* @__PURE__ */ jsx("div", { className: "w-full sm:w-auto max-sm:[&>button]:w-full", children })
|
|
2028
|
+
]
|
|
2029
|
+
}
|
|
2030
|
+
),
|
|
2031
|
+
autoRename && /* @__PURE__ */ jsxs(
|
|
2032
|
+
"div",
|
|
2033
|
+
{
|
|
2034
|
+
className: "shrink-0 border-t border-border bg-background px-4 py-3 sm:px-6",
|
|
2035
|
+
"data-testid": testIdOr(testIds?.settingsPanel, { testId: "upload-settings-panel" }),
|
|
2036
|
+
children: [
|
|
2037
|
+
/* @__PURE__ */ jsx("label", { htmlFor: "auto-rename-instruction", className: "text-sm font-medium", children: l.titleInstruction }),
|
|
2038
|
+
/* @__PURE__ */ jsx(
|
|
2039
|
+
Textarea,
|
|
2040
|
+
{
|
|
2041
|
+
id: "auto-rename-instruction",
|
|
2042
|
+
value: autoRenameInstruction,
|
|
2043
|
+
onChange: (e) => onAutoRenameInstructionChange(e.target.value),
|
|
2044
|
+
placeholder: l.titleInstructionPlaceholder,
|
|
2045
|
+
className: "mt-1 min-h-[60px] text-sm",
|
|
2046
|
+
"data-testid": testIdOr(testIds?.instruction, { testId: "auto-rename-instruction" })
|
|
2047
|
+
}
|
|
2048
|
+
)
|
|
2049
|
+
]
|
|
2050
|
+
}
|
|
2051
|
+
)
|
|
2052
|
+
] });
|
|
2053
|
+
}
|
|
2054
|
+
function ShareToggle({
|
|
2055
|
+
isVisible,
|
|
2056
|
+
onToggle,
|
|
2057
|
+
workspaceEntityLabel,
|
|
2058
|
+
compact = false
|
|
2059
|
+
}) {
|
|
2060
|
+
const doc = getEntityLabel("DOCUMENT", "PLURAL").toLowerCase();
|
|
2061
|
+
const workspace = workspaceEntityLabel.toLowerCase();
|
|
2062
|
+
const description = isVisible ? `Uploaded ${doc} will be shared with this ${workspace} \u2014 everyone in it, now and in the future.` : `Uploaded ${doc} stay private to you \u2014 not shared with this ${workspace}. You can change this later.`;
|
|
2063
|
+
const audience = visibilityAudience(isVisible, workspaceEntityLabel);
|
|
2064
|
+
const toggle = /* @__PURE__ */ jsx(
|
|
2065
|
+
VisibilityToggle,
|
|
2066
|
+
{
|
|
2067
|
+
items: { shared: isVisible },
|
|
2068
|
+
onToggle,
|
|
2069
|
+
showLabel: true,
|
|
2070
|
+
label: audience,
|
|
2071
|
+
showTooltip: false
|
|
2072
|
+
}
|
|
2073
|
+
);
|
|
2074
|
+
if (compact) {
|
|
2075
|
+
const summary = isVisible ? `Everyone in this ${workspace} can see uploaded ${doc}.` : `Only you can see uploaded ${doc}.`;
|
|
2076
|
+
return /* @__PURE__ */ jsxs("div", { "data-testid": "share-toggle", className: "flex max-w-[15rem] flex-col items-end gap-1", children: [
|
|
2077
|
+
toggle,
|
|
2078
|
+
/* @__PURE__ */ jsx("p", { className: "text-right text-xs text-muted-foreground", children: summary })
|
|
2079
|
+
] });
|
|
2080
|
+
}
|
|
2081
|
+
return /* @__PURE__ */ jsx(UploadShareNote, { description, compact: false, children: toggle });
|
|
2082
|
+
}
|
|
2083
|
+
var DEFAULT_UPLOAD_SOURCES_LABELS = {
|
|
2084
|
+
uploadFiles: "Choose files",
|
|
2085
|
+
uploadFolder: "Choose a folder"
|
|
2086
|
+
};
|
|
2087
|
+
function UploadFrame({ isCompact, isDimmed, className, children }) {
|
|
2088
|
+
return /* @__PURE__ */ jsx(
|
|
2089
|
+
"div",
|
|
2090
|
+
{
|
|
2091
|
+
"data-slot": "upload-frame",
|
|
2092
|
+
className: cn(
|
|
2093
|
+
"relative flex w-full flex-col items-center",
|
|
2094
|
+
isCompact ? "gap-4" : "gap-6",
|
|
2095
|
+
isDimmed && "opacity-50",
|
|
2096
|
+
className
|
|
2097
|
+
),
|
|
2098
|
+
children
|
|
2099
|
+
}
|
|
2100
|
+
);
|
|
2101
|
+
}
|
|
2102
|
+
function UploadDropArea({
|
|
2103
|
+
isActive,
|
|
2104
|
+
isDisabled,
|
|
2105
|
+
isProcessing,
|
|
2106
|
+
processingMessage,
|
|
2107
|
+
isCompact,
|
|
2108
|
+
title,
|
|
2109
|
+
subtitle,
|
|
2110
|
+
onDrag,
|
|
2111
|
+
onDrop,
|
|
2112
|
+
onClick,
|
|
2113
|
+
actions,
|
|
2114
|
+
testId = "upload-dropzone-area"
|
|
2115
|
+
}) {
|
|
2116
|
+
const active = isActive && !isDisabled;
|
|
2117
|
+
return /* @__PURE__ */ jsxs(
|
|
2118
|
+
"div",
|
|
2119
|
+
{
|
|
2120
|
+
"data-slot": "upload-drop-area",
|
|
2121
|
+
"data-testid": testId,
|
|
2122
|
+
onDragEnter: onDrag,
|
|
2123
|
+
onDragLeave: onDrag,
|
|
2124
|
+
onDragOver: onDrag,
|
|
2125
|
+
onDrop,
|
|
2126
|
+
onClick,
|
|
2127
|
+
className: cn(
|
|
2128
|
+
"relative flex w-full flex-col items-center justify-center rounded-lg border text-center transition-colors",
|
|
2129
|
+
active ? "border-dashed border-primary bg-accent" : "border-border bg-card shadow-xs hover:border-ring/50 hover:bg-accent/40",
|
|
2130
|
+
isDisabled || isProcessing ? "cursor-not-allowed" : "cursor-pointer",
|
|
2131
|
+
isCompact ? "min-h-[150px] p-4" : "min-h-[200px] p-5",
|
|
2132
|
+
// Touch screens cannot drag files in: the area stays in the DOM (assistive tech, e2e) but
|
|
2133
|
+
// the "Choose files / folder" buttons are the whole affordance.
|
|
2134
|
+
"pointer-coarse:sr-only"
|
|
2135
|
+
),
|
|
2136
|
+
children: [
|
|
2137
|
+
isProcessing && /* @__PURE__ */ jsxs(
|
|
2138
|
+
"div",
|
|
2139
|
+
{
|
|
2140
|
+
role: "status",
|
|
2141
|
+
className: "absolute inset-0 z-10 flex flex-col items-center justify-center rounded-lg bg-background/80",
|
|
2142
|
+
children: [
|
|
2143
|
+
/* @__PURE__ */ jsx(Loader2, { className: "mb-3 size-8 animate-spin text-primary" }),
|
|
2144
|
+
/* @__PURE__ */ jsx("div", { className: "progress-bar-processing mb-3 h-1.5 w-48 rounded-sm" }),
|
|
2145
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: processingMessage })
|
|
2146
|
+
]
|
|
2147
|
+
}
|
|
2148
|
+
),
|
|
2149
|
+
/* @__PURE__ */ jsx(
|
|
2150
|
+
"div",
|
|
2151
|
+
{
|
|
2152
|
+
className: cn(
|
|
2153
|
+
"mb-2 flex items-center justify-center rounded-full bg-muted text-muted-foreground",
|
|
2154
|
+
isCompact ? "size-11" : "size-10",
|
|
2155
|
+
active && "bg-primary/10 text-primary"
|
|
2156
|
+
),
|
|
2157
|
+
children: /* @__PURE__ */ jsx(Upload, { className: "size-5" })
|
|
2158
|
+
}
|
|
2159
|
+
),
|
|
2160
|
+
/* @__PURE__ */ jsx("h4", { className: "text-sm font-semibold text-foreground", children: title }),
|
|
2161
|
+
subtitle && /* @__PURE__ */ jsx("p", { className: "mt-1 max-w-sm text-sm text-muted-foreground", children: subtitle }),
|
|
2162
|
+
actions
|
|
2163
|
+
]
|
|
2164
|
+
}
|
|
2165
|
+
);
|
|
2166
|
+
}
|
|
2167
|
+
function UploadBrowseButtons({
|
|
2168
|
+
onFiles,
|
|
2169
|
+
onFolder,
|
|
2170
|
+
isDisabled,
|
|
2171
|
+
layout = "inline",
|
|
2172
|
+
labels
|
|
2173
|
+
}) {
|
|
2174
|
+
const l = { ...DEFAULT_UPLOAD_SOURCES_LABELS, ...labels };
|
|
2175
|
+
const isInline = layout === "inline";
|
|
2176
|
+
const size = isInline ? "sm" : "default";
|
|
2177
|
+
const width = isInline ? void 0 : "w-full";
|
|
2178
|
+
return /* @__PURE__ */ jsxs(
|
|
2179
|
+
"div",
|
|
2180
|
+
{
|
|
2181
|
+
"data-slot": "upload-browse-buttons",
|
|
2182
|
+
className: isInline ? "mt-3 flex flex-wrap items-center justify-center gap-2" : "grid grid-cols-1 gap-2 sm:grid-cols-2",
|
|
2183
|
+
children: [
|
|
2184
|
+
/* @__PURE__ */ jsxs(
|
|
2185
|
+
Button,
|
|
2186
|
+
{
|
|
2187
|
+
variant: isInline ? "outline" : "default",
|
|
2188
|
+
size,
|
|
2189
|
+
className: width,
|
|
2190
|
+
onClick: onFiles,
|
|
2191
|
+
disabled: isDisabled,
|
|
2192
|
+
"data-testid": "upload-files-button",
|
|
2193
|
+
children: [
|
|
2194
|
+
/* @__PURE__ */ jsx(FileText, { className: "mr-2 size-4" }),
|
|
2195
|
+
l.uploadFiles
|
|
2196
|
+
]
|
|
2197
|
+
}
|
|
2198
|
+
),
|
|
2199
|
+
/* @__PURE__ */ jsxs(
|
|
2200
|
+
Button,
|
|
2201
|
+
{
|
|
2202
|
+
variant: "outline",
|
|
2203
|
+
size,
|
|
2204
|
+
className: width,
|
|
2205
|
+
onClick: onFolder,
|
|
2206
|
+
disabled: isDisabled,
|
|
2207
|
+
"data-testid": "upload-folder-button",
|
|
2208
|
+
children: [
|
|
2209
|
+
/* @__PURE__ */ jsx(FolderPlus, { className: "mr-2 size-4" }),
|
|
2210
|
+
l.uploadFolder
|
|
2211
|
+
]
|
|
2212
|
+
}
|
|
2213
|
+
)
|
|
2214
|
+
]
|
|
2215
|
+
}
|
|
2216
|
+
);
|
|
2217
|
+
}
|
|
2218
|
+
function UploadSourcePicker({ options, isDisabled }) {
|
|
2219
|
+
return /* @__PURE__ */ jsx(
|
|
2220
|
+
"div",
|
|
2221
|
+
{
|
|
2222
|
+
"data-slot": "upload-source-picker",
|
|
2223
|
+
className: "flex w-full flex-col gap-2",
|
|
2224
|
+
"data-testid": "upload-source-picker",
|
|
2225
|
+
children: options.map((o) => {
|
|
2226
|
+
const button = /* @__PURE__ */ jsxs(
|
|
2227
|
+
Button,
|
|
2228
|
+
{
|
|
2229
|
+
variant: "outline",
|
|
2230
|
+
onClick: o.onClick,
|
|
2231
|
+
disabled: isDisabled,
|
|
2232
|
+
"data-testid": `upload-source-pick-${o.key}`,
|
|
2233
|
+
className: "h-auto w-full justify-start gap-3 px-4 py-3 text-left",
|
|
2234
|
+
children: [
|
|
2235
|
+
/* @__PURE__ */ jsx("span", { className: "shrink-0 text-muted-foreground [&_svg]:size-5", children: o.icon }),
|
|
2236
|
+
/* @__PURE__ */ jsxs("span", { className: "flex flex-col", children: [
|
|
2237
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium", children: o.label }),
|
|
2238
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs font-normal text-muted-foreground", children: o.description })
|
|
2239
|
+
] })
|
|
2240
|
+
]
|
|
2241
|
+
}
|
|
2242
|
+
);
|
|
2243
|
+
return /* @__PURE__ */ jsx("span", { className: "contents", children: o.wrap ? o.wrap(button) : button }, o.key);
|
|
2244
|
+
})
|
|
2245
|
+
}
|
|
2246
|
+
);
|
|
2247
|
+
}
|
|
2248
|
+
function UploadUrlButton({
|
|
2249
|
+
isCompact,
|
|
2250
|
+
isDisabled,
|
|
2251
|
+
label = "Add from URL",
|
|
2252
|
+
onClick
|
|
2253
|
+
}) {
|
|
2254
|
+
return /* @__PURE__ */ jsxs(
|
|
2255
|
+
Button,
|
|
2256
|
+
{
|
|
2257
|
+
variant: "outline",
|
|
2258
|
+
size: isCompact ? "sm" : "default",
|
|
2259
|
+
disabled: isDisabled,
|
|
2260
|
+
onClick,
|
|
2261
|
+
"data-testid": "upload-url-button",
|
|
2262
|
+
children: [
|
|
2263
|
+
/* @__PURE__ */ jsx(Globe, { className: "mr-2 size-4" }),
|
|
2264
|
+
label
|
|
2265
|
+
]
|
|
2266
|
+
}
|
|
2267
|
+
);
|
|
2268
|
+
}
|
|
2269
|
+
function UploadSourceSection({
|
|
2270
|
+
testId,
|
|
2271
|
+
className,
|
|
2272
|
+
isIsolated,
|
|
2273
|
+
children
|
|
2274
|
+
}) {
|
|
2275
|
+
return /* @__PURE__ */ jsx(
|
|
2276
|
+
"div",
|
|
2277
|
+
{
|
|
2278
|
+
"data-slot": "upload-source-section",
|
|
2279
|
+
"data-testid": testId,
|
|
2280
|
+
className,
|
|
2281
|
+
onClick: isIsolated ? (e) => e.stopPropagation() : void 0,
|
|
2282
|
+
children
|
|
2283
|
+
}
|
|
2284
|
+
);
|
|
2285
|
+
}
|
|
2286
|
+
var DEFAULT_URL_INPUT_DIALOG_LABELS = {
|
|
2287
|
+
title: "Add from the internet",
|
|
2288
|
+
description: "Enter one or more URLs to download documents \u2014 paste several separated by commas or new lines.",
|
|
2289
|
+
supports: "Supports PDF, Word, PowerPoint, Excel, RTF, TXT, MD, HTML, ZIP, and audio/video links (YouTube et al.).",
|
|
2290
|
+
url: (position) => position === null ? "URL " : `URL ${position}`,
|
|
2291
|
+
placeholder: "https://example.com/document.pdf or a YouTube / audio / video link",
|
|
2292
|
+
removeUrl: (position) => `Remove URL ${position}`,
|
|
2293
|
+
addAnother: "Add Another URL",
|
|
2294
|
+
adding: "Adding\u2026",
|
|
2295
|
+
addDocuments: "Add Documents",
|
|
2296
|
+
mediaPreview: "Media preview"
|
|
2297
|
+
};
|
|
2298
|
+
function UrlInputDialogView({
|
|
2299
|
+
open,
|
|
2300
|
+
onOpenChange,
|
|
2301
|
+
trigger,
|
|
2302
|
+
title,
|
|
2303
|
+
urls,
|
|
2304
|
+
errors,
|
|
2305
|
+
onUrlChange,
|
|
2306
|
+
onUrlPaste,
|
|
2307
|
+
onAddUrl,
|
|
2308
|
+
onRemoveUrl,
|
|
2309
|
+
renderPreview,
|
|
2310
|
+
submitError,
|
|
2311
|
+
isSubmitting,
|
|
2312
|
+
onSubmit,
|
|
2313
|
+
labels,
|
|
2314
|
+
testIds
|
|
2315
|
+
}) {
|
|
2316
|
+
const l = { ...DEFAULT_URL_INPUT_DIALOG_LABELS, ...labels };
|
|
2317
|
+
return /* @__PURE__ */ jsxs(Dialog, { open, onOpenChange, children: [
|
|
2318
|
+
trigger !== void 0 && /* @__PURE__ */ jsx(DialogTrigger, { asChild: true, children: trigger }),
|
|
2319
|
+
/* @__PURE__ */ jsxs(
|
|
2320
|
+
DialogContent,
|
|
2321
|
+
{
|
|
2322
|
+
presentation: "sheet",
|
|
2323
|
+
className: "flex flex-col gap-0 overflow-hidden p-0 sm:max-w-[525px]",
|
|
2324
|
+
"data-testid": testIdOr(testIds?.modal, { testId: "upload-modal-internet" }),
|
|
2325
|
+
children: [
|
|
2326
|
+
/* @__PURE__ */ jsx(ModalHeader, { children: /* @__PURE__ */ jsx(DialogTitle, { children: title ?? l.title }) }),
|
|
2327
|
+
/* @__PURE__ */ jsxs("div", { className: "px-6 pb-6", children: [
|
|
2328
|
+
/* @__PURE__ */ jsxs(DialogDescription, { className: "pt-4 text-sm text-muted-foreground", children: [
|
|
2329
|
+
l.description,
|
|
2330
|
+
/* @__PURE__ */ jsx("span", { className: "mt-1 block text-xs", children: l.supports })
|
|
2331
|
+
] }),
|
|
2332
|
+
/* @__PURE__ */ jsxs("div", { className: "grid gap-4 py-4", children: [
|
|
2333
|
+
urls.map((url, index) => /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
2334
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
2335
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1", children: [
|
|
2336
|
+
/* @__PURE__ */ jsx(Label, { htmlFor: `url-${index}`, className: "text-sm", children: l.url(urls.length > 1 ? index + 1 : null) }),
|
|
2337
|
+
/* @__PURE__ */ jsx(
|
|
2338
|
+
Input,
|
|
2339
|
+
{
|
|
2340
|
+
id: `url-${index}`,
|
|
2341
|
+
type: "text",
|
|
2342
|
+
placeholder: l.placeholder,
|
|
2343
|
+
value: url,
|
|
2344
|
+
onChange: (e) => onUrlChange(index, e.target.value),
|
|
2345
|
+
onPaste: (e) => {
|
|
2346
|
+
e.preventDefault();
|
|
2347
|
+
onUrlPaste(index, e.clipboardData.getData("text"));
|
|
2348
|
+
},
|
|
2349
|
+
className: cn(errors[index] && "border-red-border")
|
|
2350
|
+
}
|
|
2351
|
+
),
|
|
2352
|
+
errors[index] && /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-red-text", children: errors[index] })
|
|
2353
|
+
] }),
|
|
2354
|
+
urls.length > 1 && /* @__PURE__ */ jsx(
|
|
2355
|
+
Button,
|
|
2356
|
+
{
|
|
2357
|
+
type: "button",
|
|
2358
|
+
variant: "ghost",
|
|
2359
|
+
size: "icon",
|
|
2360
|
+
onClick: () => onRemoveUrl(index),
|
|
2361
|
+
className: "mt-6",
|
|
2362
|
+
"aria-label": l.removeUrl(index + 1),
|
|
2363
|
+
children: /* @__PURE__ */ jsx(X, { className: "h-4 w-4" })
|
|
2364
|
+
}
|
|
2365
|
+
)
|
|
2366
|
+
] }),
|
|
2367
|
+
renderPreview?.(url, index)
|
|
2368
|
+
] }, index)),
|
|
2369
|
+
/* @__PURE__ */ jsxs(Button, { type: "button", variant: "outline", size: "sm", onClick: onAddUrl, className: "w-full", children: [
|
|
2370
|
+
/* @__PURE__ */ jsx(Plus, { className: "mr-2 h-4 w-4" }),
|
|
2371
|
+
l.addAnother
|
|
2372
|
+
] })
|
|
2373
|
+
] }),
|
|
2374
|
+
submitError && /* @__PURE__ */ jsx(
|
|
2375
|
+
"p",
|
|
2376
|
+
{
|
|
2377
|
+
className: "text-sm text-red-text",
|
|
2378
|
+
"data-testid": testIdOr(testIds?.submitError, { testId: "url-submit-error" }),
|
|
2379
|
+
children: submitError
|
|
2380
|
+
}
|
|
2381
|
+
),
|
|
2382
|
+
/* @__PURE__ */ jsx("div", { className: "flex flex-col-reverse sm:flex-row sm:justify-end gap-2", children: /* @__PURE__ */ jsx(
|
|
2383
|
+
Button,
|
|
2384
|
+
{
|
|
2385
|
+
onClick: onSubmit,
|
|
2386
|
+
disabled: isSubmitting,
|
|
2387
|
+
"data-testid": testIdOr(testIds?.submit, { testId: "url-submit-button" }),
|
|
2388
|
+
children: isSubmitting ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2389
|
+
/* @__PURE__ */ jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }),
|
|
2390
|
+
l.adding
|
|
2391
|
+
] }) : l.addDocuments
|
|
2392
|
+
}
|
|
2393
|
+
) })
|
|
2394
|
+
] })
|
|
2395
|
+
]
|
|
2396
|
+
}
|
|
2397
|
+
)
|
|
2398
|
+
] });
|
|
2399
|
+
}
|
|
2400
|
+
function UrlDialogTitle({ icon, workspaceName, labels }) {
|
|
2401
|
+
const l = { ...DEFAULT_URL_INPUT_DIALOG_LABELS, ...labels };
|
|
2402
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("flex min-w-0 items-center", icon ? "gap-3" : "gap-2"), children: [
|
|
2403
|
+
icon && /* @__PURE__ */ jsx("span", { className: "flex-shrink-0", children: icon }),
|
|
2404
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 truncate", title: workspaceName, children: workspaceName }),
|
|
2405
|
+
/* @__PURE__ */ jsx("span", { className: "flex-shrink-0 text-muted-foreground", children: "/" }),
|
|
2406
|
+
/* @__PURE__ */ jsx("span", { className: "flex-shrink-0", children: l.title })
|
|
2407
|
+
] });
|
|
2408
|
+
}
|
|
2409
|
+
function MediaPreviewView({ kind, src, testId, labels }) {
|
|
2410
|
+
const l = { ...DEFAULT_URL_INPUT_DIALOG_LABELS, ...labels };
|
|
2411
|
+
return /* @__PURE__ */ jsxs("div", { className: "mt-2 overflow-hidden rounded-md border", "data-testid": testId, children: [
|
|
2412
|
+
kind === "youtube" && /* @__PURE__ */ jsx(
|
|
2413
|
+
"iframe",
|
|
2414
|
+
{
|
|
2415
|
+
className: "aspect-video w-full",
|
|
2416
|
+
src,
|
|
2417
|
+
title: l.mediaPreview,
|
|
2418
|
+
allow: "accelerometer; encrypted-media; picture-in-picture",
|
|
2419
|
+
allowFullScreen: true
|
|
2420
|
+
}
|
|
2421
|
+
),
|
|
2422
|
+
kind === "video" && /* @__PURE__ */ jsx("video", { className: "max-h-56 w-full bg-black", src, controls: true, preload: "metadata" }),
|
|
2423
|
+
kind === "audio" && /* @__PURE__ */ jsx("audio", { className: "w-full p-2", src, controls: true, preload: "metadata" })
|
|
2424
|
+
] });
|
|
2425
|
+
}
|
|
2426
|
+
|
|
2427
|
+
// src/files/media-preview.ts
|
|
2428
|
+
var MEDIA_HOSTS = [
|
|
2429
|
+
"youtube.com",
|
|
2430
|
+
"youtu.be",
|
|
2431
|
+
"vimeo.com",
|
|
2432
|
+
"soundcloud.com",
|
|
2433
|
+
"dailymotion.com",
|
|
2434
|
+
"twitch.tv"
|
|
2435
|
+
];
|
|
2436
|
+
var VIDEO_EXTENSIONS = [".mp4", ".mpeg", ".mpg", ".webm", ".mov", ".avi", ".mkv", ".ogv"];
|
|
2437
|
+
var AUDIO_EXTENSIONS = [".mp3", ".wav", ".m4a", ".aac", ".flac", ".ogg", ".oga"];
|
|
2438
|
+
function normalizeHost(hostname) {
|
|
2439
|
+
return hostname.toLowerCase().replace(/^(www|m)\./, "");
|
|
2440
|
+
}
|
|
2441
|
+
function getYoutubeId(url) {
|
|
2442
|
+
const host = normalizeHost(url.hostname);
|
|
2443
|
+
if (host === "youtu.be") return url.pathname.slice(1).split("/")[0] || null;
|
|
2444
|
+
if (host === "youtube.com" || host.endsWith(".youtube.com")) {
|
|
2445
|
+
if (url.pathname === "/watch") return url.searchParams.get("v");
|
|
2446
|
+
const segments = url.pathname.split("/").filter(Boolean);
|
|
2447
|
+
if (segments[0] === "embed" || segments[0] === "shorts" || segments[0] === "v") {
|
|
2448
|
+
return segments[1] ?? null;
|
|
2449
|
+
}
|
|
2450
|
+
}
|
|
2451
|
+
return null;
|
|
2452
|
+
}
|
|
2453
|
+
function getExtension(pathname) {
|
|
2454
|
+
const lower = pathname.toLowerCase();
|
|
2455
|
+
const lastDot = lower.lastIndexOf(".");
|
|
2456
|
+
const lastSlash = lower.lastIndexOf("/");
|
|
2457
|
+
return lastDot > lastSlash ? lower.slice(lastDot) : "";
|
|
2458
|
+
}
|
|
2459
|
+
function getMediaPreview(rawUrl) {
|
|
2460
|
+
let url;
|
|
2461
|
+
try {
|
|
2462
|
+
url = new URL(rawUrl);
|
|
2463
|
+
} catch {
|
|
2464
|
+
return null;
|
|
2465
|
+
}
|
|
2466
|
+
const youtubeId = getYoutubeId(url);
|
|
2467
|
+
if (youtubeId) {
|
|
2468
|
+
return { kind: "youtube", embedUrl: `https://www.youtube.com/embed/${youtubeId}` };
|
|
2469
|
+
}
|
|
2470
|
+
const extension = getExtension(url.pathname);
|
|
2471
|
+
if (VIDEO_EXTENSIONS.includes(extension)) return { kind: "video", src: rawUrl };
|
|
2472
|
+
if (AUDIO_EXTENSIONS.includes(extension)) return { kind: "audio", src: rawUrl };
|
|
2473
|
+
return null;
|
|
2474
|
+
}
|
|
2475
|
+
function isMediaUrl(rawUrl) {
|
|
2476
|
+
if (getMediaPreview(rawUrl)) return true;
|
|
2477
|
+
try {
|
|
2478
|
+
const host = normalizeHost(new URL(rawUrl).hostname);
|
|
2479
|
+
return MEDIA_HOSTS.some((mediaHost) => host === mediaHost || host.endsWith(`.${mediaHost}`));
|
|
2480
|
+
} catch {
|
|
2481
|
+
return false;
|
|
2482
|
+
}
|
|
2483
|
+
}
|
|
2484
|
+
function UrlInputDialog({
|
|
2485
|
+
onUrlsSubmit,
|
|
2486
|
+
trigger,
|
|
2487
|
+
processing = false,
|
|
2488
|
+
open: controlledOpen,
|
|
2489
|
+
onOpenChange,
|
|
2490
|
+
titleWorkspaceName,
|
|
2491
|
+
titleIcon
|
|
2492
|
+
}) {
|
|
2493
|
+
const [uncontrolledOpen, setUncontrolledOpen] = useState(false);
|
|
2494
|
+
const open = controlledOpen ?? uncontrolledOpen;
|
|
2495
|
+
const setOpen = (next) => {
|
|
2496
|
+
onOpenChange?.(next);
|
|
2497
|
+
if (controlledOpen === void 0) setUncontrolledOpen(next);
|
|
2498
|
+
};
|
|
2499
|
+
const [urls, setUrls] = useState([""]);
|
|
2500
|
+
const [errors, setErrors] = useState([]);
|
|
2501
|
+
const [submitting, setSubmitting] = useState(false);
|
|
2502
|
+
const [submitError, setSubmitError] = useState(null);
|
|
2503
|
+
const preprocessUrl = (url) => {
|
|
2504
|
+
let processedUrl = url.trim();
|
|
2505
|
+
if (processedUrl && !processedUrl.match(/^https?:\/\//i)) {
|
|
2506
|
+
processedUrl = "https://" + processedUrl;
|
|
2507
|
+
}
|
|
2508
|
+
try {
|
|
2509
|
+
new URL(processedUrl);
|
|
2510
|
+
processedUrl = processedUrl.replace(/ /g, "%20");
|
|
2511
|
+
return processedUrl;
|
|
2512
|
+
} catch {
|
|
2513
|
+
return processedUrl.replace(/ /g, "%20");
|
|
2514
|
+
}
|
|
2515
|
+
};
|
|
2516
|
+
const validateUrl = (url) => {
|
|
2517
|
+
try {
|
|
2518
|
+
const urlObj = new URL(url);
|
|
2519
|
+
if (isMediaUrl(url)) {
|
|
2520
|
+
return { valid: true };
|
|
2521
|
+
}
|
|
2522
|
+
const pathname = urlObj.pathname.toLowerCase();
|
|
2523
|
+
const supportedExtensions = [
|
|
2524
|
+
".pdf",
|
|
2525
|
+
".txt",
|
|
2526
|
+
".md",
|
|
2527
|
+
".html",
|
|
2528
|
+
".doc",
|
|
2529
|
+
".docx",
|
|
2530
|
+
".rtf",
|
|
2531
|
+
".ppt",
|
|
2532
|
+
".pptx",
|
|
2533
|
+
".xls",
|
|
2534
|
+
".xlsx",
|
|
2535
|
+
// .zip is fetched from the URL by the browser and extracted by the
|
|
2536
|
+
// frontend zip worker; each entry is then uploaded as a normal file.
|
|
2537
|
+
".zip"
|
|
2538
|
+
];
|
|
2539
|
+
const hasFileExtension = pathname.includes(".") && pathname.lastIndexOf(".") > pathname.lastIndexOf("/");
|
|
2540
|
+
const hasValidExtension = !hasFileExtension || supportedExtensions.some((ext) => pathname.endsWith(ext));
|
|
2541
|
+
if (!hasValidExtension) {
|
|
2542
|
+
return {
|
|
2543
|
+
valid: false,
|
|
2544
|
+
error: "File type not supported. Supported formats: PDF, DOC(X), PPT(X), XLS(X), RTF, TXT, MD, HTML, ZIP."
|
|
2545
|
+
};
|
|
2546
|
+
}
|
|
2547
|
+
return { valid: true };
|
|
2548
|
+
} catch {
|
|
2549
|
+
return { valid: false, error: "Invalid URL format" };
|
|
2550
|
+
}
|
|
2551
|
+
};
|
|
2552
|
+
const addUrlField = () => {
|
|
2553
|
+
setUrls([...urls, ""]);
|
|
2554
|
+
setErrors([...errors, ""]);
|
|
2555
|
+
};
|
|
2556
|
+
const removeUrlField = (index) => {
|
|
2557
|
+
setUrls(urls.filter((_, i) => i !== index));
|
|
2558
|
+
setErrors(errors.filter((_, i) => i !== index));
|
|
2559
|
+
};
|
|
2560
|
+
const updateUrl = (index, value) => {
|
|
2561
|
+
if (submitError) setSubmitError(null);
|
|
2562
|
+
const delimiters = /[,\n]+/;
|
|
2563
|
+
if (delimiters.test(value)) {
|
|
2564
|
+
const urlList = value.split(delimiters).map((u) => u.trim()).filter((u) => u.length > 0);
|
|
2565
|
+
if (urlList.length > 1) {
|
|
2566
|
+
const newUrls2 = [...urls];
|
|
2567
|
+
newUrls2.splice(index, 1, ...urlList);
|
|
2568
|
+
if (index === urls.length - 1) {
|
|
2569
|
+
newUrls2.push("");
|
|
2570
|
+
}
|
|
2571
|
+
setUrls(newUrls2);
|
|
2572
|
+
const newErrors = [...errors];
|
|
2573
|
+
urlList.forEach((_, i) => {
|
|
2574
|
+
newErrors[index + i] = "";
|
|
2575
|
+
});
|
|
2576
|
+
setErrors(newErrors);
|
|
2577
|
+
return;
|
|
2578
|
+
}
|
|
2579
|
+
}
|
|
2580
|
+
const newUrls = [...urls];
|
|
2581
|
+
newUrls[index] = value;
|
|
2582
|
+
setUrls(newUrls);
|
|
2583
|
+
if (errors[index]) {
|
|
2584
|
+
const newErrors = [...errors];
|
|
2585
|
+
newErrors[index] = "";
|
|
2586
|
+
setErrors(newErrors);
|
|
2587
|
+
}
|
|
2588
|
+
};
|
|
2589
|
+
const handleSubmit = async () => {
|
|
2590
|
+
const newErrors = [];
|
|
2591
|
+
const validUrls = [];
|
|
2592
|
+
urls.forEach((url, index) => {
|
|
2593
|
+
const trimmedUrl = url.trim();
|
|
2594
|
+
if (!trimmedUrl) {
|
|
2595
|
+
newErrors[index] = "URL is required";
|
|
2596
|
+
} else {
|
|
2597
|
+
const processedUrl = preprocessUrl(trimmedUrl);
|
|
2598
|
+
const validation = validateUrl(processedUrl);
|
|
2599
|
+
if (!validation.valid) {
|
|
2600
|
+
newErrors[index] = validation.error || "Invalid URL";
|
|
2601
|
+
} else {
|
|
2602
|
+
newErrors[index] = "";
|
|
2603
|
+
validUrls.push(processedUrl);
|
|
2604
|
+
}
|
|
2605
|
+
}
|
|
2606
|
+
});
|
|
2607
|
+
setErrors(newErrors);
|
|
2608
|
+
if (validUrls.length > 0 && !newErrors.some((error) => error)) {
|
|
2609
|
+
setSubmitError(null);
|
|
2610
|
+
setSubmitting(true);
|
|
2611
|
+
let ok;
|
|
2612
|
+
try {
|
|
2613
|
+
ok = await onUrlsSubmit(validUrls);
|
|
2614
|
+
} catch {
|
|
2615
|
+
ok = false;
|
|
2616
|
+
}
|
|
2617
|
+
setSubmitting(false);
|
|
2618
|
+
if (ok === false) {
|
|
2619
|
+
setSubmitError("Failed to upload documents from URLs. Please check the URLs and try again.");
|
|
2620
|
+
return;
|
|
2621
|
+
}
|
|
2622
|
+
setOpen(false);
|
|
2623
|
+
setUrls([""]);
|
|
2624
|
+
setErrors([]);
|
|
2625
|
+
}
|
|
2626
|
+
};
|
|
2627
|
+
const showTrigger = trigger !== void 0 || controlledOpen === void 0;
|
|
2628
|
+
const title = titleWorkspaceName ? /* @__PURE__ */ jsx(UrlDialogTitle, { icon: titleIcon, workspaceName: titleWorkspaceName }) : void 0;
|
|
2629
|
+
return /* @__PURE__ */ jsx(
|
|
2630
|
+
UrlInputDialogView,
|
|
2631
|
+
{
|
|
2632
|
+
open,
|
|
2633
|
+
onOpenChange: setOpen,
|
|
2634
|
+
trigger: showTrigger ? trigger || /* @__PURE__ */ jsxs(Button, { variant: "outline", size: "sm", disabled: processing, children: [
|
|
2635
|
+
/* @__PURE__ */ jsx(Link, { className: "w-4 h-4 mr-2" }),
|
|
2636
|
+
processing ? "Processing..." : "Add from URL"
|
|
2637
|
+
] }) : void 0,
|
|
2638
|
+
title,
|
|
2639
|
+
urls,
|
|
2640
|
+
errors,
|
|
2641
|
+
onUrlChange: updateUrl,
|
|
2642
|
+
onUrlPaste: updateUrl,
|
|
2643
|
+
onAddUrl: addUrlField,
|
|
2644
|
+
onRemoveUrl: removeUrlField,
|
|
2645
|
+
renderPreview: (url, index) => {
|
|
2646
|
+
const trimmed = url.trim();
|
|
2647
|
+
const preview = trimmed ? getMediaPreview(preprocessUrl(trimmed)) : null;
|
|
2648
|
+
if (!preview) return null;
|
|
2649
|
+
return /* @__PURE__ */ jsx(
|
|
2650
|
+
MediaPreviewView,
|
|
2651
|
+
{
|
|
2652
|
+
kind: preview.kind,
|
|
2653
|
+
src: preview.kind === "youtube" ? preview.embedUrl : preview.src,
|
|
2654
|
+
testId: `url-media-preview-${index}`
|
|
2655
|
+
}
|
|
2656
|
+
);
|
|
2657
|
+
},
|
|
2658
|
+
submitError,
|
|
2659
|
+
isSubmitting: submitting,
|
|
2660
|
+
onSubmit: handleSubmit
|
|
2661
|
+
}
|
|
2662
|
+
);
|
|
2663
|
+
}
|
|
2664
|
+
var POINTS = [
|
|
2665
|
+
{
|
|
2666
|
+
icon: KeyRound,
|
|
2667
|
+
heading: "Only you hold the key",
|
|
2668
|
+
body: "You choose who to invite to a workspace and the role they hold. Each workspace is encrypted with its own key, held only by its members \u2014 so no one outside it, including ARBI administrators, can access its confidential data."
|
|
2669
|
+
},
|
|
2670
|
+
{
|
|
2671
|
+
icon: Eye,
|
|
2672
|
+
heading: "You decide what to share",
|
|
2673
|
+
body: "Within a workspace, conversations are private by default and documents are shared with collaborators. Anything you keep private stays invisible to other members, even the owner."
|
|
2674
|
+
},
|
|
2675
|
+
{
|
|
2676
|
+
icon: ShieldCheck,
|
|
2677
|
+
heading: "Your data stays in the UK",
|
|
2678
|
+
body: "By default, the AI that processes your files runs on ARBI's own infrastructure in the United Kingdom. Third-party models (OpenAI, Anthropic or Google) are optional; we select providers with the strongest data-protection terms, but recommend reviewing each provider's data-retention policy before enabling one."
|
|
2679
|
+
},
|
|
2680
|
+
{
|
|
2681
|
+
icon: BrainCircuit,
|
|
2682
|
+
heading: "We never train AI on your data",
|
|
2683
|
+
body: "Your files and conversations are never used to train AI models."
|
|
2684
|
+
}
|
|
2685
|
+
];
|
|
2686
|
+
function PrivacyExplainerModal() {
|
|
2687
|
+
const [open, setOpen] = useState(false);
|
|
2688
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2689
|
+
/* @__PURE__ */ jsxs(
|
|
2690
|
+
Button,
|
|
2691
|
+
{
|
|
2692
|
+
type: "button",
|
|
2693
|
+
variant: "ghost",
|
|
2694
|
+
size: "sm",
|
|
2695
|
+
onClick: () => setOpen(true),
|
|
2696
|
+
className: "gap-1.5 text-primary hover:text-primary",
|
|
2697
|
+
"data-testid": "privacy-explainer-button",
|
|
2698
|
+
children: [
|
|
2699
|
+
/* @__PURE__ */ jsx(Info, { className: "w-4 h-4" }),
|
|
2700
|
+
"Privacy Guarantee",
|
|
2701
|
+
/* @__PURE__ */ jsx(ChevronRight, { className: "w-3.5 h-3.5 opacity-70" })
|
|
2702
|
+
]
|
|
2703
|
+
}
|
|
2704
|
+
),
|
|
2705
|
+
/* @__PURE__ */ jsx(Dialog, { open, onOpenChange: setOpen, children: /* @__PURE__ */ jsxs(DialogContent, { className: "sm:max-w-lg", "data-testid": "privacy-explainer-dialog", children: [
|
|
2706
|
+
/* @__PURE__ */ jsxs(DialogHeader, { children: [
|
|
2707
|
+
/* @__PURE__ */ jsxs(DialogTitle, { className: "flex items-center gap-2", children: [
|
|
2708
|
+
/* @__PURE__ */ jsx(ShieldCheck, { className: "h-5 w-5 text-primary" }),
|
|
2709
|
+
"Your data, your keys"
|
|
2710
|
+
] }),
|
|
2711
|
+
/* @__PURE__ */ jsx(DialogDescription, { children: "How ARBI protects confidentiality." })
|
|
2712
|
+
] }),
|
|
2713
|
+
/* @__PURE__ */ jsx("div", { className: "space-y-5 py-1", children: POINTS.map(({ icon: Icon, heading, body }) => /* @__PURE__ */ jsxs("div", { className: "flex gap-3", children: [
|
|
2714
|
+
/* @__PURE__ */ jsx(Icon, { className: "mt-0.5 h-5 w-5 shrink-0 text-primary" }),
|
|
2715
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-0.5", children: [
|
|
2716
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-semibold leading-none", children: heading }),
|
|
2717
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: body })
|
|
2718
|
+
] })
|
|
2719
|
+
] }, heading)) }),
|
|
2720
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2 pt-1", children: [
|
|
2721
|
+
/* @__PURE__ */ jsx(
|
|
2722
|
+
"a",
|
|
2723
|
+
{
|
|
2724
|
+
href: "https://arbicity.com/ARBI-Security-Whitepaper.pdf",
|
|
2725
|
+
target: "_blank",
|
|
2726
|
+
rel: "noopener noreferrer",
|
|
2727
|
+
className: "text-sm font-medium text-primary hover:underline",
|
|
2728
|
+
"data-testid": "privacy-explainer-whitepaper-link",
|
|
2729
|
+
children: "Full security details \u2192"
|
|
2730
|
+
}
|
|
2731
|
+
),
|
|
2732
|
+
/* @__PURE__ */ jsx(
|
|
2733
|
+
Button,
|
|
2734
|
+
{
|
|
2735
|
+
type: "button",
|
|
2736
|
+
onClick: () => setOpen(false),
|
|
2737
|
+
"data-testid": "privacy-explainer-dismiss",
|
|
2738
|
+
children: "Got it"
|
|
2739
|
+
}
|
|
2740
|
+
)
|
|
2741
|
+
] })
|
|
2742
|
+
] }) })
|
|
2743
|
+
] });
|
|
2744
|
+
}
|
|
1717
2745
|
|
|
1718
|
-
export { CHROME, DEFAULT_EXPLORER_LABELS, DEFAULT_FOLDER_FILTER_LABELS, DEFAULT_FOLDER_PICKER_LABELS, ExplorerDragPreview, ExplorerDropOverlay, ExplorerEmpty, ExplorerFileTile, ExplorerFileTooltip, ExplorerFolderTile, ExplorerFrame, ExplorerLoadingTiles, ExplorerMarquee, ExplorerScroller, ExplorerStage, FailedStageIcon, FieldAttribution, FieldFolderSelect, FieldFolderValue, FieldLabelsSelect, FieldNativeSelect, FieldValue, FieldWithAttribution, FilesFilterBar, FilesModalFooter, FilesTagsButton, FilesViewCenter, FilterButton, FolderBreadcrumb, FolderCell, FolderCommandList, FolderFilterButton, FolderPickerRow, FolderProviderIcon, FolderTree, LINE_PX, MAX_LINES, MIN_LINES, RECENTLY_DELETED_HINT, RECENTLY_DELETED_HINT_PLURAL, ROW_MIN, RowDensityControl, StatusPill, VendorLogo, buildExplorerEntries, canChangeVisibility, canDeleteDocument, canEditDocumentFields, collectFolderDocs, confirmHideFromMembers, formatFolderSegment, getExplorerDisplayName, hasFolderProviderIcon, isExplorerDocument, joinFolderPath, linesForRowHeight, parseFolderSegments, rowHeightForLines, searchExplorerDocuments, shareStateOf, shareTooltipFor, sortExplorerFiles, visibilityAudience, visibilityToggleTooltip };
|
|
1719
|
-
//# sourceMappingURL=chunk-
|
|
1720
|
-
//# sourceMappingURL=chunk-
|
|
2746
|
+
export { CHROME, DEFAULT_EXPLORER_LABELS, DEFAULT_FOLDER_FILTER_LABELS, DEFAULT_FOLDER_PICKER_LABELS, DEFAULT_UPLOAD_FOOTER_LABELS, DEFAULT_UPLOAD_PARTS_LABELS, DEFAULT_UPLOAD_SOURCES_LABELS, DEFAULT_URL_INPUT_DIALOG_LABELS, ExplorerDragPreview, ExplorerDropOverlay, ExplorerEmpty, ExplorerFileTile, ExplorerFileTooltip, ExplorerFolderTile, ExplorerFrame, ExplorerLoadingTiles, ExplorerMarquee, ExplorerScroller, ExplorerStage, FailedStageIcon, FieldAttribution, FieldFolderSelect, FieldFolderValue, FieldLabelsSelect, FieldNativeSelect, FieldValue, FieldWithAttribution, FilesFilterBar, FilesModalFooter, FilesTagsButton, FilesViewCenter, FilterButton, FolderBreadcrumb, FolderCell, FolderCommandList, FolderFilterButton, FolderPickerRow, FolderProviderIcon, FolderTree, LINE_PX, MAX_LINES, MIN_LINES, MediaPreviewView, PrivacyExplainerModal, RECENTLY_DELETED_HINT, RECENTLY_DELETED_HINT_PLURAL, ROW_MIN, RejectedFilesList, RowDensityControl, SelectedFilesList, ShareToggle, StatusPill, UploadBrowseButtons, UploadContainer, UploadDropArea, UploadErrorMessage, UploadFooterBar, UploadFrame, UploadProgress, UploadShareNote, UploadSourcePicker, UploadSourceSection, UploadUrlButton, UrlDialogTitle, UrlInputDialog, UrlInputDialogView, VendorLogo, buildExplorerEntries, canChangeVisibility, canDeleteDocument, canEditDocumentFields, collectFolderDocs, confirmHideFromMembers, formatFolderSegment, getExplorerDisplayName, getMediaPreview, hasFolderProviderIcon, isExplorerDocument, isMediaUrl, joinFolderPath, linesForRowHeight, parseFolderSegments, rowHeightForLines, searchExplorerDocuments, shareStateOf, shareTooltipFor, sortExplorerFiles, visibilityAudience, visibilityToggleTooltip };
|
|
2747
|
+
//# sourceMappingURL=chunk-7KWUQQIB.js.map
|
|
2748
|
+
//# sourceMappingURL=chunk-7KWUQQIB.js.map
|