@mcp-b/react-components 0.16.1 → 0.18.0
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/{AgentActivity-BNUNrP9O.d.ts → AgentActivity-D2SHSGFX.d.ts} +1 -1
- package/dist/{AgentChat-CrlpbvQJ.d.ts → AgentChat-ClxViuUM.d.ts} +4 -29
- package/dist/AgentMessageParts-CyD2UB3V.d.ts +46 -0
- package/dist/AgentToolRunsContext-BVe4stgw.d.ts +21 -0
- package/dist/{Button-FX_hpqxm.d.ts → Button-DLGzHsjc.d.ts} +13 -7
- package/dist/{CodeBlock-BmB4Xaqq.js → CodeBlock-Bfp5PAg3.js} +9 -6
- package/dist/{CodeBlock-BRajW4QU.d.ts → CodeBlock-gV4kZeCI.d.ts} +2 -9
- package/dist/Collapsible-N64ASIQr.d.ts +119 -0
- package/dist/{Combobox-B9Fcd6q-.d.ts → Combobox-CYc37s5l.d.ts} +11 -33
- package/dist/{FileTree-CkVbIMWV.js → FileTree-3zYtrddG.js} +46 -20
- package/dist/{Menu-Bgu-ufb5.d.ts → Menu-L6MZm-7N.d.ts} +15 -56
- package/dist/{Message-BkMdE3bS.js → Message-BXtmfc9Q.js} +13 -20
- package/dist/{ModelSelector-SlJNgwKY.js → ModelSelector-Cqw_qrUG.js} +18 -25
- package/dist/{PromptInput-BWTuXMOD.d.ts → PromptInput-Bdh9pqlo.d.ts} +41 -71
- package/dist/{ResponsiveSidebarShell-Dd9DCcBT.d.ts → ResponsiveSidebarShell-CsAh4NyL.d.ts} +1 -0
- package/dist/{Select-BeEsefzh.d.ts → Select-B_13gg_J.d.ts} +16 -44
- package/dist/{Tabs-3Zc4tb9D.d.ts → Tabs-ColWK-XA.d.ts} +14 -20
- package/dist/{ThinkChat-CzC-zNGA.js → ThinkChat-15EhfvYJ.js} +123 -73
- package/dist/{ThinkChatActivity-BFQnb2ct.d.ts → ThinkChatActivity-Bzot45kX.d.ts} +9 -4
- package/dist/{ThinkChatActivitySummary-BPmu9a-c.d.ts → ThinkChatActivitySummary-D1xOrNrq.d.ts} +1 -1
- package/dist/{ThinkChatContext-C3Eb1Xpi.d.ts → ThinkChatContext-DrsZqdaO.d.ts} +1 -1
- package/dist/ThinkRecoveryNotice-DFIcG9UX.d.ts +19 -0
- package/dist/{Toggle-CAAlNl-M.d.ts → Toggle-JKZ43D5S.d.ts} +2 -2
- package/dist/{ToggleGroup-8hPv-b69.d.ts → ToggleGroup-DNd6cDJZ.d.ts} +4 -5
- package/dist/Workspace-Jez8ffUj.d.ts +274 -0
- package/dist/WorkspaceExplorer-B9dQWNVK.d.ts +32 -0
- package/dist/{WorkspaceFile-DOZkPwzu.d.ts → WorkspaceFile-CzyHnESE.d.ts} +1 -1
- package/dist/{WorkspaceFileView-rSN_yT0L.js → WorkspaceFileView-C68Ub8S8.js} +121 -128
- package/dist/{WorkspaceLink-DIPbXrUM.js → WorkspaceLink-BYYeTQLf.js} +20 -55
- package/dist/{WorkspaceLink-DK1DWMHe.d.ts → WorkspaceLink-O-EBKUJ8.d.ts} +6 -9
- package/dist/class-names-BiMDVpUo.js +14 -0
- package/dist/components/Accordion.d.ts +5 -15
- package/dist/components/Accordion.js +16 -10
- package/dist/components/Activity.d.ts +5 -10
- package/dist/components/Activity.js +2 -2
- package/dist/components/AgentActivity.d.ts +1 -1
- package/dist/components/AgentActivity.js +4 -5
- package/dist/components/AgentActivityPreview.d.ts +9 -9
- package/dist/components/AgentActivityPreview.js +8 -12
- package/dist/components/AgentAttention.d.ts +2 -2
- package/dist/components/AgentAttention.js +1 -1
- package/dist/components/AgentChat.d.ts +2 -2
- package/dist/components/AgentChat.js +113 -218
- package/dist/components/AgentChatMessageEditor.js +3 -3
- package/dist/components/AgentChatTurnError.js +2 -2
- package/dist/components/AgentConnection.js +4 -4
- package/dist/components/AgentMessageParts.d.ts +2 -0
- package/dist/components/AgentMessageParts.js +119 -0
- package/dist/components/AgentToolDetail.d.ts +57 -0
- package/dist/components/AgentToolDetail.js +100 -0
- package/dist/components/AgentToolRunsContext.d.ts +2 -0
- package/dist/components/AgentToolRunsContext.js +16 -0
- package/dist/components/AlertDialog.d.ts +7 -19
- package/dist/components/AlertDialog.js +21 -32
- package/dist/components/AppTopBar.d.ts +28 -8
- package/dist/components/AppTopBar.js +36 -12
- package/dist/components/Approval.d.ts +102 -0
- package/dist/components/Approval.js +227 -0
- package/dist/components/Artifact.d.ts +3 -5
- package/dist/components/Artifact.js +7 -5
- package/dist/components/Autocomplete.d.ts +11 -33
- package/dist/components/Autocomplete.js +23 -30
- package/dist/components/Avatar.d.ts +4 -12
- package/dist/components/Avatar.js +13 -12
- package/dist/components/Badge.js +3 -0
- package/dist/components/BrowserLiveView.js +27 -12
- package/dist/components/BrowserReplay.js +4 -3
- package/dist/components/BrowserRunPanel.js +58 -78
- package/dist/components/Button.d.ts +1 -1
- package/dist/components/Button.js +14 -16
- package/dist/components/Card.d.ts +7 -8
- package/dist/components/Card.js +19 -10
- package/dist/components/ChainOfThought.d.ts +5 -11
- package/dist/components/ChainOfThought.js +3 -2
- package/dist/components/ChatGptSignInScreen.js +8 -8
- package/dist/components/Checkbox.d.ts +2 -4
- package/dist/components/Checkbox.js +6 -5
- package/dist/components/CheckboxGroup.d.ts +1 -3
- package/dist/components/CheckboxGroup.js +15 -14
- package/dist/components/Checkpoint.d.ts +64 -0
- package/dist/components/Checkpoint.js +63 -0
- package/dist/components/CodeBlock.d.ts +1 -1
- package/dist/components/CodeBlock.js +1 -1
- package/dist/components/CodexModelSelector.d.ts +1 -1
- package/dist/components/CodexModelSelector.js +2 -2
- package/dist/components/Collapsible.d.ts +1 -124
- package/dist/components/Collapsible.js +7 -10
- package/dist/components/Combobox.d.ts +1 -1
- package/dist/components/Combobox.js +23 -30
- package/dist/components/Commit.d.ts +5 -11
- package/dist/components/Commit.js +6 -5
- package/dist/components/Context.js +1 -1
- package/dist/components/ContextMenu.d.ts +21 -37
- package/dist/components/ContextMenu.js +34 -51
- package/dist/components/Conversation.d.ts +3 -5
- package/dist/components/Conversation.js +5 -4
- package/dist/components/DescriptionListParts.js +1 -1
- package/dist/components/Dialog.d.ts +6 -17
- package/dist/components/Dialog.js +17 -24
- package/dist/components/EnvironmentVariables.d.ts +1 -1
- package/dist/components/EnvironmentVariables.js +4 -3
- package/dist/components/Field.d.ts +17 -20
- package/dist/components/Field.js +20 -17
- package/dist/components/Fieldset.d.ts +2 -7
- package/dist/components/Fieldset.js +7 -6
- package/dist/components/FileTree.d.ts +6 -0
- package/dist/components/FileTree.js +1 -1
- package/dist/components/Form.d.ts +1 -4
- package/dist/components/Form.js +3 -2
- package/dist/components/GithubMotionMark.js +1 -1
- package/dist/components/IconButton.d.ts +2 -3
- package/dist/components/IconButton.js +2 -1
- package/dist/components/InlineCitation.d.ts +66 -0
- package/dist/components/InlineCitation.js +142 -0
- package/dist/components/Input.d.ts +1 -4
- package/dist/components/Input.js +3 -2
- package/dist/components/Marker.js +1 -1
- package/dist/components/McpConnectionRequest.js +2 -2
- package/dist/components/McpServerPicker.d.ts +1 -1
- package/dist/components/McpServerPicker.js +6 -5
- package/dist/components/MediaPreviewCard.d.ts +103 -0
- package/dist/components/MediaPreviewCard.js +193 -0
- package/dist/components/Menu.d.ts +1 -1
- package/dist/components/Menu.js +33 -52
- package/dist/components/Menubar.d.ts +22 -43
- package/dist/components/Menubar.js +36 -53
- package/dist/components/Message.d.ts +7 -7
- package/dist/components/Message.js +1 -1
- package/dist/components/MessageScroller.d.ts +2 -2
- package/dist/components/MessageScroller.js +6 -5
- package/dist/components/Meter.d.ts +5 -20
- package/dist/components/Meter.js +11 -10
- package/dist/components/ModelSelector.d.ts +6 -9
- package/dist/components/ModelSelector.js +1 -1
- package/dist/components/NavigationMenu.d.ts +11 -33
- package/dist/components/NavigationMenu.js +23 -30
- package/dist/components/NumberField.d.ts +6 -24
- package/dist/components/NumberField.js +13 -12
- package/dist/components/Plan.d.ts +103 -0
- package/dist/components/Plan.js +113 -0
- package/dist/components/Popover.d.ts +9 -36
- package/dist/components/Popover.js +23 -34
- package/dist/components/PreviewCard.d.ts +6 -24
- package/dist/components/PreviewCard.js +13 -24
- package/dist/components/PricingBillingToggle.js +1 -1
- package/dist/components/PricingFAQ.js +1 -1
- package/dist/components/PricingPage.js +2 -1
- package/dist/components/PricingPlanCard.js +5 -4
- package/dist/components/PricingUsageCalculator.js +3 -3
- package/dist/components/Progress.d.ts +3 -8
- package/dist/components/Progress.js +7 -10
- package/dist/components/PromptInput.d.ts +2 -2
- package/dist/components/PromptInput.js +83 -218
- package/dist/components/Queue.d.ts +7 -17
- package/dist/components/Queue.js +2 -3
- package/dist/components/RadioGroup.d.ts +3 -8
- package/dist/components/RadioGroup.js +7 -10
- package/dist/components/Reasoning.d.ts +4 -8
- package/dist/components/Reasoning.js +3 -6
- package/dist/components/ResizableSidePanel.js +2 -2
- package/dist/components/ResponsiveSidebarShell.d.ts +1 -1
- package/dist/components/ResponsiveSidebarShell.js +18 -11
- package/dist/components/ScrollArea.d.ts +5 -20
- package/dist/components/ScrollArea.js +12 -10
- package/dist/components/SearchField.d.ts +43 -0
- package/dist/components/SearchField.js +52 -0
- package/dist/components/Select.d.ts +1 -1
- package/dist/components/Select.js +33 -57
- package/dist/components/Separator.d.ts +1 -5
- package/dist/components/Separator.js +3 -6
- package/dist/components/Slider.d.ts +6 -19
- package/dist/components/Slider.js +15 -14
- package/dist/components/Sources.d.ts +4 -9
- package/dist/components/Sources.js +3 -2
- package/dist/components/Stepper.js +16 -9
- package/dist/components/SubagentRunDetails.js +1 -1
- package/dist/components/SubagentRunIndicator.js +2 -2
- package/dist/components/SubagentRunList.d.ts +3 -5
- package/dist/components/SubagentRunList.js +3 -5
- package/dist/components/SubagentRunSelector.d.ts +9 -22
- package/dist/components/SubagentRunSelector.js +29 -31
- package/dist/components/Switch.d.ts +4 -7
- package/dist/components/Switch.js +6 -10
- package/dist/components/Tabs.d.ts +2 -2
- package/dist/components/Tabs.js +21 -18
- package/dist/components/Task.d.ts +4 -9
- package/dist/components/Task.js +4 -3
- package/dist/components/Terminal.d.ts +3 -4
- package/dist/components/Terminal.js +5 -4
- package/dist/components/TestResults.d.ts +4 -9
- package/dist/components/TestResults.js +11 -6
- package/dist/components/Textarea.js +1 -1
- package/dist/components/ThemeModeControl.js +1 -1
- package/dist/components/ThinkChat.d.ts +45 -22
- package/dist/components/ThinkChat.js +7 -5
- package/dist/components/ThinkChatActivity.d.ts +2 -2
- package/dist/components/ThinkChatActivity.js +24 -7
- package/dist/components/ThinkChatActivitySummary.d.ts +1 -1
- package/dist/components/ThinkChatActivitySummary.js +7 -3
- package/dist/components/ThinkChatContext.d.ts +1 -1
- package/dist/components/ThinkChatToolPanels.js +27 -17
- package/dist/components/ThinkExecutionDetail.js +2 -2
- package/dist/components/ThinkExecutionStatus.js +2 -2
- package/dist/components/ThinkExecutionWorkbench.d.ts +30 -8
- package/dist/components/ThinkExecutionWorkbench.js +70 -134
- package/dist/components/ThinkFullApp.d.ts +40 -15
- package/dist/components/ThinkFullApp.js +193 -117
- package/dist/components/ThinkFullAppViewSwitch.d.ts +1 -1
- package/dist/components/ThinkFullAppViewSwitch.js +2 -2
- package/dist/components/ThinkPendingApproval.d.ts +60 -0
- package/dist/components/ThinkPendingApproval.js +99 -0
- package/dist/components/ThinkRecoveryNotice.d.ts +2 -0
- package/dist/components/ThinkRecoveryNotice.js +46 -0
- package/dist/components/ThinkRoutine.js +1 -0
- package/dist/components/ThinkRoutineBrowser.d.ts +17 -9
- package/dist/components/ThinkRoutineBrowser.js +37 -44
- package/dist/components/ThinkRoutineDetail.d.ts +5 -2
- package/dist/components/ThinkRoutineDetail.js +4 -4
- package/dist/components/ThinkRoutineForm.d.ts +3 -2
- package/dist/components/ThinkRoutineForm.js +11 -10
- package/dist/components/ThinkRoutineLibrary.d.ts +27 -25
- package/dist/components/ThinkRoutineLibrary.js +104 -80
- package/dist/components/ThinkRoutineRuns.d.ts +3 -2
- package/dist/components/ThinkRoutineRuns.js +31 -24
- package/dist/components/ThinkThreadPicker.d.ts +17 -11
- package/dist/components/ThinkThreadPicker.js +163 -39
- package/dist/components/ThinkThreadShell.d.ts +1 -1
- package/dist/components/Toast.d.ts +7 -28
- package/dist/components/Toast.js +15 -14
- package/dist/components/Toggle.d.ts +1 -1
- package/dist/components/Toggle.js +10 -8
- package/dist/components/ToggleGroup.d.ts +1 -1
- package/dist/components/ToggleGroup.js +21 -26
- package/dist/components/ToolApproval.d.ts +28 -0
- package/dist/components/ToolApproval.js +35 -0
- package/dist/components/ToolInvocation.d.ts +26 -0
- package/dist/components/ToolInvocation.js +72 -0
- package/dist/components/Toolbar.d.ts +6 -24
- package/dist/components/Toolbar.js +13 -12
- package/dist/components/Tooltip.d.ts +11 -10
- package/dist/components/Tooltip.js +17 -11
- package/dist/components/TransitionSurface.d.ts +27 -0
- package/dist/components/TransitionSurface.js +20 -0
- package/dist/components/WebPreview.d.ts +6 -7
- package/dist/components/WebPreview.js +70 -55
- package/dist/components/Workspace.d.ts +2 -2
- package/dist/components/Workspace.js +361 -346
- package/dist/components/WorkspaceBrowser.d.ts +4 -7
- package/dist/components/WorkspaceBrowser.js +16 -26
- package/dist/components/WorkspaceExplorer.d.ts +5 -33
- package/dist/components/WorkspaceExplorer.js +19 -32
- package/dist/components/WorkspaceFile.d.ts +1 -1
- package/dist/components/WorkspaceFileView.d.ts +14 -2
- package/dist/components/WorkspaceFileView.js +1 -1
- package/dist/components/WorkspaceHeader.d.ts +0 -8
- package/dist/components/WorkspaceHeader.js +3 -15
- package/dist/components/WorkspaceLink.d.ts +1 -1
- package/dist/components/WorkspaceLink.js +1 -1
- package/dist/components/icons.d.ts +2 -2
- package/dist/components/icons.js +2 -2
- package/dist/{copy-button-DtPMgN7e.d.ts → copy-button-D7aAYA-2.d.ts} +2 -3
- package/dist/{copy-button-Dejn5heL.js → copy-button-DeK6KXEV.js} +3 -2
- package/dist/{icons-CpfUer49.js → icons-CQJ-aMnI.js} +7 -3
- package/dist/{icons-GQd1xF4e.d.ts → icons-CYXmvKlJ.d.ts} +22 -2
- package/dist/navigation-link-Cob7KBlM.js +19 -0
- package/dist/styles/accordion.css +4 -19
- package/dist/styles/activity.css +48 -56
- package/dist/styles/agent-activity-preview.css +6 -0
- package/dist/styles/agent-chat.css +14 -63
- package/dist/styles/agent-connection.css +0 -12
- package/dist/styles/agent-tool-detail.css +54 -0
- package/dist/styles/alert-dialog.css +16 -18
- package/dist/styles/app-top-bar.css +17 -9
- package/dist/styles/approval.css +177 -0
- package/dist/styles/artifact.css +6 -18
- package/dist/styles/autocomplete.css +2 -1
- package/dist/styles/avatar.css +35 -30
- package/dist/styles/badge.css +10 -10
- package/dist/styles/base-ui-motion.css +94 -39
- package/dist/styles/browser-control-overlay.css +0 -1
- package/dist/styles/browser-live-view.css +39 -22
- package/dist/styles/browser-replay.css +1 -1
- package/dist/styles/browser-run-panel.css +13 -6
- package/dist/styles/button.css +36 -33
- package/dist/styles/card.css +5 -6
- package/dist/styles/chain-of-thought.css +22 -24
- package/dist/styles/checkbox.css +18 -5
- package/dist/styles/checkpoint.css +58 -0
- package/dist/styles/codex-model-selector.css +3 -7
- package/dist/styles/collapsible.css +10 -10
- package/dist/styles/combobox.css +4 -3
- package/dist/styles/commit.css +19 -39
- package/dist/styles/composition-motion.css +83 -0
- package/dist/styles/context-menu.css +3 -11
- package/dist/styles/context.css +11 -10
- package/dist/styles/conversation.css +18 -23
- package/dist/styles/dialog.css +15 -15
- package/dist/styles/environment-variables.css +0 -13
- package/dist/styles/field.css +32 -12
- package/dist/styles/file-tree.css +66 -22
- package/dist/styles/form.css +1 -1
- package/dist/styles/index.css +13 -4
- package/dist/styles/inline-citation.css +107 -0
- package/dist/styles/input.css +2 -2
- package/dist/styles/marker.css +14 -13
- package/dist/styles/mcp-server-picker.css +20 -47
- package/dist/styles/media-preview-card.css +160 -0
- package/dist/styles/menu.css +11 -40
- package/dist/styles/menubar.css +12 -19
- package/dist/styles/message-scroller.css +0 -12
- package/dist/styles/message.css +25 -31
- package/dist/styles/meter.css +2 -2
- package/dist/styles/model-selector.css +16 -34
- package/dist/styles/motion-reduction.css +29 -0
- package/dist/styles/navigation-menu.css +14 -30
- package/dist/styles/number-field.css +22 -4
- package/dist/styles/plan.css +132 -0
- package/dist/styles/popover.css +15 -52
- package/dist/styles/preview-card.css +2 -32
- package/dist/styles/progress.css +8 -3
- package/dist/styles/prompt-input.css +76 -269
- package/dist/styles/queue.css +48 -32
- package/dist/styles/radio.css +19 -12
- package/dist/styles/reasoning.css +2 -1
- package/dist/styles/recipes.css +207 -26
- package/dist/styles/resizable-side-panel.css +4 -10
- package/dist/styles/responsive-sidebar-shell.css +32 -34
- package/dist/styles/scroll-area.css +32 -15
- package/dist/styles/search-field.css +21 -0
- package/dist/styles/select.css +19 -12
- package/dist/styles/slider.css +25 -29
- package/dist/styles/sources.css +3 -11
- package/dist/styles/stepper.css +36 -26
- package/dist/styles/subagent-run.css +13 -71
- package/dist/styles/switch.css +32 -29
- package/dist/styles/tabs.css +79 -23
- package/dist/styles/task.css +11 -23
- package/dist/styles/test-results.css +29 -36
- package/dist/styles/theme-mode-control.css +8 -0
- package/dist/styles/think-execution-workbench.css +18 -15
- package/dist/styles/think-full-app.css +51 -100
- package/dist/styles/think-routine-library.css +51 -40
- package/dist/styles/think-thread-picker.css +207 -50
- package/dist/styles/toast.css +48 -34
- package/dist/styles/toggle-group.css +2 -36
- package/dist/styles/toggle.css +29 -5
- package/dist/styles/toolbar.css +25 -27
- package/dist/styles/tooltip.css +2 -32
- package/dist/styles/transition-surface.css +55 -0
- package/dist/styles/utilities.css +31 -0
- package/dist/styles/web-preview.css +0 -21
- package/dist/styles/workspace-explorer.css +104 -99
- package/dist/summarize-tool-input-CqTcGRYy.js +15 -0
- package/dist/think-agent-Cip5KAPj.d.ts +7 -0
- package/dist/utils/codex-model-catalog.d.ts +4 -4
- package/dist/utils/mcp-server-catalog.d.ts +132 -0
- package/dist/utils/mcp-server-catalog.js +90 -0
- package/dist/utils/structured-code.d.ts +1 -1
- package/dist/workspace-path-L_KmjRjq.js +26 -0
- package/package.json +14 -9
- package/dist/Workspace-D39LxGvP.d.ts +0 -62
- package/dist/class-names-9UtZwb0J.js +0 -12
- package/dist/components/AppFrame.d.ts +0 -24
- package/dist/components/AppFrame.js +0 -25
- package/dist/components/Shell.d.ts +0 -163
- package/dist/components/Shell.js +0 -137
- package/dist/components/SubagentRun.d.ts +0 -86
- package/dist/components/SubagentRun.js +0 -108
- package/dist/styles/app-frame.css +0 -15
- package/dist/styles/shell.css +0 -122
- package/dist/summarize-tool-input-BUJsENSn.js +0 -12
|
@@ -1,33 +1,29 @@
|
|
|
1
|
+
import { n as isWorkspacePathWithinRoot, t as canonicalizeAbsoluteWorkspacePath } from "../workspace-path-L_KmjRjq.js";
|
|
1
2
|
import { getWorkspaceBasename, inferWorkspaceMedia } from "./WorkspaceFile.js";
|
|
2
3
|
import * as React from "react";
|
|
4
|
+
import { queryOptions, useQueries, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
3
5
|
//#region src/components/Workspace.ts
|
|
4
6
|
const DEFAULT_MAX_INLINE_ASSET_BYTES = 32 * 1024 * 1024;
|
|
5
7
|
const WORKSPACE_DIRECTORY_PAGE_SIZE = 1e3;
|
|
8
|
+
const ACTIVE_FILE_GC_TIME = 2e3;
|
|
6
9
|
const EMPTY_ENTRIES_BY_DIRECTORY = Object.freeze({});
|
|
7
10
|
const EMPTY_ENTRY_BY_PATH = /* @__PURE__ */ new Map();
|
|
8
11
|
const EMPTY_PATHS = /* @__PURE__ */ new Set();
|
|
12
|
+
const INACTIVE_FILE_INFO = {
|
|
13
|
+
path: "",
|
|
14
|
+
name: "",
|
|
15
|
+
type: "file",
|
|
16
|
+
mimeType: "text/plain",
|
|
17
|
+
size: 0,
|
|
18
|
+
createdAt: 0,
|
|
19
|
+
updatedAt: 0
|
|
20
|
+
};
|
|
21
|
+
const INACTIVE_FILE_ASSET_RESOLVER = () => null;
|
|
9
22
|
function toErrorMessage(error) {
|
|
10
23
|
return error instanceof Error ? error.message : String(error);
|
|
11
24
|
}
|
|
12
|
-
function
|
|
13
|
-
if (
|
|
14
|
-
const segments = [];
|
|
15
|
-
for (const segment of path.split("/")) {
|
|
16
|
-
if (!segment || segment === ".") continue;
|
|
17
|
-
if (segment === "..") segments.pop();
|
|
18
|
-
else segments.push(segment);
|
|
19
|
-
}
|
|
20
|
-
return `/${segments.join("/")}`;
|
|
21
|
-
}
|
|
22
|
-
function isPathWithinWorkspaceRoot(path, root) {
|
|
23
|
-
const normalizedPath = normalizeWorkspacePath(path);
|
|
24
|
-
const normalizedRoot = normalizeWorkspacePath(root);
|
|
25
|
-
if (!normalizedPath || !normalizedRoot) return false;
|
|
26
|
-
return normalizedRoot === "/" || normalizedPath === normalizedRoot || normalizedPath.startsWith(`${normalizedRoot}/`);
|
|
27
|
-
}
|
|
28
|
-
function getWorkspaceParentPath(path) {
|
|
29
|
-
const separatorIndex = path.lastIndexOf("/");
|
|
30
|
-
return separatorIndex <= 0 ? "/" : path.slice(0, separatorIndex);
|
|
25
|
+
function throwIfAborted(signal) {
|
|
26
|
+
if (signal.aborted) throw signal.reason ?? new DOMException("The query was cancelled.", "AbortError");
|
|
31
27
|
}
|
|
32
28
|
function getAssetDataSize(asset) {
|
|
33
29
|
if (asset.kind === "url") return void 0;
|
|
@@ -42,10 +38,7 @@ function normalizeWorkspaceAsset(asset, path, inferredMedia, info) {
|
|
|
42
38
|
size: asset.size ?? getAssetDataSize(asset) ?? info.size
|
|
43
39
|
};
|
|
44
40
|
return {
|
|
45
|
-
asset:
|
|
46
|
-
...asset,
|
|
47
|
-
...metadata
|
|
48
|
-
} : {
|
|
41
|
+
asset: {
|
|
49
42
|
...asset,
|
|
50
43
|
...metadata
|
|
51
44
|
},
|
|
@@ -65,360 +58,382 @@ async function readWorkspaceAssetBytes(source, path, info, maxInlineAssetBytes)
|
|
|
65
58
|
} : null;
|
|
66
59
|
}
|
|
67
60
|
/**
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
61
|
+
* Source/root prefix for cache inspection, cancellation, or removal.
|
|
62
|
+
* Do not broadly invalidate this prefix: active file queries must refresh in
|
|
63
|
+
* stat → resolver → content order. Use a resource option key or `refresh()`.
|
|
71
64
|
*/
|
|
72
|
-
function
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
source,
|
|
97
|
-
root,
|
|
98
|
-
generation: 0
|
|
99
|
-
});
|
|
100
|
-
if (sourceIdentityRef.current.source !== source || sourceIdentityRef.current.root !== root) sourceIdentityRef.current = {
|
|
101
|
-
source,
|
|
102
|
-
root,
|
|
103
|
-
generation: sourceIdentityRef.current.generation + 1
|
|
65
|
+
function workspaceQueryKey(sourceKey, root) {
|
|
66
|
+
return [
|
|
67
|
+
"workspace",
|
|
68
|
+
sourceKey,
|
|
69
|
+
root
|
|
70
|
+
];
|
|
71
|
+
}
|
|
72
|
+
function workspaceFileQueryKey(sourceKey, root, requestedPath) {
|
|
73
|
+
return [
|
|
74
|
+
...workspaceQueryKey(sourceKey, root),
|
|
75
|
+
"file",
|
|
76
|
+
requestedPath
|
|
77
|
+
];
|
|
78
|
+
}
|
|
79
|
+
function workspaceFileVersion(target) {
|
|
80
|
+
return {
|
|
81
|
+
path: target.readPath,
|
|
82
|
+
name: target.info.name,
|
|
83
|
+
type: target.info.type,
|
|
84
|
+
mimeType: target.info.mimeType ?? null,
|
|
85
|
+
size: target.info.size,
|
|
86
|
+
createdAt: target.info.createdAt,
|
|
87
|
+
updatedAt: target.info.updatedAt,
|
|
88
|
+
target: target.info.target ?? null
|
|
104
89
|
};
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
return next;
|
|
116
|
-
});
|
|
117
|
-
}, []);
|
|
118
|
-
const setDirectoryError = React.useCallback((path, message) => {
|
|
119
|
-
setDirectoryErrorsByPath((current) => {
|
|
120
|
-
if (message !== null) {
|
|
121
|
-
if (current[path] === message) return current;
|
|
122
|
-
return {
|
|
123
|
-
...current,
|
|
124
|
-
[path]: message
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
if (!Object.hasOwn(current, path)) return current;
|
|
128
|
-
const next = { ...current };
|
|
129
|
-
delete next[path];
|
|
130
|
-
return next;
|
|
131
|
-
});
|
|
132
|
-
}, []);
|
|
133
|
-
const activateAssetFile = React.useCallback((file) => {
|
|
134
|
-
setFilesByPath((current) => {
|
|
135
|
-
if (!Object.hasOwn(current, file.path)) return current;
|
|
136
|
-
const next = { ...current };
|
|
137
|
-
delete next[file.path];
|
|
138
|
-
return next;
|
|
139
|
-
});
|
|
140
|
-
setActiveAssetFile(file);
|
|
141
|
-
}, []);
|
|
142
|
-
const cacheTextFile = React.useCallback((file) => {
|
|
143
|
-
setActiveAssetFile((current) => current?.path === file.path ? null : current);
|
|
144
|
-
setFilesByPath((current) => ({
|
|
145
|
-
...current,
|
|
146
|
-
[file.path]: file
|
|
147
|
-
}));
|
|
148
|
-
}, []);
|
|
149
|
-
const cancelFileLoad = React.useCallback(() => {
|
|
150
|
-
const request = fileRequestRef.current;
|
|
151
|
-
if (!request) return;
|
|
152
|
-
request.controller.abort();
|
|
153
|
-
fileRequestRef.current = null;
|
|
154
|
-
markLoading(request.path, false);
|
|
155
|
-
}, [markLoading]);
|
|
156
|
-
const loadDirectory = React.useCallback(async (path, { force = false } = {}) => {
|
|
157
|
-
if (!force && loadedDirectoriesRef.current.has(path)) return;
|
|
158
|
-
const identity = sourceIdentityRef.current;
|
|
159
|
-
if (identity.source !== source || identity.root !== root) return;
|
|
160
|
-
const generation = identity.generation;
|
|
161
|
-
const requestVersion = nextDirectoryRequestVersionRef.current + 1;
|
|
162
|
-
nextDirectoryRequestVersionRef.current = requestVersion;
|
|
163
|
-
directoryRequestVersionsRef.current.set(path, requestVersion);
|
|
164
|
-
const requestIsCurrent = () => generation === sourceIdentityRef.current.generation && directoryRequestVersionsRef.current.get(path) === requestVersion;
|
|
165
|
-
markLoading(path, true);
|
|
166
|
-
try {
|
|
90
|
+
}
|
|
91
|
+
/** Shared directory options for workspace components and route loaders. */
|
|
92
|
+
function workspaceDirectoryQueryOptions(source, sourceKey, root, path) {
|
|
93
|
+
return queryOptions({
|
|
94
|
+
queryKey: [
|
|
95
|
+
...workspaceQueryKey(sourceKey, root),
|
|
96
|
+
"directory",
|
|
97
|
+
path
|
|
98
|
+
],
|
|
99
|
+
queryFn: async ({ signal }) => {
|
|
167
100
|
const entries = [];
|
|
168
101
|
let offset = 0;
|
|
169
102
|
for (;;) {
|
|
103
|
+
throwIfAborted(signal);
|
|
170
104
|
const page = await source.readDir(path, {
|
|
171
105
|
limit: WORKSPACE_DIRECTORY_PAGE_SIZE,
|
|
172
106
|
offset
|
|
173
107
|
});
|
|
174
|
-
|
|
108
|
+
throwIfAborted(signal);
|
|
175
109
|
entries.push(...page);
|
|
176
|
-
if (page.length < WORKSPACE_DIRECTORY_PAGE_SIZE)
|
|
110
|
+
if (page.length < WORKSPACE_DIRECTORY_PAGE_SIZE) return entries;
|
|
177
111
|
offset += page.length;
|
|
178
112
|
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
cancelFileLoad();
|
|
207
|
-
const controller = new AbortController();
|
|
208
|
-
const request = {
|
|
209
|
-
path,
|
|
210
|
-
controller
|
|
211
|
-
};
|
|
212
|
-
fileRequestRef.current = request;
|
|
213
|
-
markLoading(path, true);
|
|
214
|
-
let fileInfo = listedFileInfo;
|
|
215
|
-
let media = inferWorkspaceMedia(path, fileInfo?.mimeType);
|
|
216
|
-
const requestIsCurrent = () => !controller.signal.aborted && generation === sourceIdentityRef.current.generation && selectedPathRef.current === path && (refreshRequestVersion === void 0 || refreshRequestVersionRef.current === refreshRequestVersion);
|
|
217
|
-
try {
|
|
218
|
-
if (!isPathWithinWorkspaceRoot(path, root)) throw new Error("This file is outside the configured workspace root.");
|
|
219
|
-
const resolvedInfo = await source.stat(path);
|
|
220
|
-
if (!requestIsCurrent()) return;
|
|
221
|
-
if (!resolvedInfo) {
|
|
222
|
-
fileInfo = null;
|
|
223
|
-
throw new Error("File metadata is unavailable because source.stat() returned null.");
|
|
224
|
-
}
|
|
225
|
-
fileInfo = resolvedInfo;
|
|
226
|
-
const readPath = normalizeWorkspacePath(resolvedInfo.path);
|
|
113
|
+
},
|
|
114
|
+
staleTime: Infinity
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
/** Shared workspace-summary options for workspace components and route loaders. */
|
|
118
|
+
function workspaceInfoQueryOptions(source, sourceKey, root) {
|
|
119
|
+
return queryOptions({
|
|
120
|
+
queryKey: [...workspaceQueryKey(sourceKey, root), "info"],
|
|
121
|
+
queryFn: async ({ signal }) => {
|
|
122
|
+
if (!("getWorkspaceInfo" in source) || typeof source.getWorkspaceInfo !== "function") return null;
|
|
123
|
+
const info = await source.getWorkspaceInfo();
|
|
124
|
+
throwIfAborted(signal);
|
|
125
|
+
return info;
|
|
126
|
+
},
|
|
127
|
+
staleTime: Infinity
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
/** Re-stat and validate a requested path before any resolver or file read. */
|
|
131
|
+
function workspaceFileStatQueryOptions(source, sourceKey, root, requestedPath) {
|
|
132
|
+
return queryOptions({
|
|
133
|
+
queryKey: [...workspaceFileQueryKey(sourceKey, root, requestedPath), "stat"],
|
|
134
|
+
queryFn: async ({ signal }) => {
|
|
135
|
+
if (!isWorkspacePathWithinRoot(requestedPath, root)) throw new Error("This file is outside the configured workspace root.");
|
|
136
|
+
const info = await source.stat(requestedPath);
|
|
137
|
+
throwIfAborted(signal);
|
|
138
|
+
if (!info) throw new Error("File metadata is unavailable because source.stat() returned null.");
|
|
139
|
+
const readPath = canonicalizeAbsoluteWorkspacePath(info.path);
|
|
227
140
|
if (!readPath) throw new Error("The workspace source returned an invalid file path from stat().");
|
|
228
|
-
if (readPath !==
|
|
229
|
-
if (!
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
root: normalizeWorkspacePath(root) ?? root,
|
|
236
|
-
info: resolvedInfo,
|
|
237
|
-
signal: controller.signal
|
|
238
|
-
}) : null;
|
|
239
|
-
if (!requestIsCurrent()) return;
|
|
240
|
-
if (resolvedAsset) {
|
|
241
|
-
const normalized = normalizeWorkspaceAsset(resolvedAsset, readPath, media, resolvedInfo);
|
|
242
|
-
if (!normalized) throw new Error("The host returned an asset without a supported image, PDF, audio, or video MIME type.");
|
|
243
|
-
media = normalized.media;
|
|
244
|
-
activateAssetFile({
|
|
245
|
-
path,
|
|
246
|
-
name: getWorkspaceBasename(path),
|
|
247
|
-
content: null,
|
|
248
|
-
asset: normalized.asset,
|
|
249
|
-
info: resolvedInfo,
|
|
250
|
-
error: null
|
|
251
|
-
});
|
|
252
|
-
return;
|
|
253
|
-
}
|
|
254
|
-
if (media) {
|
|
255
|
-
const byteAsset = await readWorkspaceAssetBytes(source, readPath, resolvedInfo, maxInlineAssetBytesRef.current);
|
|
256
|
-
if (!requestIsCurrent()) return;
|
|
257
|
-
const normalized = byteAsset ? normalizeWorkspaceAsset(byteAsset, readPath, media, resolvedInfo) : null;
|
|
258
|
-
activateAssetFile({
|
|
259
|
-
path,
|
|
260
|
-
name: getWorkspaceBasename(path),
|
|
261
|
-
content: null,
|
|
262
|
-
asset: normalized?.asset ?? null,
|
|
263
|
-
info: resolvedInfo,
|
|
264
|
-
error: null
|
|
265
|
-
});
|
|
266
|
-
return;
|
|
267
|
-
}
|
|
268
|
-
const content = await source.readFile(readPath);
|
|
269
|
-
if (!requestIsCurrent()) return;
|
|
270
|
-
cacheTextFile({
|
|
271
|
-
path,
|
|
272
|
-
name: getWorkspaceBasename(path),
|
|
273
|
-
content,
|
|
274
|
-
asset: null,
|
|
275
|
-
info: resolvedInfo,
|
|
276
|
-
error: null
|
|
277
|
-
});
|
|
278
|
-
} catch (readError) {
|
|
279
|
-
if (!requestIsCurrent()) return;
|
|
280
|
-
const failedFile = {
|
|
281
|
-
path,
|
|
282
|
-
name: getWorkspaceBasename(path),
|
|
283
|
-
content: null,
|
|
284
|
-
asset: null,
|
|
285
|
-
info: fileInfo,
|
|
286
|
-
error: toErrorMessage(readError)
|
|
141
|
+
if (readPath !== info.path) throw new Error("The workspace source returned a non-canonical file path from stat().");
|
|
142
|
+
if (!isWorkspacePathWithinRoot(readPath, root)) throw new Error("This file's resolved path is outside the configured workspace root.");
|
|
143
|
+
return {
|
|
144
|
+
requestedPath,
|
|
145
|
+
readPath,
|
|
146
|
+
info,
|
|
147
|
+
media: inferWorkspaceMedia(readPath, info.mimeType)
|
|
287
148
|
};
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
149
|
+
},
|
|
150
|
+
staleTime: 0,
|
|
151
|
+
refetchOnMount: "always",
|
|
152
|
+
refetchOnWindowFocus: false,
|
|
153
|
+
refetchOnReconnect: false,
|
|
154
|
+
retry: false
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
/** Optional host asset resolution, scoped to the current stat result. */
|
|
158
|
+
function workspaceFileAssetQueryOptions(sourceKey, root, target, resolveFileAsset) {
|
|
159
|
+
return queryOptions({
|
|
160
|
+
queryKey: [
|
|
161
|
+
...workspaceFileQueryKey(sourceKey, root, target.requestedPath),
|
|
162
|
+
"asset",
|
|
163
|
+
workspaceFileVersion(target)
|
|
164
|
+
],
|
|
165
|
+
queryFn: async ({ signal }) => {
|
|
166
|
+
const resolvedAsset = await resolveFileAsset({
|
|
167
|
+
path: target.readPath,
|
|
168
|
+
requestedPath: target.requestedPath,
|
|
169
|
+
root: canonicalizeAbsoluteWorkspacePath(root) ?? root,
|
|
170
|
+
info: target.info,
|
|
171
|
+
signal
|
|
172
|
+
});
|
|
173
|
+
if (!resolvedAsset) return null;
|
|
174
|
+
const normalized = normalizeWorkspaceAsset(resolvedAsset, target.readPath, target.media, target.info);
|
|
175
|
+
if (!normalized) throw new Error("The host returned an asset without a supported image, PDF, audio, or video MIME type.");
|
|
176
|
+
return normalized;
|
|
177
|
+
},
|
|
178
|
+
staleTime: 0,
|
|
179
|
+
gcTime: ACTIVE_FILE_GC_TIME,
|
|
180
|
+
refetchOnMount: "always",
|
|
181
|
+
refetchOnWindowFocus: false,
|
|
182
|
+
refetchOnReconnect: false,
|
|
183
|
+
retry: false
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
/** Cached text read options, scoped to the validated stat result. */
|
|
187
|
+
function workspaceTextFileQueryOptions(source, sourceKey, root, target) {
|
|
188
|
+
return queryOptions({
|
|
189
|
+
queryKey: [
|
|
190
|
+
...workspaceFileQueryKey(sourceKey, root, target.requestedPath),
|
|
191
|
+
"text",
|
|
192
|
+
workspaceFileVersion(target)
|
|
193
|
+
],
|
|
194
|
+
queryFn: async ({ signal }) => {
|
|
195
|
+
const content = await source.readFile(target.readPath);
|
|
196
|
+
throwIfAborted(signal);
|
|
197
|
+
return content;
|
|
198
|
+
},
|
|
199
|
+
staleTime: Infinity
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
/** Active-file-only buffered asset options, scoped to the validated stat result. */
|
|
203
|
+
function workspaceBinaryFileQueryOptions(source, sourceKey, root, target, maxInlineAssetBytes) {
|
|
204
|
+
return queryOptions({
|
|
205
|
+
queryKey: [
|
|
206
|
+
...workspaceFileQueryKey(sourceKey, root, target.requestedPath),
|
|
207
|
+
"bytes",
|
|
208
|
+
workspaceFileVersion(target),
|
|
209
|
+
{ maxInlineAssetBytes }
|
|
210
|
+
],
|
|
211
|
+
queryFn: async ({ signal }) => {
|
|
212
|
+
const asset = await readWorkspaceAssetBytes(source, target.readPath, target.info, maxInlineAssetBytes);
|
|
213
|
+
throwIfAborted(signal);
|
|
214
|
+
return asset ? normalizeWorkspaceAsset(asset, target.readPath, target.media, target.info) : null;
|
|
215
|
+
},
|
|
216
|
+
staleTime: 0,
|
|
217
|
+
gcTime: ACTIVE_FILE_GC_TIME,
|
|
218
|
+
refetchOnMount: "always",
|
|
219
|
+
refetchOnWindowFocus: false,
|
|
220
|
+
refetchOnReconnect: false,
|
|
221
|
+
retry: false
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
async function refreshWorkspaceFile(queryClient, { source, sourceKey, root, selectedPath, resolveFileAsset, maxInlineAssetBytes }) {
|
|
225
|
+
if (!selectedPath) return;
|
|
226
|
+
const target = await queryClient.fetchQuery({
|
|
227
|
+
...workspaceFileStatQueryOptions(source, sourceKey, root, selectedPath),
|
|
228
|
+
staleTime: 0
|
|
229
|
+
});
|
|
230
|
+
if (resolveFileAsset) {
|
|
231
|
+
const options = workspaceFileAssetQueryOptions(sourceKey, root, target, resolveFileAsset);
|
|
232
|
+
if (!queryClient.getQueryState(options.queryKey)) return;
|
|
233
|
+
if (await queryClient.fetchQuery({
|
|
234
|
+
...options,
|
|
235
|
+
staleTime: 0
|
|
236
|
+
})) return;
|
|
237
|
+
}
|
|
238
|
+
if (target.media) {
|
|
239
|
+
const options = workspaceBinaryFileQueryOptions(source, sourceKey, root, target, maxInlineAssetBytes);
|
|
240
|
+
if (queryClient.getQueryState(options.queryKey)) await queryClient.fetchQuery({
|
|
241
|
+
...options,
|
|
242
|
+
staleTime: 0
|
|
343
243
|
});
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
const options = workspaceTextFileQueryOptions(source, sourceKey, root, target);
|
|
247
|
+
if (queryClient.getQueryState(options.queryKey)) await queryClient.fetchQuery({
|
|
248
|
+
...options,
|
|
249
|
+
staleTime: 0
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Headless state for browsing a Think workspace. TanStack Query owns remote
|
|
254
|
+
* directory, metadata, resolver, text, and byte lifecycles; the route owns
|
|
255
|
+
* selection, while this hook only keeps local tree expansion state.
|
|
256
|
+
*/
|
|
257
|
+
function useWorkspace({ source, sourceKey, root = "/", selectedPath, onSelectedPathChange, resolveFileAsset, maxInlineAssetBytes = DEFAULT_MAX_INLINE_ASSET_BYTES }) {
|
|
258
|
+
const queryClient = useQueryClient();
|
|
259
|
+
const scopeKey = JSON.stringify([sourceKey, root]);
|
|
260
|
+
const [expandedPathsByScope, setExpandedPathsByScope] = React.useState({});
|
|
261
|
+
const expandedPaths = expandedPathsByScope[scopeKey] ?? EMPTY_PATHS;
|
|
262
|
+
const latestExpansionRef = React.useRef({
|
|
263
|
+
scopeKey,
|
|
264
|
+
paths: expandedPaths
|
|
265
|
+
});
|
|
266
|
+
const normalizedMaxInlineAssetBytes = Number.isFinite(maxInlineAssetBytes) && maxInlineAssetBytes >= 0 ? maxInlineAssetBytes : DEFAULT_MAX_INLINE_ASSET_BYTES;
|
|
267
|
+
const directoryPaths = React.useMemo(() => [.../* @__PURE__ */ new Set([root, ...expandedPaths])].sort(), [expandedPaths, root]);
|
|
268
|
+
const directoryQueries = useQueries({ queries: directoryPaths.map((path) => workspaceDirectoryQueryOptions(source, sourceKey, root, path)) });
|
|
269
|
+
const infoQuery = useQuery({
|
|
270
|
+
...workspaceInfoQueryOptions(source, sourceKey, root),
|
|
271
|
+
enabled: "getWorkspaceInfo" in source && typeof source.getWorkspaceInfo === "function"
|
|
272
|
+
});
|
|
273
|
+
const statQuery = useQuery({
|
|
274
|
+
...workspaceFileStatQueryOptions(source, sourceKey, root, selectedPath ?? root),
|
|
275
|
+
enabled: selectedPath !== null
|
|
276
|
+
});
|
|
277
|
+
const target = selectedPath === null ? void 0 : statQuery.data;
|
|
278
|
+
const statSettled = target !== void 0 && statQuery.isSuccess && !statQuery.isFetching;
|
|
279
|
+
const queryTarget = target ?? {
|
|
280
|
+
requestedPath: selectedPath ?? root,
|
|
281
|
+
readPath: selectedPath ?? root,
|
|
282
|
+
info: INACTIVE_FILE_INFO,
|
|
283
|
+
media: null
|
|
284
|
+
};
|
|
285
|
+
const assetQuery = useQuery({
|
|
286
|
+
...workspaceFileAssetQueryOptions(sourceKey, root, queryTarget, resolveFileAsset ?? INACTIVE_FILE_ASSET_RESOLVER),
|
|
287
|
+
enabled: statSettled && resolveFileAsset !== void 0
|
|
288
|
+
});
|
|
289
|
+
const resolvedAsset = assetQuery.data ?? null;
|
|
290
|
+
const resolverSettled = !resolveFileAsset || assetQuery.isSuccess && !assetQuery.isFetching;
|
|
291
|
+
const textQuery = useQuery({
|
|
292
|
+
...workspaceTextFileQueryOptions(source, sourceKey, root, queryTarget),
|
|
293
|
+
enabled: statSettled && resolverSettled && !resolvedAsset && !target.media
|
|
294
|
+
});
|
|
295
|
+
const binaryQuery = useQuery({
|
|
296
|
+
...workspaceBinaryFileQueryOptions(source, sourceKey, root, queryTarget, normalizedMaxInlineAssetBytes),
|
|
297
|
+
enabled: statSettled && resolverSettled && !resolvedAsset && Boolean(target.media)
|
|
298
|
+
});
|
|
299
|
+
const entriesByDirectory = React.useMemo(() => {
|
|
300
|
+
const entries = {};
|
|
301
|
+
for (const [index, path] of directoryPaths.entries()) {
|
|
302
|
+
const data = directoryQueries[index]?.data;
|
|
303
|
+
if (data) entries[path] = data;
|
|
304
|
+
}
|
|
305
|
+
return entries;
|
|
306
|
+
}, [directoryPaths, directoryQueries]);
|
|
307
|
+
const entryByPath = React.useMemo(() => {
|
|
308
|
+
const entries = /* @__PURE__ */ new Map();
|
|
309
|
+
for (const directoryEntries of Object.values(entriesByDirectory)) for (const entry of directoryEntries) entries.set(entry.path, entry);
|
|
310
|
+
return entries;
|
|
311
|
+
}, [entriesByDirectory]);
|
|
312
|
+
const setExpandedPaths = React.useCallback((next) => {
|
|
313
|
+
latestExpansionRef.current = {
|
|
314
|
+
scopeKey,
|
|
315
|
+
paths: next
|
|
316
|
+
};
|
|
317
|
+
setExpandedPathsByScope((current) => ({
|
|
318
|
+
...current,
|
|
319
|
+
[scopeKey]: next
|
|
320
|
+
}));
|
|
321
|
+
}, [scopeKey]);
|
|
322
|
+
const selectFile = React.useCallback((path) => onSelectedPathChange?.(path), [onSelectedPathChange]);
|
|
323
|
+
const selectedError = statQuery.error ?? assetQuery.error ?? textQuery.error ?? binaryQuery.error;
|
|
324
|
+
let selectedFile = null;
|
|
325
|
+
if (selectedPath && selectedError) selectedFile = {
|
|
326
|
+
path: selectedPath,
|
|
327
|
+
name: getWorkspaceBasename(selectedPath),
|
|
328
|
+
content: null,
|
|
329
|
+
asset: null,
|
|
330
|
+
info: target?.info ?? null,
|
|
331
|
+
error: toErrorMessage(selectedError)
|
|
332
|
+
};
|
|
333
|
+
else if (selectedPath && statSettled && target && resolverSettled) {
|
|
334
|
+
if (resolvedAsset) selectedFile = {
|
|
335
|
+
path: selectedPath,
|
|
336
|
+
name: getWorkspaceBasename(selectedPath),
|
|
337
|
+
content: null,
|
|
338
|
+
asset: resolvedAsset.asset,
|
|
339
|
+
info: target.info,
|
|
340
|
+
error: null
|
|
341
|
+
};
|
|
342
|
+
else if (target.media && binaryQuery.isSuccess && !binaryQuery.isFetching) selectedFile = {
|
|
343
|
+
path: selectedPath,
|
|
344
|
+
name: getWorkspaceBasename(selectedPath),
|
|
345
|
+
content: null,
|
|
346
|
+
asset: binaryQuery.data?.asset ?? null,
|
|
347
|
+
info: target.info,
|
|
348
|
+
error: null
|
|
349
|
+
};
|
|
350
|
+
else if (!target.media && textQuery.isSuccess) selectedFile = {
|
|
351
|
+
path: selectedPath,
|
|
352
|
+
name: getWorkspaceBasename(selectedPath),
|
|
353
|
+
content: textQuery.data,
|
|
354
|
+
asset: null,
|
|
355
|
+
info: target.info,
|
|
356
|
+
error: null
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
const loadingPaths = React.useMemo(() => {
|
|
360
|
+
const paths = /* @__PURE__ */ new Set();
|
|
361
|
+
for (const [index, path] of directoryPaths.entries()) if (directoryQueries[index]?.isFetching) paths.add(path);
|
|
362
|
+
if (selectedPath && [
|
|
363
|
+
statQuery,
|
|
364
|
+
assetQuery,
|
|
365
|
+
textQuery,
|
|
366
|
+
binaryQuery
|
|
367
|
+
].some((query) => query.isFetching)) paths.add(selectedPath);
|
|
368
|
+
return paths;
|
|
344
369
|
}, [
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
370
|
+
assetQuery,
|
|
371
|
+
binaryQuery,
|
|
372
|
+
directoryPaths,
|
|
373
|
+
directoryQueries,
|
|
374
|
+
selectedPath,
|
|
375
|
+
statQuery,
|
|
376
|
+
textQuery
|
|
349
377
|
]);
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
const setExpandedPaths = React.useCallback((next) => {
|
|
354
|
-
setExpandedPathsState((current) => {
|
|
355
|
-
for (const path of next) if (!current.has(path)) loadDirectory(path);
|
|
356
|
-
return next;
|
|
357
|
-
});
|
|
358
|
-
}, [loadDirectory]);
|
|
359
|
-
const selectFile = React.useCallback((path) => {
|
|
360
|
-
cancelFileLoad();
|
|
361
|
-
selectedPathRef.current = path;
|
|
362
|
-
setActiveAssetFile(null);
|
|
363
|
-
setSelectedPath(path);
|
|
364
|
-
if (path !== null) loadFile(path);
|
|
365
|
-
}, [cancelFileLoad, loadFile]);
|
|
378
|
+
const rootDirectoryIndex = directoryPaths.indexOf(root);
|
|
379
|
+
const isLoading = Boolean(directoryQueries[rootDirectoryIndex]?.isFetching) || infoQuery.isFetching;
|
|
380
|
+
const error = [...new Set(directoryQueries.map((query) => query.error).filter((queryError) => queryError !== null).map(toErrorMessage))].join("; ") || null;
|
|
366
381
|
const refresh = React.useCallback(() => {
|
|
367
382
|
(async () => {
|
|
368
|
-
const
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
const
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
setIsLoading(true);
|
|
377
|
-
try {
|
|
378
|
-
const directoryPaths = [.../* @__PURE__ */ new Set([root, ...expandedPaths])];
|
|
379
|
-
const [refreshedListings] = await Promise.all([Promise.all(directoryPaths.map((path) => loadDirectory(path, { force: true }))), loadInfo()]);
|
|
380
|
-
if (!requestIsCurrent()) return;
|
|
381
|
-
const refreshedSelectedPath = selectedPathRef.current;
|
|
382
|
-
if (refreshedSelectedPath) {
|
|
383
|
-
const selectedDirectoryIndex = directoryPaths.indexOf(getWorkspaceParentPath(refreshedSelectedPath));
|
|
384
|
-
const selectedDirectoryListing = refreshedListings[selectedDirectoryIndex];
|
|
385
|
-
if (selectedDirectoryIndex >= 0 && (selectedDirectoryListing === null || selectedDirectoryListing === void 0)) return;
|
|
386
|
-
await loadFile(refreshedSelectedPath, {
|
|
387
|
-
force: true,
|
|
388
|
-
refreshRequestVersion
|
|
383
|
+
const latestExpandedPaths = latestExpansionRef.current.scopeKey === scopeKey ? latestExpansionRef.current.paths : expandedPaths;
|
|
384
|
+
const refreshedDirectoryPaths = [.../* @__PURE__ */ new Set([root, ...latestExpandedPaths])].sort();
|
|
385
|
+
await queryClient.cancelQueries({ queryKey: workspaceQueryKey(sourceKey, root) });
|
|
386
|
+
const refreshedDirectories = await Promise.all(refreshedDirectoryPaths.map(async (path) => {
|
|
387
|
+
try {
|
|
388
|
+
await queryClient.fetchQuery({
|
|
389
|
+
...workspaceDirectoryQueryOptions(source, sourceKey, root, path),
|
|
390
|
+
staleTime: 0
|
|
389
391
|
});
|
|
392
|
+
return true;
|
|
393
|
+
} catch {
|
|
394
|
+
return false;
|
|
390
395
|
}
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
396
|
+
}));
|
|
397
|
+
if ("getWorkspaceInfo" in source && typeof source.getWorkspaceInfo === "function") await queryClient.fetchQuery({
|
|
398
|
+
...workspaceInfoQueryOptions(source, sourceKey, root),
|
|
399
|
+
staleTime: 0
|
|
400
|
+
}).catch(() => void 0);
|
|
401
|
+
if (refreshedDirectories.includes(false)) return;
|
|
402
|
+
await refreshWorkspaceFile(queryClient, {
|
|
403
|
+
source,
|
|
404
|
+
sourceKey,
|
|
405
|
+
root,
|
|
406
|
+
selectedPath,
|
|
407
|
+
resolveFileAsset,
|
|
408
|
+
maxInlineAssetBytes: normalizedMaxInlineAssetBytes
|
|
409
|
+
});
|
|
410
|
+
})().catch(() => {});
|
|
395
411
|
}, [
|
|
396
412
|
expandedPaths,
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
413
|
+
normalizedMaxInlineAssetBytes,
|
|
414
|
+
queryClient,
|
|
415
|
+
resolveFileAsset,
|
|
400
416
|
root,
|
|
401
|
-
|
|
417
|
+
scopeKey,
|
|
418
|
+
selectedPath,
|
|
419
|
+
source,
|
|
420
|
+
sourceKey
|
|
402
421
|
]);
|
|
403
|
-
const stateIsCurrent = stateGeneration === sourceIdentityRef.current.generation;
|
|
404
|
-
const directoryError = [...new Set(Object.values(directoryErrorsByPath))].join("; ") || null;
|
|
405
|
-
const visibleSelectedPath = stateIsCurrent ? selectedPath : null;
|
|
406
|
-
const selectedFile = visibleSelectedPath ? activeAssetFile?.path === visibleSelectedPath ? activeAssetFile : filesByPath[visibleSelectedPath] ?? null : null;
|
|
407
422
|
return {
|
|
408
423
|
root,
|
|
409
|
-
entriesByDirectory:
|
|
410
|
-
entryByPath:
|
|
411
|
-
expandedPaths
|
|
424
|
+
entriesByDirectory: Object.keys(entriesByDirectory).length > 0 ? entriesByDirectory : EMPTY_ENTRIES_BY_DIRECTORY,
|
|
425
|
+
entryByPath: entryByPath.size > 0 ? entryByPath : EMPTY_ENTRY_BY_PATH,
|
|
426
|
+
expandedPaths,
|
|
412
427
|
setExpandedPaths,
|
|
413
|
-
selectedPath
|
|
428
|
+
selectedPath,
|
|
414
429
|
selectFile,
|
|
415
430
|
selectedFile,
|
|
416
|
-
isLoading
|
|
417
|
-
loadingPaths:
|
|
418
|
-
error
|
|
419
|
-
info:
|
|
431
|
+
isLoading,
|
|
432
|
+
loadingPaths: loadingPaths.size > 0 ? loadingPaths : EMPTY_PATHS,
|
|
433
|
+
error,
|
|
434
|
+
info: infoQuery.data ?? null,
|
|
420
435
|
refresh
|
|
421
436
|
};
|
|
422
437
|
}
|
|
423
438
|
//#endregion
|
|
424
|
-
export { useWorkspace };
|
|
439
|
+
export { useWorkspace, workspaceBinaryFileQueryOptions, workspaceDirectoryQueryOptions, workspaceFileAssetQueryOptions, workspaceFileStatQueryOptions, workspaceInfoQueryOptions, workspaceQueryKey, workspaceTextFileQueryOptions };
|