@bendyline/docblocks-react 1.1.2 → 2.0.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/README.md +31 -5
- package/dist/AppMenu/AppMenu.d.ts +29 -2
- package/dist/AppMenu/AppMenu.d.ts.map +1 -1
- package/dist/AppMenu/AppMenu.js +41 -2
- package/dist/AppMenu/AppMenu.js.map +1 -1
- package/dist/AppMenu/index.d.ts +1 -1
- package/dist/AppMenu/index.d.ts.map +1 -1
- package/dist/DocBlocksShell/DocBlocksShell.d.ts +15 -2
- package/dist/DocBlocksShell/DocBlocksShell.d.ts.map +1 -1
- package/dist/DocBlocksShell/DocBlocksShell.js +1677 -298
- package/dist/DocBlocksShell/DocBlocksShell.js.map +1 -1
- package/dist/DocBlocksShell/LazyEditorShell.d.ts +3 -0
- package/dist/DocBlocksShell/LazyEditorShell.d.ts.map +1 -0
- package/dist/DocBlocksShell/LazyEditorShell.js +3 -0
- package/dist/DocBlocksShell/LazyEditorShell.js.map +1 -0
- package/dist/DocBlocksShell/UpdateAvailableNotice.d.ts +13 -0
- package/dist/DocBlocksShell/UpdateAvailableNotice.d.ts.map +1 -0
- package/dist/DocBlocksShell/UpdateAvailableNotice.js +16 -0
- package/dist/DocBlocksShell/UpdateAvailableNotice.js.map +1 -0
- package/dist/DocBlocksShell/document-title.d.ts +3 -0
- package/dist/DocBlocksShell/document-title.d.ts.map +1 -0
- package/dist/DocBlocksShell/document-title.js +17 -0
- package/dist/DocBlocksShell/document-title.js.map +1 -0
- package/dist/DocBlocksShell/workspace-authority-barrier.d.ts +14 -0
- package/dist/DocBlocksShell/workspace-authority-barrier.d.ts.map +1 -0
- package/dist/DocBlocksShell/workspace-authority-barrier.js +23 -0
- package/dist/DocBlocksShell/workspace-authority-barrier.js.map +1 -0
- package/dist/Export/DeferredExportToolbarControls.d.ts +5 -0
- package/dist/Export/DeferredExportToolbarControls.d.ts.map +1 -0
- package/dist/Export/DeferredExportToolbarControls.js +10 -0
- package/dist/Export/DeferredExportToolbarControls.js.map +1 -0
- package/dist/Export/ExportDialog.d.ts +10 -1
- package/dist/Export/ExportDialog.d.ts.map +1 -1
- package/dist/Export/ExportDialog.js +20 -18
- package/dist/Export/ExportDialog.js.map +1 -1
- package/dist/Export/ExportToolbarControls.d.ts +21 -1
- package/dist/Export/ExportToolbarControls.d.ts.map +1 -1
- package/dist/Export/ExportToolbarControls.js +96 -11
- package/dist/Export/ExportToolbarControls.js.map +1 -1
- package/dist/Export/export-destination.d.ts +3 -0
- package/dist/Export/export-destination.d.ts.map +1 -0
- package/dist/Export/export-destination.js +32 -0
- package/dist/Export/export-destination.js.map +1 -0
- package/dist/Export/index.d.ts +8 -4
- package/dist/Export/index.d.ts.map +1 -1
- package/dist/Export/index.js +4 -1
- package/dist/Export/index.js.map +1 -1
- package/dist/Export/public-api.d.ts +12 -0
- package/dist/Export/public-api.d.ts.map +1 -0
- package/dist/Export/public-api.js +9 -0
- package/dist/Export/public-api.js.map +1 -0
- package/dist/Export/run-export.d.ts +3 -1
- package/dist/Export/run-export.d.ts.map +1 -1
- package/dist/Export/run-export.js +30 -13
- package/dist/Export/run-export.js.map +1 -1
- package/dist/ExportDialog-MEUISWZX.js +9 -0
- package/dist/ExportDialog-MEUISWZX.js.map +1 -0
- package/dist/ExportToolbarControls-D2YDWOXW.js +373 -0
- package/dist/ExportToolbarControls-D2YDWOXW.js.map +1 -0
- package/dist/FileExplorer/FileExplorer.d.ts +26 -4
- package/dist/FileExplorer/FileExplorer.d.ts.map +1 -1
- package/dist/FileExplorer/FileExplorer.js +204 -29
- package/dist/FileExplorer/FileExplorer.js.map +1 -1
- package/dist/FileExplorer/FileTreeNode.d.ts +24 -3
- package/dist/FileExplorer/FileTreeNode.d.ts.map +1 -1
- package/dist/FileExplorer/FileTreeNode.js +27 -8
- package/dist/FileExplorer/FileTreeNode.js.map +1 -1
- package/dist/FileExplorer/index.d.ts +1 -1
- package/dist/FileExplorer/index.d.ts.map +1 -1
- package/dist/FileExplorer/useFileTree.d.ts +5 -3
- package/dist/FileExplorer/useFileTree.d.ts.map +1 -1
- package/dist/FileExplorer/useFileTree.js +173 -13
- package/dist/FileExplorer/useFileTree.js.map +1 -1
- package/dist/Git/GitAuthGuidanceDialog.d.ts +18 -0
- package/dist/Git/GitAuthGuidanceDialog.d.ts.map +1 -0
- package/dist/Git/GitAuthGuidanceDialog.js +27 -0
- package/dist/Git/GitAuthGuidanceDialog.js.map +1 -0
- package/dist/Git/GitBranchesDialog.d.ts +13 -0
- package/dist/Git/GitBranchesDialog.d.ts.map +1 -0
- package/dist/Git/GitBranchesDialog.js +59 -0
- package/dist/Git/GitBranchesDialog.js.map +1 -0
- package/dist/Git/GitCloneDialog.d.ts +14 -0
- package/dist/Git/GitCloneDialog.d.ts.map +1 -0
- package/dist/Git/GitCloneDialog.js +79 -0
- package/dist/Git/GitCloneDialog.js.map +1 -0
- package/dist/Git/GitCommitDialog.d.ts +12 -0
- package/dist/Git/GitCommitDialog.d.ts.map +1 -0
- package/dist/Git/GitCommitDialog.js +38 -0
- package/dist/Git/GitCommitDialog.js.map +1 -0
- package/dist/Git/GitConflictsDialog.d.ts +12 -0
- package/dist/Git/GitConflictsDialog.d.ts.map +1 -0
- package/dist/Git/GitConflictsDialog.js +17 -0
- package/dist/Git/GitConflictsDialog.js.map +1 -0
- package/dist/Git/GitContext.d.ts +89 -0
- package/dist/Git/GitContext.d.ts.map +1 -0
- package/dist/Git/GitContext.js +15 -0
- package/dist/Git/GitContext.js.map +1 -0
- package/dist/Git/GitDiffDialog.d.ts +20 -0
- package/dist/Git/GitDiffDialog.d.ts.map +1 -0
- package/dist/Git/GitDiffDialog.js +100 -0
- package/dist/Git/GitDiffDialog.js.map +1 -0
- package/dist/Git/GitDiffView.d.ts +23 -0
- package/dist/Git/GitDiffView.d.ts.map +1 -0
- package/dist/Git/GitDiffView.js +77 -0
- package/dist/Git/GitDiffView.js.map +1 -0
- package/dist/Git/GitHistoryDialog.d.ts +15 -0
- package/dist/Git/GitHistoryDialog.d.ts.map +1 -0
- package/dist/Git/GitHistoryDialog.js +107 -0
- package/dist/Git/GitHistoryDialog.js.map +1 -0
- package/dist/Git/GitStatusBar.d.ts +8 -0
- package/dist/Git/GitStatusBar.d.ts.map +1 -0
- package/dist/Git/GitStatusBar.js +49 -0
- package/dist/Git/GitStatusBar.js.map +1 -0
- package/dist/Git/GitToolbarControl.d.ts +15 -0
- package/dist/Git/GitToolbarControl.d.ts.map +1 -0
- package/dist/Git/GitToolbarControl.js +51 -0
- package/dist/Git/GitToolbarControl.js.map +1 -0
- package/dist/Git/GitUI.d.ts +14 -0
- package/dist/Git/GitUI.d.ts.map +1 -0
- package/dist/Git/GitUI.js +21 -0
- package/dist/Git/GitUI.js.map +1 -0
- package/dist/Git/commit-selection.d.ts +22 -0
- package/dist/Git/commit-selection.d.ts.map +1 -0
- package/dist/Git/commit-selection.js +47 -0
- package/dist/Git/commit-selection.js.map +1 -0
- package/dist/Git/git-clone-utils.d.ts +8 -0
- package/dist/Git/git-clone-utils.d.ts.map +1 -0
- package/dist/Git/git-clone-utils.js +26 -0
- package/dist/Git/git-clone-utils.js.map +1 -0
- package/dist/Git/git-status.d.ts +24 -0
- package/dist/Git/git-status.d.ts.map +1 -0
- package/dist/Git/git-status.js +105 -0
- package/dist/Git/git-status.js.map +1 -0
- package/dist/Git/useGit.d.ts +15 -0
- package/dist/Git/useGit.d.ts.map +1 -0
- package/dist/Git/useGit.js +206 -0
- package/dist/Git/useGit.js.map +1 -0
- package/dist/Git/useGitStatus.d.ts +17 -0
- package/dist/Git/useGitStatus.d.ts.map +1 -0
- package/dist/Git/useGitStatus.js +63 -0
- package/dist/Git/useGitStatus.js.map +1 -0
- package/dist/GitToolbarControl-LMIR4R7I.js +117 -0
- package/dist/GitToolbarControl-LMIR4R7I.js.map +1 -0
- package/dist/GitUI-KGF5MSNV.js +1048 -0
- package/dist/GitUI-KGF5MSNV.js.map +1 -0
- package/dist/LazyEditorShell-EF2BWRXU.js +6 -0
- package/dist/LazyEditorShell-EF2BWRXU.js.map +1 -0
- package/dist/Settings/Settings.d.ts +23 -0
- package/dist/Settings/Settings.d.ts.map +1 -0
- package/dist/Settings/Settings.js +22 -0
- package/dist/Settings/Settings.js.map +1 -0
- package/dist/Settings/public-api.d.ts +3 -0
- package/dist/Settings/public-api.d.ts.map +1 -0
- package/dist/Settings/public-api.js +2 -0
- package/dist/Settings/public-api.js.map +1 -0
- package/dist/WorkspacePicker/WorkspacePicker.d.ts +6 -1
- package/dist/WorkspacePicker/WorkspacePicker.d.ts.map +1 -1
- package/dist/WorkspacePicker/WorkspacePicker.js +16 -5
- package/dist/WorkspacePicker/WorkspacePicker.js.map +1 -1
- package/dist/chunk-3SAXDU2U.js +157 -0
- package/dist/chunk-3SAXDU2U.js.map +1 -0
- package/dist/chunk-4XXSWN3T.js +13 -0
- package/dist/chunk-4XXSWN3T.js.map +1 -0
- package/dist/chunk-5A4KEWKT.js +97 -0
- package/dist/chunk-5A4KEWKT.js.map +1 -0
- package/dist/chunk-AOVTHZU7.js +321 -0
- package/dist/chunk-AOVTHZU7.js.map +1 -0
- package/dist/chunk-DD4VFJQI.js +51 -0
- package/dist/chunk-DD4VFJQI.js.map +1 -0
- package/dist/chunk-GSNZSCIK.js +55 -0
- package/dist/chunk-GSNZSCIK.js.map +1 -0
- package/dist/chunk-VHDP4IPL.js +70 -0
- package/dist/chunk-VHDP4IPL.js.map +1 -0
- package/dist/chunk-ZI56BNB7.js +270 -0
- package/dist/chunk-ZI56BNB7.js.map +1 -0
- package/dist/components/Dialog.d.ts +22 -0
- package/dist/components/Dialog.d.ts.map +1 -0
- package/dist/components/Dialog.js +33 -0
- package/dist/components/Dialog.js.map +1 -0
- package/dist/editor.d.ts +10 -0
- package/dist/editor.d.ts.map +1 -0
- package/dist/editor.js +70 -0
- package/dist/editor.js.map +1 -0
- package/dist/export/index.d.ts +87 -0
- package/dist/export/index.js +26 -0
- package/dist/export/index.js.map +1 -0
- package/dist/hooks/index.d.ts +2 -1
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +1 -1
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/useDocumentSession.d.ts +16 -0
- package/dist/hooks/useDocumentSession.d.ts.map +1 -0
- package/dist/hooks/useDocumentSession.js +18 -0
- package/dist/hooks/useDocumentSession.js.map +1 -0
- package/dist/icons.d.ts +11 -6
- package/dist/icons.d.ts.map +1 -1
- package/dist/icons.js +21 -20
- package/dist/icons.js.map +1 -1
- package/dist/index.d.ts +8 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/preferences/theme.d.ts +18 -0
- package/dist/preferences/theme.d.ts.map +1 -0
- package/dist/preferences/theme.js +63 -0
- package/dist/preferences/theme.js.map +1 -0
- package/dist/provider-lease.d.ts +10 -0
- package/dist/provider-lease.d.ts.map +1 -0
- package/dist/provider-lease.js +42 -0
- package/dist/provider-lease.js.map +1 -0
- package/dist/run-export-ICTZITXC.js +10 -0
- package/dist/run-export-ICTZITXC.js.map +1 -0
- package/dist/settings/index.d.ts +28 -0
- package/dist/settings/index.js +12 -0
- package/dist/settings/index.js.map +1 -0
- package/package.json +24 -9
- package/src/AppMenu/AppMenu.tsx +169 -99
- package/src/AppMenu/index.ts +1 -1
- package/src/DocBlocksShell/DocBlocksShell.tsx +2157 -537
- package/src/DocBlocksShell/LazyEditorShell.ts +2 -0
- package/src/DocBlocksShell/UpdateAvailableNotice.tsx +60 -0
- package/src/DocBlocksShell/document-title.ts +19 -0
- package/src/DocBlocksShell/workspace-authority-barrier.ts +26 -0
- package/src/Export/DeferredExportToolbarControls.tsx +23 -0
- package/src/Export/ExportDialog.tsx +74 -20
- package/src/Export/ExportToolbarControls.tsx +238 -40
- package/src/Export/export-destination.ts +30 -0
- package/src/Export/index.ts +18 -4
- package/src/Export/public-api.ts +17 -0
- package/src/Export/run-export.ts +36 -11
- package/src/FileExplorer/FileExplorer.tsx +284 -38
- package/src/FileExplorer/FileTreeNode.tsx +100 -8
- package/src/FileExplorer/index.ts +1 -1
- package/src/FileExplorer/useFileTree.ts +190 -16
- package/src/Git/GitAuthGuidanceDialog.tsx +84 -0
- package/src/Git/GitBranchesDialog.tsx +144 -0
- package/src/Git/GitCloneDialog.tsx +200 -0
- package/src/Git/GitCommitDialog.tsx +119 -0
- package/src/Git/GitConflictsDialog.tsx +62 -0
- package/src/Git/GitContext.tsx +88 -0
- package/src/Git/GitDiffDialog.tsx +147 -0
- package/src/Git/GitDiffView.tsx +105 -0
- package/src/Git/GitHistoryDialog.tsx +195 -0
- package/src/Git/GitStatusBar.tsx +157 -0
- package/src/Git/GitToolbarControl.tsx +123 -0
- package/src/Git/GitUI.tsx +68 -0
- package/src/Git/commit-selection.ts +63 -0
- package/src/Git/git-clone-utils.ts +23 -0
- package/src/Git/git-status.ts +113 -0
- package/src/Git/useGit.ts +279 -0
- package/src/Git/useGitStatus.ts +78 -0
- package/src/Settings/Settings.tsx +118 -0
- package/src/Settings/public-api.ts +8 -0
- package/src/WorkspacePicker/WorkspacePicker.tsx +62 -8
- package/src/components/Dialog.tsx +81 -0
- package/src/editor.ts +72 -0
- package/src/hooks/index.ts +2 -1
- package/src/hooks/useDocumentSession.ts +37 -0
- package/src/icons.tsx +33 -55
- package/src/index.ts +35 -5
- package/src/preferences/theme.ts +67 -0
- package/src/provider-lease.ts +52 -0
- package/src/styles/docblocks.css +2174 -79
- package/src/types/pwa-dom.d.ts +31 -0
- package/dist/hooks/useAutoSave.d.ts +0 -15
- package/dist/hooks/useAutoSave.d.ts.map +0 -1
- package/dist/hooks/useAutoSave.js +0 -83
- package/dist/hooks/useAutoSave.js.map +0 -1
- package/dist/monaco-slim.d.ts +0 -19
- package/dist/monaco-slim.d.ts.map +0 -1
- package/dist/monaco-slim.js +0 -19
- package/dist/monaco-slim.js.map +0 -1
- package/src/fonts/fonts.css +0 -362
- package/src/fonts/licenses/LICENSE-cormorant-garamond.txt +0 -93
- package/src/fonts/licenses/LICENSE-crimson-text.txt +0 -93
- package/src/fonts/licenses/LICENSE-dm-sans.txt +0 -93
- package/src/fonts/licenses/LICENSE-dm-serif-display.txt +0 -93
- package/src/fonts/licenses/LICENSE-hanken-grotesk.txt +0 -94
- package/src/fonts/licenses/LICENSE-ibm-plex-sans.txt +0 -93
- package/src/fonts/licenses/LICENSE-inter.txt +0 -93
- package/src/fonts/licenses/LICENSE-jetbrains-mono.txt +0 -93
- package/src/fonts/licenses/LICENSE-lora.txt +0 -93
- package/src/fonts/licenses/LICENSE-merriweather.txt +0 -93
- package/src/fonts/licenses/LICENSE-oswald.txt +0 -93
- package/src/fonts/licenses/LICENSE-playfair-display.txt +0 -93
- package/src/fonts/licenses/LICENSE-pt-serif.txt +0 -93
- package/src/fonts/licenses/LICENSE-roboto.txt +0 -93
- package/src/fonts/licenses/LICENSE-source-serif-4.txt +0 -93
- package/src/fonts/woff2/cormorant-garamond-400.woff2 +0 -0
- package/src/fonts/woff2/cormorant-garamond-700.woff2 +0 -0
- package/src/fonts/woff2/crimson-text-400.woff2 +0 -0
- package/src/fonts/woff2/crimson-text-400i.woff2 +0 -0
- package/src/fonts/woff2/crimson-text-700.woff2 +0 -0
- package/src/fonts/woff2/dm-sans-400.woff2 +0 -0
- package/src/fonts/woff2/dm-sans-400i.woff2 +0 -0
- package/src/fonts/woff2/dm-sans-500.woff2 +0 -0
- package/src/fonts/woff2/dm-sans-700.woff2 +0 -0
- package/src/fonts/woff2/dm-serif-display-400.woff2 +0 -0
- package/src/fonts/woff2/hanken-grotesk-400.woff2 +0 -0
- package/src/fonts/woff2/hanken-grotesk-400i.woff2 +0 -0
- package/src/fonts/woff2/hanken-grotesk-500.woff2 +0 -0
- package/src/fonts/woff2/hanken-grotesk-600.woff2 +0 -0
- package/src/fonts/woff2/hanken-grotesk-700.woff2 +0 -0
- package/src/fonts/woff2/ibm-plex-sans-400.woff2 +0 -0
- package/src/fonts/woff2/ibm-plex-sans-400i.woff2 +0 -0
- package/src/fonts/woff2/ibm-plex-sans-500.woff2 +0 -0
- package/src/fonts/woff2/ibm-plex-sans-600.woff2 +0 -0
- package/src/fonts/woff2/ibm-plex-sans-700.woff2 +0 -0
- package/src/fonts/woff2/inter-400.woff2 +0 -0
- package/src/fonts/woff2/inter-400i.woff2 +0 -0
- package/src/fonts/woff2/inter-500.woff2 +0 -0
- package/src/fonts/woff2/inter-600.woff2 +0 -0
- package/src/fonts/woff2/inter-700.woff2 +0 -0
- package/src/fonts/woff2/jetbrains-mono-400.woff2 +0 -0
- package/src/fonts/woff2/jetbrains-mono-400i.woff2 +0 -0
- package/src/fonts/woff2/jetbrains-mono-700.woff2 +0 -0
- package/src/fonts/woff2/lora-400.woff2 +0 -0
- package/src/fonts/woff2/lora-400i.woff2 +0 -0
- package/src/fonts/woff2/lora-700.woff2 +0 -0
- package/src/fonts/woff2/merriweather-400.woff2 +0 -0
- package/src/fonts/woff2/merriweather-700.woff2 +0 -0
- package/src/fonts/woff2/oswald-400.woff2 +0 -0
- package/src/fonts/woff2/oswald-700.woff2 +0 -0
- package/src/fonts/woff2/playfair-display-400.woff2 +0 -0
- package/src/fonts/woff2/playfair-display-700.woff2 +0 -0
- package/src/fonts/woff2/pt-serif-400.woff2 +0 -0
- package/src/fonts/woff2/pt-serif-700.woff2 +0 -0
- package/src/fonts/woff2/roboto-400.woff2 +0 -0
- package/src/fonts/woff2/roboto-400i.woff2 +0 -0
- package/src/fonts/woff2/roboto-700.woff2 +0 -0
- package/src/fonts/woff2/source-serif-4-400.woff2 +0 -0
- package/src/fonts/woff2/source-serif-4-400i.woff2 +0 -0
- package/src/fonts/woff2/source-serif-4-700.woff2 +0 -0
- package/src/hooks/useAutoSave.ts +0 -116
- package/src/monaco-slim.ts +0 -20
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitBranchesDialog — switch between local branches or create a new one.
|
|
3
|
+
*
|
|
4
|
+
* Loads the branch list once from the host git API on mount. Remote
|
|
5
|
+
* branches are display-only in v1 (a collapsed disclosure); switching and
|
|
6
|
+
* creating go through the GitValue actions so errors (e.g. uncommitted
|
|
7
|
+
* changes blocking a checkout) surface inline via lastResult.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { useEffect, useRef, useState } from 'react';
|
|
11
|
+
import type { GitBranchInfo } from '@bendyline/docblocks/host';
|
|
12
|
+
import { Dialog } from '../components/Dialog.js';
|
|
13
|
+
import { useGitContext } from './GitContext.js';
|
|
14
|
+
|
|
15
|
+
export function GitBranchesDialog({
|
|
16
|
+
createFocus,
|
|
17
|
+
onClose,
|
|
18
|
+
}: {
|
|
19
|
+
createFocus?: boolean;
|
|
20
|
+
onClose: () => void;
|
|
21
|
+
}) {
|
|
22
|
+
const git = useGitContext();
|
|
23
|
+
const gitApi = git?.gitApi ?? null;
|
|
24
|
+
const repositoryId = git?.repositoryId ?? null;
|
|
25
|
+
|
|
26
|
+
const [branches, setBranches] = useState<GitBranchInfo[] | null>(null);
|
|
27
|
+
const [loadError, setLoadError] = useState<string | null>(null);
|
|
28
|
+
const [newName, setNewName] = useState('');
|
|
29
|
+
const createInputRef = useRef<HTMLInputElement>(null);
|
|
30
|
+
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
if (!gitApi || !repositoryId) return;
|
|
33
|
+
let cancelled = false;
|
|
34
|
+
void gitApi.listBranches(repositoryId).then((result) => {
|
|
35
|
+
if (cancelled) return;
|
|
36
|
+
if (result.ok) setBranches(result.value);
|
|
37
|
+
else setLoadError(result.error.message || 'Could not list branches');
|
|
38
|
+
});
|
|
39
|
+
return () => {
|
|
40
|
+
cancelled = true;
|
|
41
|
+
};
|
|
42
|
+
}, [gitApi, repositoryId]);
|
|
43
|
+
|
|
44
|
+
if (!git) return null;
|
|
45
|
+
|
|
46
|
+
const locals = branches?.filter((b) => b.kind === 'local') ?? [];
|
|
47
|
+
const remotes = branches?.filter((b) => b.kind === 'remote') ?? [];
|
|
48
|
+
const canCreate = newName.trim().length > 0 && git.busy === null;
|
|
49
|
+
|
|
50
|
+
const handleSwitch = async (name: string) => {
|
|
51
|
+
const ok = await git.switchBranch(name);
|
|
52
|
+
if (ok) onClose();
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const handleCreate = async () => {
|
|
56
|
+
if (!canCreate) return;
|
|
57
|
+
const ok = await git.createBranch(newName.trim());
|
|
58
|
+
if (ok) onClose();
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<Dialog
|
|
63
|
+
title="Branches"
|
|
64
|
+
onClose={onClose}
|
|
65
|
+
initialFocusRef={createFocus ? createInputRef : undefined}
|
|
66
|
+
>
|
|
67
|
+
{branches === null && loadError === null && <p className="db-git-hint">Loading branches…</p>}
|
|
68
|
+
{loadError !== null && (
|
|
69
|
+
<p className="db-git-form-error" role="alert">
|
|
70
|
+
{loadError}
|
|
71
|
+
</p>
|
|
72
|
+
)}
|
|
73
|
+
{branches !== null && (
|
|
74
|
+
<div className="db-git-branch-list">
|
|
75
|
+
{locals.map((branch) =>
|
|
76
|
+
branch.current ? (
|
|
77
|
+
<span
|
|
78
|
+
key={branch.name}
|
|
79
|
+
className="db-git-branch-row db-git-branch-row--current"
|
|
80
|
+
aria-current="true"
|
|
81
|
+
>
|
|
82
|
+
{branch.name}
|
|
83
|
+
</span>
|
|
84
|
+
) : (
|
|
85
|
+
<button
|
|
86
|
+
key={branch.name}
|
|
87
|
+
type="button"
|
|
88
|
+
className="db-git-branch-row"
|
|
89
|
+
disabled={git.busy !== null}
|
|
90
|
+
onClick={() => void handleSwitch(branch.name)}
|
|
91
|
+
>
|
|
92
|
+
{branch.name}
|
|
93
|
+
</button>
|
|
94
|
+
),
|
|
95
|
+
)}
|
|
96
|
+
</div>
|
|
97
|
+
)}
|
|
98
|
+
{git.lastResult?.tone === 'error' && (
|
|
99
|
+
<p className="db-git-form-error" role="alert">
|
|
100
|
+
{git.lastResult.message}
|
|
101
|
+
</p>
|
|
102
|
+
)}
|
|
103
|
+
<hr />
|
|
104
|
+
<div className="db-git-form-row">
|
|
105
|
+
<label className="db-git-form-label" htmlFor="db-git-new-branch-name">
|
|
106
|
+
New branch
|
|
107
|
+
</label>
|
|
108
|
+
<input
|
|
109
|
+
id="db-git-new-branch-name"
|
|
110
|
+
ref={createInputRef}
|
|
111
|
+
className="db-git-form-input"
|
|
112
|
+
type="text"
|
|
113
|
+
value={newName}
|
|
114
|
+
onChange={(e) => setNewName(e.target.value)}
|
|
115
|
+
onKeyDown={(e) => {
|
|
116
|
+
if (e.key === 'Enter') void handleCreate();
|
|
117
|
+
}}
|
|
118
|
+
placeholder="feature/my-branch"
|
|
119
|
+
spellCheck={false}
|
|
120
|
+
/>
|
|
121
|
+
<button
|
|
122
|
+
type="button"
|
|
123
|
+
className="db-git-primary-btn"
|
|
124
|
+
disabled={!canCreate}
|
|
125
|
+
onClick={() => void handleCreate()}
|
|
126
|
+
>
|
|
127
|
+
Create
|
|
128
|
+
</button>
|
|
129
|
+
</div>
|
|
130
|
+
{remotes.length > 0 && (
|
|
131
|
+
<details>
|
|
132
|
+
<summary>Remote branches ({remotes.length})</summary>
|
|
133
|
+
<div className="db-git-branch-list">
|
|
134
|
+
{remotes.map((branch) => (
|
|
135
|
+
<span key={branch.name} className="db-git-branch-row">
|
|
136
|
+
{branch.name}
|
|
137
|
+
</span>
|
|
138
|
+
))}
|
|
139
|
+
</div>
|
|
140
|
+
</details>
|
|
141
|
+
)}
|
|
142
|
+
</Dialog>
|
|
143
|
+
);
|
|
144
|
+
}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitCloneDialog — clone a remote repository into a new local workspace.
|
|
3
|
+
*
|
|
4
|
+
* The renderer only collects the URL; the main process shows the native
|
|
5
|
+
* destination picker, streams progress back, and registers the clone as a
|
|
6
|
+
* workspace. An auth failure swaps the body to the shared credential
|
|
7
|
+
* guidance copy (no credentials are ever collected here).
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { useEffect, useRef, useState } from 'react';
|
|
11
|
+
import type {
|
|
12
|
+
ElectronWorkspaceInfo,
|
|
13
|
+
GitCloneHandle,
|
|
14
|
+
GitCloneProgress,
|
|
15
|
+
} from '@bendyline/docblocks/host';
|
|
16
|
+
import { Dialog } from '../components/Dialog.js';
|
|
17
|
+
import { useGitContext } from './GitContext.js';
|
|
18
|
+
import { deriveCloneFolderName, isLikelyGitUrl } from './git-clone-utils.js';
|
|
19
|
+
import { GitCredentialGuidance } from './GitAuthGuidanceDialog.js';
|
|
20
|
+
|
|
21
|
+
export function GitCloneDialog({
|
|
22
|
+
onClose,
|
|
23
|
+
onCloned,
|
|
24
|
+
}: {
|
|
25
|
+
onClose: () => void;
|
|
26
|
+
onCloned: (info: ElectronWorkspaceInfo) => void;
|
|
27
|
+
}) {
|
|
28
|
+
const git = useGitContext();
|
|
29
|
+
const gitApi = git?.gitApi ?? null;
|
|
30
|
+
|
|
31
|
+
const [url, setUrl] = useState('');
|
|
32
|
+
const [cloning, setCloning] = useState(false);
|
|
33
|
+
const [progress, setProgress] = useState<GitCloneProgress | null>(null);
|
|
34
|
+
const [error, setError] = useState<string | null>(null);
|
|
35
|
+
/** Non-null → show embedded credential guidance instead of the form. */
|
|
36
|
+
const [authDetail, setAuthDetail] = useState<{ detail?: string } | null>(null);
|
|
37
|
+
const handleRef = useRef<GitCloneHandle | null>(null);
|
|
38
|
+
const urlInputRef = useRef<HTMLInputElement>(null);
|
|
39
|
+
|
|
40
|
+
// Closing the dialog mid-clone abandons it — kill git and clean up.
|
|
41
|
+
useEffect(
|
|
42
|
+
() => () => {
|
|
43
|
+
handleRef.current?.cancel();
|
|
44
|
+
},
|
|
45
|
+
[],
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
if (!gitApi || typeof gitApi.clone !== 'function') return null;
|
|
49
|
+
|
|
50
|
+
const canClone = isLikelyGitUrl(url) && !cloning;
|
|
51
|
+
|
|
52
|
+
const handleClone = async () => {
|
|
53
|
+
if (!canClone) return;
|
|
54
|
+
setCloning(true);
|
|
55
|
+
setError(null);
|
|
56
|
+
setProgress(null);
|
|
57
|
+
const handle = gitApi.clone(url.trim(), (p) => setProgress(p));
|
|
58
|
+
handleRef.current = handle;
|
|
59
|
+
const result = await handle.result;
|
|
60
|
+
handleRef.current = null;
|
|
61
|
+
setCloning(false);
|
|
62
|
+
setProgress(null);
|
|
63
|
+
if (!result.ok) {
|
|
64
|
+
switch (result.error.code) {
|
|
65
|
+
case 'invalid-url':
|
|
66
|
+
setError('That doesn’t look like a valid repository URL.');
|
|
67
|
+
break;
|
|
68
|
+
case 'destination-exists':
|
|
69
|
+
setError('A folder with that name already exists there. Pick a different location.');
|
|
70
|
+
break;
|
|
71
|
+
case 'auth-failed':
|
|
72
|
+
setAuthDetail({ detail: result.error.message });
|
|
73
|
+
break;
|
|
74
|
+
case 'cancelled':
|
|
75
|
+
break; // user cancelled — just return to the form
|
|
76
|
+
default:
|
|
77
|
+
setError(result.error.message);
|
|
78
|
+
}
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
if (result.value === null) return; // user cancelled the destination picker
|
|
82
|
+
onCloned(result.value);
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const progressPercent = progress?.percent ?? null;
|
|
86
|
+
const progressText =
|
|
87
|
+
progress !== null
|
|
88
|
+
? `${progress.phase}…${progressPercent !== null ? ` ${Math.round(progressPercent)}%` : ''}`
|
|
89
|
+
: 'Starting clone…';
|
|
90
|
+
|
|
91
|
+
if (authDetail !== null) {
|
|
92
|
+
return (
|
|
93
|
+
<Dialog
|
|
94
|
+
title="Clone repository"
|
|
95
|
+
onClose={onClose}
|
|
96
|
+
footer={
|
|
97
|
+
<>
|
|
98
|
+
<button
|
|
99
|
+
type="button"
|
|
100
|
+
className="db-git-secondary-btn"
|
|
101
|
+
onClick={() => setAuthDetail(null)}
|
|
102
|
+
>
|
|
103
|
+
Back
|
|
104
|
+
</button>
|
|
105
|
+
<button type="button" className="db-git-primary-btn" onClick={onClose}>
|
|
106
|
+
Close
|
|
107
|
+
</button>
|
|
108
|
+
</>
|
|
109
|
+
}
|
|
110
|
+
>
|
|
111
|
+
<p className="db-settings-hint">Git could not authenticate with that remote.</p>
|
|
112
|
+
<GitCredentialGuidance detail={authDetail.detail} />
|
|
113
|
+
</Dialog>
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return (
|
|
118
|
+
<Dialog
|
|
119
|
+
title="Clone repository"
|
|
120
|
+
onClose={onClose}
|
|
121
|
+
closeOnBackdrop={!cloning}
|
|
122
|
+
initialFocusRef={urlInputRef}
|
|
123
|
+
footer={
|
|
124
|
+
<>
|
|
125
|
+
<button
|
|
126
|
+
type="button"
|
|
127
|
+
className="db-git-secondary-btn"
|
|
128
|
+
onClick={onClose}
|
|
129
|
+
disabled={cloning}
|
|
130
|
+
>
|
|
131
|
+
Cancel
|
|
132
|
+
</button>
|
|
133
|
+
<button
|
|
134
|
+
type="button"
|
|
135
|
+
className="db-git-primary-btn"
|
|
136
|
+
disabled={!canClone}
|
|
137
|
+
onClick={() => void handleClone()}
|
|
138
|
+
>
|
|
139
|
+
Clone
|
|
140
|
+
</button>
|
|
141
|
+
</>
|
|
142
|
+
}
|
|
143
|
+
>
|
|
144
|
+
<div className="db-git-form-row">
|
|
145
|
+
<label className="db-git-form-label" htmlFor="db-git-clone-url">
|
|
146
|
+
Repository URL
|
|
147
|
+
</label>
|
|
148
|
+
<input
|
|
149
|
+
id="db-git-clone-url"
|
|
150
|
+
ref={urlInputRef}
|
|
151
|
+
className="db-git-form-input"
|
|
152
|
+
type="text"
|
|
153
|
+
value={url}
|
|
154
|
+
onChange={(e) => setUrl(e.target.value)}
|
|
155
|
+
onKeyDown={(e) => {
|
|
156
|
+
if (e.key === 'Enter') void handleClone();
|
|
157
|
+
}}
|
|
158
|
+
placeholder="https://github.com/owner/repo.git"
|
|
159
|
+
disabled={cloning}
|
|
160
|
+
spellCheck={false}
|
|
161
|
+
/>
|
|
162
|
+
</div>
|
|
163
|
+
{isLikelyGitUrl(url) && (
|
|
164
|
+
<p className="db-git-hint">
|
|
165
|
+
Will clone into: <b>{deriveCloneFolderName(url)}</b> — you’ll pick where next
|
|
166
|
+
</p>
|
|
167
|
+
)}
|
|
168
|
+
<p className="db-git-hint">
|
|
169
|
+
HTTPS and SSH URLs both work. You’ll choose the destination folder in the next step.
|
|
170
|
+
</p>
|
|
171
|
+
{error !== null && (
|
|
172
|
+
<p className="db-git-form-error" role="alert">
|
|
173
|
+
{error}
|
|
174
|
+
</p>
|
|
175
|
+
)}
|
|
176
|
+
{cloning && (
|
|
177
|
+
<div className="db-git-progress">
|
|
178
|
+
{progressPercent !== null && (
|
|
179
|
+
<div
|
|
180
|
+
className="db-git-progress-bar"
|
|
181
|
+
role="progressbar"
|
|
182
|
+
aria-valuemin={0}
|
|
183
|
+
aria-valuemax={100}
|
|
184
|
+
aria-valuenow={Math.round(progressPercent)}
|
|
185
|
+
style={{ width: `${progressPercent}%` }}
|
|
186
|
+
/>
|
|
187
|
+
)}
|
|
188
|
+
<p className="db-git-progress-text">{progressText}</p>
|
|
189
|
+
<button
|
|
190
|
+
type="button"
|
|
191
|
+
className="db-git-secondary-btn"
|
|
192
|
+
onClick={() => handleRef.current?.cancel()}
|
|
193
|
+
>
|
|
194
|
+
Cancel
|
|
195
|
+
</button>
|
|
196
|
+
</div>
|
|
197
|
+
)}
|
|
198
|
+
</Dialog>
|
|
199
|
+
);
|
|
200
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitCommitDialog — message + per-file selection for committing changes.
|
|
3
|
+
*
|
|
4
|
+
* All changed files are included by default; while a merge is being
|
|
5
|
+
* concluded, conflicted files are force-included (locked) because a commit
|
|
6
|
+
* that omits them would not resolve the merge. Selection logic lives in
|
|
7
|
+
* commit-selection.ts so it stays unit-testable.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { useRef, useState } from 'react';
|
|
11
|
+
import { Dialog } from '../components/Dialog.js';
|
|
12
|
+
import { useGitContext } from './GitContext.js';
|
|
13
|
+
import { BADGE_LABELS, badgeKindFor } from './git-status.js';
|
|
14
|
+
import {
|
|
15
|
+
canCommit,
|
|
16
|
+
initSelection,
|
|
17
|
+
isMergeCommit,
|
|
18
|
+
selectedPaths,
|
|
19
|
+
setAllSelected,
|
|
20
|
+
toggleSelection,
|
|
21
|
+
type CommitSelection,
|
|
22
|
+
} from './commit-selection.js';
|
|
23
|
+
|
|
24
|
+
export function GitCommitDialog({ onClose }: { onClose: () => void }) {
|
|
25
|
+
const git = useGitContext();
|
|
26
|
+
const status = git?.status ?? null;
|
|
27
|
+
const merging = isMergeCommit(status);
|
|
28
|
+
|
|
29
|
+
const [message, setMessage] = useState('');
|
|
30
|
+
const [selection, setSelection] = useState<CommitSelection>(() =>
|
|
31
|
+
initSelection(status?.changes ?? [], merging),
|
|
32
|
+
);
|
|
33
|
+
const messageRef = useRef<HTMLTextAreaElement>(null);
|
|
34
|
+
|
|
35
|
+
if (!git || !status) return null;
|
|
36
|
+
|
|
37
|
+
const allOn = [...selection.included.values()].every(Boolean);
|
|
38
|
+
const commitDisabled = !canCommit(message, selection) || git.busy !== null;
|
|
39
|
+
|
|
40
|
+
const handleCommit = async () => {
|
|
41
|
+
const ok = await git.commit(message, selectedPaths(selection));
|
|
42
|
+
if (ok) onClose();
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<Dialog
|
|
47
|
+
title={merging ? 'Commit merge' : 'Commit changes'}
|
|
48
|
+
onClose={onClose}
|
|
49
|
+
size="wide"
|
|
50
|
+
closeOnBackdrop={false}
|
|
51
|
+
initialFocusRef={messageRef}
|
|
52
|
+
footer={
|
|
53
|
+
<>
|
|
54
|
+
<button type="button" className="db-git-secondary-btn" onClick={onClose}>
|
|
55
|
+
Cancel
|
|
56
|
+
</button>
|
|
57
|
+
<button
|
|
58
|
+
type="button"
|
|
59
|
+
className="db-git-primary-btn"
|
|
60
|
+
disabled={commitDisabled}
|
|
61
|
+
onClick={() => void handleCommit()}
|
|
62
|
+
>
|
|
63
|
+
Commit
|
|
64
|
+
</button>
|
|
65
|
+
</>
|
|
66
|
+
}
|
|
67
|
+
>
|
|
68
|
+
{merging && (
|
|
69
|
+
<p className="db-settings-hint">
|
|
70
|
+
You’re completing a merge. Committing will conclude it.
|
|
71
|
+
</p>
|
|
72
|
+
)}
|
|
73
|
+
<textarea
|
|
74
|
+
ref={messageRef}
|
|
75
|
+
className="db-git-commit-message"
|
|
76
|
+
value={message}
|
|
77
|
+
onChange={(e) => setMessage(e.target.value)}
|
|
78
|
+
placeholder="Commit message"
|
|
79
|
+
aria-label="Commit message"
|
|
80
|
+
rows={3}
|
|
81
|
+
/>
|
|
82
|
+
<div className="db-git-form-row">
|
|
83
|
+
<button
|
|
84
|
+
type="button"
|
|
85
|
+
className="db-git-secondary-btn"
|
|
86
|
+
onClick={() => setSelection((s) => setAllSelected(s, !allOn))}
|
|
87
|
+
>
|
|
88
|
+
{allOn ? 'Select none' : 'Select all'}
|
|
89
|
+
</button>
|
|
90
|
+
</div>
|
|
91
|
+
<ul className="db-git-file-list">
|
|
92
|
+
{status.changes.map((change) => {
|
|
93
|
+
const kind = badgeKindFor(change);
|
|
94
|
+
const locked = selection.locked.has(change.path);
|
|
95
|
+
const checked = locked || (selection.included.get(change.path) ?? true);
|
|
96
|
+
return (
|
|
97
|
+
<li key={change.path} className="db-git-file-row">
|
|
98
|
+
<label>
|
|
99
|
+
<input
|
|
100
|
+
type="checkbox"
|
|
101
|
+
checked={checked}
|
|
102
|
+
disabled={locked}
|
|
103
|
+
onChange={() => setSelection((s) => toggleSelection(s, change.path))}
|
|
104
|
+
/>
|
|
105
|
+
<span>{change.path.replace(/^\/+/, '')}</span>
|
|
106
|
+
</label>
|
|
107
|
+
<span className="db-git-file-kind">{BADGE_LABELS[kind]}</span>
|
|
108
|
+
</li>
|
|
109
|
+
);
|
|
110
|
+
})}
|
|
111
|
+
</ul>
|
|
112
|
+
{git.lastResult?.tone === 'error' && (
|
|
113
|
+
<p className="db-git-form-error" role="alert">
|
|
114
|
+
{git.lastResult.message}
|
|
115
|
+
</p>
|
|
116
|
+
)}
|
|
117
|
+
</Dialog>
|
|
118
|
+
);
|
|
119
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitConflictsDialog — lists conflicted files after a pull hits a merge
|
|
3
|
+
* conflict. Each row opens the file in the editor so the user can resolve
|
|
4
|
+
* the markers; the primary action hands off to the commit dialog, which
|
|
5
|
+
* concludes the merge.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { Dialog } from '../components/Dialog.js';
|
|
9
|
+
import { useGitContext } from './GitContext.js';
|
|
10
|
+
|
|
11
|
+
export function GitConflictsDialog({
|
|
12
|
+
paths,
|
|
13
|
+
onOpenFile,
|
|
14
|
+
onClose,
|
|
15
|
+
}: {
|
|
16
|
+
paths: string[];
|
|
17
|
+
onOpenFile: (path: string) => void;
|
|
18
|
+
onClose: () => void;
|
|
19
|
+
}) {
|
|
20
|
+
const git = useGitContext();
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<Dialog
|
|
24
|
+
title="Merge conflicts"
|
|
25
|
+
onClose={onClose}
|
|
26
|
+
footer={
|
|
27
|
+
<>
|
|
28
|
+
<button type="button" className="db-git-secondary-btn" onClick={onClose}>
|
|
29
|
+
Close
|
|
30
|
+
</button>
|
|
31
|
+
<button
|
|
32
|
+
type="button"
|
|
33
|
+
className="db-git-primary-btn"
|
|
34
|
+
onClick={() => git?.openDialog({ kind: 'commit' })}
|
|
35
|
+
>
|
|
36
|
+
Open commit dialog
|
|
37
|
+
</button>
|
|
38
|
+
</>
|
|
39
|
+
}
|
|
40
|
+
>
|
|
41
|
+
<p className="db-settings-hint">
|
|
42
|
+
These files contain conflict markers. Edit each one to resolve the conflicts, then commit to
|
|
43
|
+
complete the merge.
|
|
44
|
+
</p>
|
|
45
|
+
<ul className="db-git-file-list">
|
|
46
|
+
{paths.map((path) => (
|
|
47
|
+
<li key={path} className="db-git-file-row">
|
|
48
|
+
<button
|
|
49
|
+
type="button"
|
|
50
|
+
onClick={() => {
|
|
51
|
+
onOpenFile(path);
|
|
52
|
+
onClose();
|
|
53
|
+
}}
|
|
54
|
+
>
|
|
55
|
+
{path.replace(/^\/+/, '')}
|
|
56
|
+
</button>
|
|
57
|
+
</li>
|
|
58
|
+
))}
|
|
59
|
+
</ul>
|
|
60
|
+
</Dialog>
|
|
61
|
+
);
|
|
62
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitContext — the seam between DocBlocksShell and every git UI surface.
|
|
3
|
+
*
|
|
4
|
+
* The shell calls useGit() once and provides the value here; the status
|
|
5
|
+
* bar, file-tree badges, toolbar control, and dialogs all consume it.
|
|
6
|
+
* Consumers must tolerate a null context (FileExplorer renders standalone
|
|
7
|
+
* in tests and on surfaces with no git).
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { createContext, useContext } from 'react';
|
|
11
|
+
import type {
|
|
12
|
+
DocBlocksHostGitAPI,
|
|
13
|
+
GitCapabilities,
|
|
14
|
+
GitRepoDetection,
|
|
15
|
+
GitStatus,
|
|
16
|
+
} from '@bendyline/docblocks/host';
|
|
17
|
+
import type { FileSystemProvider } from '@bendyline/docblocks/filesystem';
|
|
18
|
+
import type { GitBadgeKind } from './git-status.js';
|
|
19
|
+
|
|
20
|
+
export type GitDialogState =
|
|
21
|
+
| { kind: 'none' }
|
|
22
|
+
| { kind: 'commit' }
|
|
23
|
+
| { kind: 'branches'; createFocus?: boolean }
|
|
24
|
+
| { kind: 'history'; path?: string }
|
|
25
|
+
/** `revision` absent → working tree vs HEAD; present → that commit vs its parent. */
|
|
26
|
+
| { kind: 'diff'; path: string; revision?: { sha: string } }
|
|
27
|
+
| { kind: 'clone' }
|
|
28
|
+
| {
|
|
29
|
+
kind: 'auth-guidance';
|
|
30
|
+
operation: 'push' | 'pull' | 'fetch' | 'clone' | 'pr';
|
|
31
|
+
detail?: string;
|
|
32
|
+
}
|
|
33
|
+
| { kind: 'conflicts'; paths: string[] };
|
|
34
|
+
|
|
35
|
+
export type GitBusyKind = 'push' | 'pull' | 'fetch' | 'commit' | 'branch' | 'pr' | null;
|
|
36
|
+
|
|
37
|
+
export interface GitInlineResult {
|
|
38
|
+
tone: 'info' | 'error';
|
|
39
|
+
message: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface GitValue {
|
|
43
|
+
/** Tier 1 — Electron host with a working git. Gates the clone entry. */
|
|
44
|
+
available: boolean;
|
|
45
|
+
capabilities: GitCapabilities | null;
|
|
46
|
+
/** Tier 2 — the active workspace root is a repository. Gates everything else. */
|
|
47
|
+
repo: GitRepoDetection | null;
|
|
48
|
+
/** Main-owned repository capability; never a native path. */
|
|
49
|
+
repositoryId: string | null;
|
|
50
|
+
/** Parsed web location of the first remote, when one exists and parses. */
|
|
51
|
+
remoteWeb: { host: string; owner: string; repo: string; webUrl: string } | null;
|
|
52
|
+
/** Raw host API for read-heavy dialogs (log, branches, file-at-revision). */
|
|
53
|
+
gitApi: DocBlocksHostGitAPI | null;
|
|
54
|
+
provider: FileSystemProvider | null;
|
|
55
|
+
theme: 'light' | 'dark';
|
|
56
|
+
|
|
57
|
+
status: GitStatus | null;
|
|
58
|
+
badges: ReadonlyMap<string, GitBadgeKind>;
|
|
59
|
+
busy: GitBusyKind;
|
|
60
|
+
/** Latest operation outcome, surfaced in an aria-live region. */
|
|
61
|
+
lastResult: GitInlineResult | null;
|
|
62
|
+
|
|
63
|
+
refresh: () => void;
|
|
64
|
+
/** Debounced refresh — used after autosave writes. */
|
|
65
|
+
scheduleRefresh: () => void;
|
|
66
|
+
|
|
67
|
+
/** Actions route their typed errors to dialogs/lastResult internally. */
|
|
68
|
+
commit: (message: string, paths: string[]) => Promise<boolean>;
|
|
69
|
+
push: () => Promise<void>;
|
|
70
|
+
pull: () => Promise<void>;
|
|
71
|
+
fetchRemote: () => Promise<void>;
|
|
72
|
+
createBranch: (name: string) => Promise<boolean>;
|
|
73
|
+
switchBranch: (name: string) => Promise<boolean>;
|
|
74
|
+
/** Open the repo (or a file within it) on the remote's web host. */
|
|
75
|
+
openOnRemote: (filePath?: string) => void;
|
|
76
|
+
createPullRequest: () => Promise<void>;
|
|
77
|
+
|
|
78
|
+
dialog: GitDialogState;
|
|
79
|
+
openDialog: (dialog: GitDialogState) => void;
|
|
80
|
+
closeDialog: () => void;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export const GitContext = createContext<GitValue | null>(null);
|
|
84
|
+
|
|
85
|
+
/** Null when no provider is mounted — callers must degrade gracefully. */
|
|
86
|
+
export function useGitContext(): GitValue | null {
|
|
87
|
+
return useContext(GitContext);
|
|
88
|
+
}
|