@bendyline/docblocks-react 2.0.0 → 2.1.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.
Files changed (300) hide show
  1. package/README.md +6 -0
  2. package/dist/{ExportDialog-MEUISWZX.js → ExportDialog-7LDIXJZ3.js} +3 -2
  3. package/dist/{ExportToolbarControls-D2YDWOXW.js → ExportToolbarControls-GHAOJMH6.js} +147 -12
  4. package/dist/ExportToolbarControls-GHAOJMH6.js.map +1 -0
  5. package/dist/{GitToolbarControl-LMIR4R7I.js → GitToolbarControl-GNMRVKWQ.js} +62 -43
  6. package/dist/GitToolbarControl-GNMRVKWQ.js.map +1 -0
  7. package/dist/{GitUI-KGF5MSNV.js → GitUI-VHOBQY43.js} +225 -140
  8. package/dist/GitUI-VHOBQY43.js.map +1 -0
  9. package/dist/ShareDialog-63ENBEDZ.js +213 -0
  10. package/dist/ShareDialog-63ENBEDZ.js.map +1 -0
  11. package/dist/chunk-57ZJJOC5.js +89 -0
  12. package/dist/chunk-57ZJJOC5.js.map +1 -0
  13. package/dist/chunk-FEWQUQML.js +256 -0
  14. package/dist/chunk-FEWQUQML.js.map +1 -0
  15. package/dist/chunk-FMGTHSTX.js +110 -0
  16. package/dist/chunk-FMGTHSTX.js.map +1 -0
  17. package/dist/chunk-UNYZQXWR.js +324 -0
  18. package/dist/chunk-UNYZQXWR.js.map +1 -0
  19. package/dist/editor.d.ts +5 -4
  20. package/dist/editor.js +8 -69
  21. package/dist/editor.js.map +1 -1
  22. package/dist/export/index.d.ts +7 -1
  23. package/dist/export/index.js +2 -1
  24. package/dist/index.d.ts +346 -21
  25. package/dist/index.js +6169 -20
  26. package/dist/index.js.map +1 -1
  27. package/dist/settings/index.d.ts +9 -1
  28. package/dist/settings/index.js +6 -4
  29. package/package.json +18 -13
  30. package/src/styles/docblocks.css +537 -26
  31. package/dist/AppMenu/AppMenu.d.ts +0 -53
  32. package/dist/AppMenu/AppMenu.d.ts.map +0 -1
  33. package/dist/AppMenu/AppMenu.js +0 -67
  34. package/dist/AppMenu/AppMenu.js.map +0 -1
  35. package/dist/AppMenu/index.d.ts +0 -3
  36. package/dist/AppMenu/index.d.ts.map +0 -1
  37. package/dist/AppMenu/index.js +0 -2
  38. package/dist/AppMenu/index.js.map +0 -1
  39. package/dist/DocBlocksShell/DocBlocksShell.d.ts +0 -49
  40. package/dist/DocBlocksShell/DocBlocksShell.d.ts.map +0 -1
  41. package/dist/DocBlocksShell/DocBlocksShell.js +0 -2730
  42. package/dist/DocBlocksShell/DocBlocksShell.js.map +0 -1
  43. package/dist/DocBlocksShell/LazyEditorShell.d.ts +0 -3
  44. package/dist/DocBlocksShell/LazyEditorShell.d.ts.map +0 -1
  45. package/dist/DocBlocksShell/LazyEditorShell.js +0 -3
  46. package/dist/DocBlocksShell/LazyEditorShell.js.map +0 -1
  47. package/dist/DocBlocksShell/UpdateAvailableNotice.d.ts +0 -13
  48. package/dist/DocBlocksShell/UpdateAvailableNotice.d.ts.map +0 -1
  49. package/dist/DocBlocksShell/UpdateAvailableNotice.js +0 -16
  50. package/dist/DocBlocksShell/UpdateAvailableNotice.js.map +0 -1
  51. package/dist/DocBlocksShell/document-title.d.ts +0 -3
  52. package/dist/DocBlocksShell/document-title.d.ts.map +0 -1
  53. package/dist/DocBlocksShell/document-title.js +0 -17
  54. package/dist/DocBlocksShell/document-title.js.map +0 -1
  55. package/dist/DocBlocksShell/index.d.ts +0 -3
  56. package/dist/DocBlocksShell/index.d.ts.map +0 -1
  57. package/dist/DocBlocksShell/index.js +0 -2
  58. package/dist/DocBlocksShell/index.js.map +0 -1
  59. package/dist/DocBlocksShell/workspace-authority-barrier.d.ts +0 -14
  60. package/dist/DocBlocksShell/workspace-authority-barrier.d.ts.map +0 -1
  61. package/dist/DocBlocksShell/workspace-authority-barrier.js +0 -23
  62. package/dist/DocBlocksShell/workspace-authority-barrier.js.map +0 -1
  63. package/dist/Export/DeferredExportToolbarControls.d.ts +0 -5
  64. package/dist/Export/DeferredExportToolbarControls.d.ts.map +0 -1
  65. package/dist/Export/DeferredExportToolbarControls.js +0 -10
  66. package/dist/Export/DeferredExportToolbarControls.js.map +0 -1
  67. package/dist/Export/ExportDialog.d.ts +0 -25
  68. package/dist/Export/ExportDialog.d.ts.map +0 -1
  69. package/dist/Export/ExportDialog.js +0 -160
  70. package/dist/Export/ExportDialog.js.map +0 -1
  71. package/dist/Export/ExportToolbarControls.d.ts +0 -37
  72. package/dist/Export/ExportToolbarControls.d.ts.map +0 -1
  73. package/dist/Export/ExportToolbarControls.js +0 -285
  74. package/dist/Export/ExportToolbarControls.js.map +0 -1
  75. package/dist/Export/export-destination.d.ts +0 -3
  76. package/dist/Export/export-destination.d.ts.map +0 -1
  77. package/dist/Export/export-destination.js +0 -32
  78. package/dist/Export/export-destination.js.map +0 -1
  79. package/dist/Export/export-options.d.ts +0 -53
  80. package/dist/Export/export-options.d.ts.map +0 -1
  81. package/dist/Export/export-options.js +0 -49
  82. package/dist/Export/export-options.js.map +0 -1
  83. package/dist/Export/index.d.ts +0 -10
  84. package/dist/Export/index.d.ts.map +0 -1
  85. package/dist/Export/index.js +0 -6
  86. package/dist/Export/index.js.map +0 -1
  87. package/dist/Export/public-api.d.ts +0 -12
  88. package/dist/Export/public-api.d.ts.map +0 -1
  89. package/dist/Export/public-api.js +0 -9
  90. package/dist/Export/public-api.js.map +0 -1
  91. package/dist/Export/run-export.d.ts +0 -10
  92. package/dist/Export/run-export.d.ts.map +0 -1
  93. package/dist/Export/run-export.js +0 -313
  94. package/dist/Export/run-export.js.map +0 -1
  95. package/dist/Export/transform-summaries.d.ts +0 -7
  96. package/dist/Export/transform-summaries.d.ts.map +0 -1
  97. package/dist/Export/transform-summaries.js +0 -6
  98. package/dist/Export/transform-summaries.js.map +0 -1
  99. package/dist/ExportToolbarControls-D2YDWOXW.js.map +0 -1
  100. package/dist/FileExplorer/FileExplorer.d.ts +0 -43
  101. package/dist/FileExplorer/FileExplorer.d.ts.map +0 -1
  102. package/dist/FileExplorer/FileExplorer.js +0 -315
  103. package/dist/FileExplorer/FileExplorer.js.map +0 -1
  104. package/dist/FileExplorer/FileTreeNode.d.ts +0 -39
  105. package/dist/FileExplorer/FileTreeNode.d.ts.map +0 -1
  106. package/dist/FileExplorer/FileTreeNode.js +0 -131
  107. package/dist/FileExplorer/FileTreeNode.js.map +0 -1
  108. package/dist/FileExplorer/index.d.ts +0 -6
  109. package/dist/FileExplorer/index.d.ts.map +0 -1
  110. package/dist/FileExplorer/index.js +0 -4
  111. package/dist/FileExplorer/index.js.map +0 -1
  112. package/dist/FileExplorer/useFileTree.d.ts +0 -37
  113. package/dist/FileExplorer/useFileTree.d.ts.map +0 -1
  114. package/dist/FileExplorer/useFileTree.js +0 -284
  115. package/dist/FileExplorer/useFileTree.js.map +0 -1
  116. package/dist/Git/GitAuthGuidanceDialog.d.ts +0 -18
  117. package/dist/Git/GitAuthGuidanceDialog.d.ts.map +0 -1
  118. package/dist/Git/GitAuthGuidanceDialog.js +0 -27
  119. package/dist/Git/GitAuthGuidanceDialog.js.map +0 -1
  120. package/dist/Git/GitBranchesDialog.d.ts +0 -13
  121. package/dist/Git/GitBranchesDialog.d.ts.map +0 -1
  122. package/dist/Git/GitBranchesDialog.js +0 -59
  123. package/dist/Git/GitBranchesDialog.js.map +0 -1
  124. package/dist/Git/GitCloneDialog.d.ts +0 -14
  125. package/dist/Git/GitCloneDialog.d.ts.map +0 -1
  126. package/dist/Git/GitCloneDialog.js +0 -79
  127. package/dist/Git/GitCloneDialog.js.map +0 -1
  128. package/dist/Git/GitCommitDialog.d.ts +0 -12
  129. package/dist/Git/GitCommitDialog.d.ts.map +0 -1
  130. package/dist/Git/GitCommitDialog.js +0 -38
  131. package/dist/Git/GitCommitDialog.js.map +0 -1
  132. package/dist/Git/GitConflictsDialog.d.ts +0 -12
  133. package/dist/Git/GitConflictsDialog.d.ts.map +0 -1
  134. package/dist/Git/GitConflictsDialog.js +0 -17
  135. package/dist/Git/GitConflictsDialog.js.map +0 -1
  136. package/dist/Git/GitContext.d.ts +0 -89
  137. package/dist/Git/GitContext.d.ts.map +0 -1
  138. package/dist/Git/GitContext.js +0 -15
  139. package/dist/Git/GitContext.js.map +0 -1
  140. package/dist/Git/GitDiffDialog.d.ts +0 -20
  141. package/dist/Git/GitDiffDialog.d.ts.map +0 -1
  142. package/dist/Git/GitDiffDialog.js +0 -100
  143. package/dist/Git/GitDiffDialog.js.map +0 -1
  144. package/dist/Git/GitDiffView.d.ts +0 -23
  145. package/dist/Git/GitDiffView.d.ts.map +0 -1
  146. package/dist/Git/GitDiffView.js +0 -77
  147. package/dist/Git/GitDiffView.js.map +0 -1
  148. package/dist/Git/GitHistoryDialog.d.ts +0 -15
  149. package/dist/Git/GitHistoryDialog.d.ts.map +0 -1
  150. package/dist/Git/GitHistoryDialog.js +0 -107
  151. package/dist/Git/GitHistoryDialog.js.map +0 -1
  152. package/dist/Git/GitStatusBar.d.ts +0 -8
  153. package/dist/Git/GitStatusBar.d.ts.map +0 -1
  154. package/dist/Git/GitStatusBar.js +0 -49
  155. package/dist/Git/GitStatusBar.js.map +0 -1
  156. package/dist/Git/GitToolbarControl.d.ts +0 -15
  157. package/dist/Git/GitToolbarControl.d.ts.map +0 -1
  158. package/dist/Git/GitToolbarControl.js +0 -51
  159. package/dist/Git/GitToolbarControl.js.map +0 -1
  160. package/dist/Git/GitUI.d.ts +0 -14
  161. package/dist/Git/GitUI.d.ts.map +0 -1
  162. package/dist/Git/GitUI.js +0 -21
  163. package/dist/Git/GitUI.js.map +0 -1
  164. package/dist/Git/commit-selection.d.ts +0 -22
  165. package/dist/Git/commit-selection.d.ts.map +0 -1
  166. package/dist/Git/commit-selection.js +0 -47
  167. package/dist/Git/commit-selection.js.map +0 -1
  168. package/dist/Git/git-clone-utils.d.ts +0 -8
  169. package/dist/Git/git-clone-utils.d.ts.map +0 -1
  170. package/dist/Git/git-clone-utils.js +0 -26
  171. package/dist/Git/git-clone-utils.js.map +0 -1
  172. package/dist/Git/git-status.d.ts +0 -24
  173. package/dist/Git/git-status.d.ts.map +0 -1
  174. package/dist/Git/git-status.js +0 -105
  175. package/dist/Git/git-status.js.map +0 -1
  176. package/dist/Git/useGit.d.ts +0 -15
  177. package/dist/Git/useGit.d.ts.map +0 -1
  178. package/dist/Git/useGit.js +0 -206
  179. package/dist/Git/useGit.js.map +0 -1
  180. package/dist/Git/useGitStatus.d.ts +0 -17
  181. package/dist/Git/useGitStatus.d.ts.map +0 -1
  182. package/dist/Git/useGitStatus.js +0 -63
  183. package/dist/Git/useGitStatus.js.map +0 -1
  184. package/dist/GitToolbarControl-LMIR4R7I.js.map +0 -1
  185. package/dist/GitUI-KGF5MSNV.js.map +0 -1
  186. package/dist/Settings/Settings.d.ts +0 -23
  187. package/dist/Settings/Settings.d.ts.map +0 -1
  188. package/dist/Settings/Settings.js +0 -22
  189. package/dist/Settings/Settings.js.map +0 -1
  190. package/dist/Settings/public-api.d.ts +0 -3
  191. package/dist/Settings/public-api.d.ts.map +0 -1
  192. package/dist/Settings/public-api.js +0 -2
  193. package/dist/Settings/public-api.js.map +0 -1
  194. package/dist/WorkspacePicker/WorkspacePicker.d.ts +0 -22
  195. package/dist/WorkspacePicker/WorkspacePicker.d.ts.map +0 -1
  196. package/dist/WorkspacePicker/WorkspacePicker.js +0 -74
  197. package/dist/WorkspacePicker/WorkspacePicker.js.map +0 -1
  198. package/dist/WorkspacePicker/WorkspaceSettingsButton.d.ts +0 -11
  199. package/dist/WorkspacePicker/WorkspaceSettingsButton.d.ts.map +0 -1
  200. package/dist/WorkspacePicker/WorkspaceSettingsButton.js +0 -27
  201. package/dist/WorkspacePicker/WorkspaceSettingsButton.js.map +0 -1
  202. package/dist/WorkspacePicker/WorkspaceSettingsDialog.d.ts +0 -20
  203. package/dist/WorkspacePicker/WorkspaceSettingsDialog.d.ts.map +0 -1
  204. package/dist/WorkspacePicker/WorkspaceSettingsDialog.js +0 -36
  205. package/dist/WorkspacePicker/WorkspaceSettingsDialog.js.map +0 -1
  206. package/dist/WorkspacePicker/index.d.ts +0 -3
  207. package/dist/WorkspacePicker/index.d.ts.map +0 -1
  208. package/dist/WorkspacePicker/index.js +0 -2
  209. package/dist/WorkspacePicker/index.js.map +0 -1
  210. package/dist/chunk-3SAXDU2U.js +0 -157
  211. package/dist/chunk-3SAXDU2U.js.map +0 -1
  212. package/dist/chunk-AOVTHZU7.js +0 -321
  213. package/dist/chunk-AOVTHZU7.js.map +0 -1
  214. package/dist/chunk-GSNZSCIK.js +0 -55
  215. package/dist/chunk-GSNZSCIK.js.map +0 -1
  216. package/dist/components/Dialog.d.ts +0 -22
  217. package/dist/components/Dialog.d.ts.map +0 -1
  218. package/dist/components/Dialog.js +0 -33
  219. package/dist/components/Dialog.js.map +0 -1
  220. package/dist/editor.d.ts.map +0 -1
  221. package/dist/hooks/index.d.ts +0 -3
  222. package/dist/hooks/index.d.ts.map +0 -1
  223. package/dist/hooks/index.js +0 -2
  224. package/dist/hooks/index.js.map +0 -1
  225. package/dist/hooks/useDocumentSession.d.ts +0 -16
  226. package/dist/hooks/useDocumentSession.d.ts.map +0 -1
  227. package/dist/hooks/useDocumentSession.js +0 -18
  228. package/dist/hooks/useDocumentSession.js.map +0 -1
  229. package/dist/icons.d.ts +0 -12
  230. package/dist/icons.d.ts.map +0 -1
  231. package/dist/icons.js +0 -28
  232. package/dist/icons.js.map +0 -1
  233. package/dist/index.d.ts.map +0 -1
  234. package/dist/preferences/theme.d.ts +0 -18
  235. package/dist/preferences/theme.d.ts.map +0 -1
  236. package/dist/preferences/theme.js +0 -63
  237. package/dist/preferences/theme.js.map +0 -1
  238. package/dist/preferences/versioning.d.ts +0 -27
  239. package/dist/preferences/versioning.d.ts.map +0 -1
  240. package/dist/preferences/versioning.js +0 -62
  241. package/dist/preferences/versioning.js.map +0 -1
  242. package/dist/provider-lease.d.ts +0 -10
  243. package/dist/provider-lease.d.ts.map +0 -1
  244. package/dist/provider-lease.js +0 -42
  245. package/dist/provider-lease.js.map +0 -1
  246. package/src/AppMenu/AppMenu.tsx +0 -334
  247. package/src/AppMenu/index.ts +0 -2
  248. package/src/DocBlocksShell/DocBlocksShell.tsx +0 -3398
  249. package/src/DocBlocksShell/LazyEditorShell.ts +0 -2
  250. package/src/DocBlocksShell/UpdateAvailableNotice.tsx +0 -60
  251. package/src/DocBlocksShell/document-title.ts +0 -19
  252. package/src/DocBlocksShell/index.ts +0 -2
  253. package/src/DocBlocksShell/workspace-authority-barrier.ts +0 -26
  254. package/src/Export/DeferredExportToolbarControls.tsx +0 -23
  255. package/src/Export/ExportDialog.tsx +0 -437
  256. package/src/Export/ExportToolbarControls.tsx +0 -511
  257. package/src/Export/export-destination.ts +0 -30
  258. package/src/Export/export-options.ts +0 -99
  259. package/src/Export/index.ts +0 -19
  260. package/src/Export/public-api.ts +0 -17
  261. package/src/Export/run-export.ts +0 -374
  262. package/src/Export/transform-summaries.ts +0 -14
  263. package/src/FileExplorer/FileExplorer.tsx +0 -528
  264. package/src/FileExplorer/FileTreeNode.tsx +0 -306
  265. package/src/FileExplorer/index.ts +0 -5
  266. package/src/FileExplorer/useFileTree.ts +0 -352
  267. package/src/Git/GitAuthGuidanceDialog.tsx +0 -84
  268. package/src/Git/GitBranchesDialog.tsx +0 -144
  269. package/src/Git/GitCloneDialog.tsx +0 -200
  270. package/src/Git/GitCommitDialog.tsx +0 -119
  271. package/src/Git/GitConflictsDialog.tsx +0 -62
  272. package/src/Git/GitContext.tsx +0 -88
  273. package/src/Git/GitDiffDialog.tsx +0 -147
  274. package/src/Git/GitDiffView.tsx +0 -105
  275. package/src/Git/GitHistoryDialog.tsx +0 -195
  276. package/src/Git/GitStatusBar.tsx +0 -157
  277. package/src/Git/GitToolbarControl.tsx +0 -123
  278. package/src/Git/GitUI.tsx +0 -68
  279. package/src/Git/commit-selection.ts +0 -63
  280. package/src/Git/git-clone-utils.ts +0 -23
  281. package/src/Git/git-status.ts +0 -113
  282. package/src/Git/useGit.ts +0 -279
  283. package/src/Git/useGitStatus.ts +0 -78
  284. package/src/Settings/Settings.tsx +0 -118
  285. package/src/Settings/public-api.ts +0 -8
  286. package/src/WorkspacePicker/WorkspacePicker.tsx +0 -191
  287. package/src/WorkspacePicker/WorkspaceSettingsButton.tsx +0 -88
  288. package/src/WorkspacePicker/WorkspaceSettingsDialog.tsx +0 -121
  289. package/src/WorkspacePicker/index.ts +0 -2
  290. package/src/components/Dialog.tsx +0 -81
  291. package/src/editor.ts +0 -72
  292. package/src/hooks/index.ts +0 -2
  293. package/src/hooks/useDocumentSession.ts +0 -37
  294. package/src/icons.tsx +0 -48
  295. package/src/index.ts +0 -61
  296. package/src/preferences/theme.ts +0 -67
  297. package/src/preferences/versioning.ts +0 -69
  298. package/src/provider-lease.ts +0 -52
  299. package/src/types/pwa-dom.d.ts +0 -31
  300. /package/dist/{ExportDialog-MEUISWZX.js.map → ExportDialog-7LDIXJZ3.js.map} +0 -0
@@ -1,147 +0,0 @@
1
- /**
2
- * GitDiffDialog — full-size modal showing a file diff.
3
- *
4
- * Without a revision: working tree vs HEAD (HEAD side via the git host API,
5
- * working side via the workspace FileSystemProvider). With a revision: that
6
- * commit vs its parent, both sides via readFileAtRevision. Absent sides
7
- * render as empty text with an "(absent)" label; binary files short-circuit
8
- * to a hint since there is no text diff to show.
9
- */
10
-
11
- import { useEffect, useState } from 'react';
12
- import { getFileSystemProviderV2, parseWorkspacePath } from '@bendyline/docblocks/filesystem';
13
- import { Dialog } from '../components/Dialog.js';
14
- import { useGitContext } from './GitContext.js';
15
- import { GitDiffView } from './GitDiffView.js';
16
-
17
- export interface GitDiffDialogProps {
18
- /** Slash-prefixed workspace-relative path. */
19
- path: string;
20
- /** Absent → working tree vs HEAD; present → that commit vs its parent. */
21
- revision?: { sha: string };
22
- onClose: () => void;
23
- }
24
-
25
- type DiffLoadState =
26
- | { phase: 'loading' }
27
- | { phase: 'error'; message: string }
28
- | { phase: 'binary' }
29
- | {
30
- phase: 'ready';
31
- original: string;
32
- modified: string;
33
- labels: { original: string; modified: string };
34
- };
35
-
36
- export function GitDiffDialog({ path, revision, onClose }: GitDiffDialogProps) {
37
- const git = useGitContext();
38
- const gitApi = git?.gitApi ?? null;
39
- const provider = git?.provider ?? null;
40
- const repositoryId = git?.repositoryId ?? null;
41
- const sha = revision?.sha ?? null;
42
-
43
- const [state, setState] = useState<DiffLoadState>({ phase: 'loading' });
44
-
45
- useEffect(() => {
46
- if (!gitApi || !repositoryId) {
47
- setState({ phase: 'error', message: 'Git is not available for this workspace.' });
48
- return;
49
- }
50
- let cancelled = false;
51
- setState({ phase: 'loading' });
52
-
53
- const load = async (): Promise<DiffLoadState> => {
54
- if (sha) {
55
- const short = sha.slice(0, 7);
56
- const [parent, at] = await Promise.all([
57
- gitApi.readFileAtRevision(repositoryId, path, { kind: 'parent-of', sha }),
58
- gitApi.readFileAtRevision(repositoryId, path, { kind: 'commit', sha }),
59
- ]);
60
- if (!parent.ok) return { phase: 'error', message: parent.error.message };
61
- if (!at.ok) return { phase: 'error', message: at.error.message };
62
- if (
63
- (parent.value.content === null && parent.value.binary) ||
64
- (at.value.content === null && at.value.binary)
65
- ) {
66
- return { phase: 'binary' };
67
- }
68
- return {
69
- phase: 'ready',
70
- original: parent.value.content ?? '',
71
- modified: at.value.content ?? '',
72
- labels: {
73
- original: parent.value.content === null ? `${short}^ (absent)` : `${short}^`,
74
- modified: at.value.content === null ? `${short} (absent)` : short,
75
- },
76
- };
77
- }
78
-
79
- if (!provider) {
80
- return { phase: 'error', message: 'Workspace files are not available.' };
81
- }
82
- const providerV2 = getFileSystemProviderV2(provider);
83
- const [head, working] = await Promise.all([
84
- gitApi.readFileAtRevision(repositoryId, path, { kind: 'head' }),
85
- providerV2
86
- ? providerV2
87
- .readFile(parseWorkspacePath(path))
88
- .then((file) => (file ? new TextDecoder().decode(file.data) : null))
89
- : provider.readFile(path),
90
- ]);
91
- if (!head.ok) return { phase: 'error', message: head.error.message };
92
- if (head.value.content === null && head.value.binary) return { phase: 'binary' };
93
- return {
94
- phase: 'ready',
95
- original: head.value.content ?? '',
96
- modified: working ?? '',
97
- labels: {
98
- original: head.value.content === null ? 'HEAD (absent)' : 'HEAD',
99
- modified: working === null ? 'Working tree (absent)' : 'Working tree',
100
- },
101
- };
102
- };
103
-
104
- load()
105
- .catch(
106
- (err: unknown): DiffLoadState => ({
107
- phase: 'error',
108
- message: err instanceof Error ? err.message : 'Failed to load the diff',
109
- }),
110
- )
111
- .then((next) => {
112
- if (!cancelled) setState(next);
113
- });
114
- return () => {
115
- cancelled = true;
116
- };
117
- }, [gitApi, provider, repositoryId, path, sha]);
118
-
119
- if (!git) return null;
120
-
121
- const fullPath = path.replace(/^\/+/, '');
122
- const baseName = fullPath.split('/').pop() || fullPath;
123
-
124
- return (
125
- <Dialog title={baseName} size="full" onClose={onClose}>
126
- <p className="db-settings-hint">{fullPath}</p>
127
- {state.phase === 'loading' && <p className="db-git-hint">Loading changes…</p>}
128
- {state.phase === 'error' && (
129
- <p className="db-git-form-error" role="alert">
130
- {state.message}
131
- </p>
132
- )}
133
- {state.phase === 'binary' && (
134
- <p className="db-git-hint">Binary file — no text diff available.</p>
135
- )}
136
- {state.phase === 'ready' && (
137
- <GitDiffView
138
- original={state.original}
139
- modified={state.modified}
140
- fileName={baseName}
141
- theme={git.theme}
142
- labels={state.labels}
143
- />
144
- )}
145
- </Dialog>
146
- );
147
- }
@@ -1,105 +0,0 @@
1
- /**
2
- * GitDiffView — read-only Monaco side-by-side diff.
3
- *
4
- * Monaco is never statically imported: squisq's useMonacoLoader() lazily
5
- * imports the editor bundle once per page and hands back the namespace.
6
- * The diff editor and both text models are created imperatively into a
7
- * host div and disposed on unmount (the classic Monaco leak). Content and
8
- * theme changes update the existing editor without recreating it.
9
- */
10
-
11
- import { useEffect, useRef } from 'react';
12
- import {
13
- detectLanguageFromFileName,
14
- useMonacoLoader,
15
- type UseMonacoLoaderResult,
16
- } from '@bendyline/squisq-editor-react';
17
-
18
- type MonacoModule = NonNullable<UseMonacoLoaderResult['monaco']>;
19
- type DiffEditorInstance = ReturnType<MonacoModule['editor']['createDiffEditor']>;
20
- type TextModel = ReturnType<MonacoModule['editor']['createModel']>;
21
-
22
- export interface GitDiffViewProps {
23
- original: string;
24
- modified: string;
25
- /** Used for language detection (markdown for .md, plain text otherwise). */
26
- fileName: string;
27
- theme: 'light' | 'dark';
28
- /** Optional column headers rendered above the two panes. */
29
- labels?: { original: string; modified: string };
30
- }
31
-
32
- function languageFor(fileName: string): string {
33
- const detected = detectLanguageFromFileName(fileName);
34
- if (detected) return detected;
35
- return fileName.toLowerCase().endsWith('.md') ? 'markdown' : 'plaintext';
36
- }
37
-
38
- export function GitDiffView({ original, modified, fileName, theme, labels }: GitDiffViewProps) {
39
- const { monaco, ready } = useMonacoLoader();
40
- const hostRef = useRef<HTMLDivElement | null>(null);
41
- const editorRef = useRef<DiffEditorInstance | null>(null);
42
- const modelsRef = useRef<{ original: TextModel; modified: TextModel } | null>(null);
43
-
44
- const language = languageFor(fileName);
45
-
46
- // Create the editor once monaco settles; dispose editor AND models on unmount.
47
- useEffect(() => {
48
- const host = hostRef.current;
49
- if (!monaco || !host) return;
50
- const originalModel = monaco.editor.createModel('', 'plaintext');
51
- const modifiedModel = monaco.editor.createModel('', 'plaintext');
52
- const editor = monaco.editor.createDiffEditor(host, {
53
- readOnly: true,
54
- renderSideBySide: true,
55
- automaticLayout: true,
56
- minimap: { enabled: false },
57
- wordWrap: 'on',
58
- scrollBeyondLastLine: false,
59
- renderOverviewRuler: false,
60
- });
61
- editor.setModel({ original: originalModel, modified: modifiedModel });
62
- editorRef.current = editor;
63
- modelsRef.current = { original: originalModel, modified: modifiedModel };
64
- return () => {
65
- editorRef.current = null;
66
- modelsRef.current = null;
67
- editor.dispose();
68
- originalModel.dispose();
69
- modifiedModel.dispose();
70
- };
71
- }, [monaco]);
72
-
73
- // Sync content + language into the existing models — never recreate the editor.
74
- useEffect(() => {
75
- if (!monaco) return;
76
- const models = modelsRef.current;
77
- if (!models) return;
78
- if (models.original.getValue() !== original) models.original.setValue(original);
79
- if (models.modified.getValue() !== modified) models.modified.setValue(modified);
80
- monaco.editor.setModelLanguage(models.original, language);
81
- monaco.editor.setModelLanguage(models.modified, language);
82
- }, [monaco, original, modified, language]);
83
-
84
- // React to theme prop changes.
85
- useEffect(() => {
86
- if (!monaco) return;
87
- monaco.editor.setTheme(theme === 'dark' ? 'vs-dark' : 'vs');
88
- }, [monaco, theme]);
89
-
90
- if (!ready) {
91
- return <div className="db-git-diff-loading">Loading diff…</div>;
92
- }
93
-
94
- return (
95
- <>
96
- {labels && (
97
- <div className="db-git-diff-labels">
98
- <span>{labels.original}</span>
99
- <span>{labels.modified}</span>
100
- </div>
101
- )}
102
- <div ref={hostRef} className="db-git-diff-host" />
103
- </>
104
- );
105
- }
@@ -1,195 +0,0 @@
1
- /**
2
- * GitHistoryDialog — paged commit log for the repository or a single file.
3
- *
4
- * Pages `git log` 50 commits at a time; a row expands (one at a time) to
5
- * show the full message body and the files changed in that commit — each
6
- * file opens the commit-vs-parent diff dialog (which replaces this one;
7
- * acceptable for v1).
8
- */
9
-
10
- import { useCallback, useEffect, useState } from 'react';
11
- import type { GitFileChange, GitLogEntry } from '@bendyline/docblocks/host';
12
- import { Dialog } from '../components/Dialog.js';
13
- import { useGitContext } from './GitContext.js';
14
- import { BADGE_GLYPHS, BADGE_LABELS, badgeKindFor } from './git-status.js';
15
-
16
- export interface GitHistoryDialogProps {
17
- /** Slash-prefixed workspace-relative path; absent → whole-repo history. */
18
- path?: string;
19
- onClose: () => void;
20
- }
21
-
22
- const PAGE_SIZE = 50;
23
-
24
- type CommitDetail = { body: string; files: GitFileChange[] } | { error: string };
25
-
26
- /** Message body beyond the subject line, or '' when it adds nothing. */
27
- function extraBody(body: string, subject: string): string {
28
- const trimmedBody = body.trim();
29
- const trimmedSubject = subject.trim();
30
- if (!trimmedBody || trimmedBody === trimmedSubject) return '';
31
- if (trimmedBody.startsWith(trimmedSubject)) {
32
- return trimmedBody.slice(trimmedSubject.length).trim();
33
- }
34
- return trimmedBody;
35
- }
36
-
37
- function formatDate(iso: string): string {
38
- const date = new Date(iso);
39
- return `${date.toLocaleDateString()} ${date.toLocaleTimeString()}`;
40
- }
41
-
42
- export function GitHistoryDialog({ path, onClose }: GitHistoryDialogProps) {
43
- const git = useGitContext();
44
- const gitApi = git?.gitApi ?? null;
45
- const repositoryId = git?.repositoryId ?? null;
46
-
47
- const [entries, setEntries] = useState<GitLogEntry[]>([]);
48
- const [loading, setLoading] = useState(false);
49
- const [error, setError] = useState<string | null>(null);
50
- const [hasMore, setHasMore] = useState(false);
51
- const [expandedSha, setExpandedSha] = useState<string | null>(null);
52
- const [details, setDetails] = useState<ReadonlyMap<string, CommitDetail>>(new Map());
53
-
54
- const loadPage = useCallback(
55
- async (skip: number) => {
56
- if (!gitApi || !repositoryId) return;
57
- setLoading(true);
58
- setError(null);
59
- try {
60
- const result = await gitApi.log(repositoryId, { path, maxCount: PAGE_SIZE, skip });
61
- if (!result.ok) {
62
- setError(result.error.message);
63
- return;
64
- }
65
- setEntries((prev) => (skip === 0 ? result.value : [...prev, ...result.value]));
66
- setHasMore(result.value.length === PAGE_SIZE);
67
- } finally {
68
- setLoading(false);
69
- }
70
- },
71
- [gitApi, repositoryId, path],
72
- );
73
-
74
- useEffect(() => {
75
- setEntries([]);
76
- setExpandedSha(null);
77
- setDetails(new Map());
78
- setHasMore(false);
79
- void loadPage(0);
80
- }, [loadPage]);
81
-
82
- const handleRowClick = (sha: string) => {
83
- if (expandedSha === sha) {
84
- setExpandedSha(null);
85
- return;
86
- }
87
- setExpandedSha(sha);
88
- if (!gitApi || !repositoryId || details.has(sha)) return;
89
- void gitApi.commitFiles(repositoryId, sha).then((result) => {
90
- setDetails((prev) => {
91
- const next = new Map(prev);
92
- next.set(sha, result.ok ? result.value : { error: result.error.message });
93
- return next;
94
- });
95
- });
96
- };
97
-
98
- if (!git) return null;
99
-
100
- const baseName = path ? path.replace(/^\/+/, '').split('/').pop() : null;
101
- const title = baseName ? `History — ${baseName}` : 'Commit history';
102
-
103
- return (
104
- <Dialog title={title} size="wide" onClose={onClose}>
105
- {error && (
106
- <p className="db-git-form-error" role="alert">
107
- {error}
108
- </p>
109
- )}
110
- {!error && entries.length === 0 && loading && <p className="db-git-hint">Loading history…</p>}
111
- {!error && entries.length === 0 && !loading && <p className="db-git-hint">No commits yet.</p>}
112
- {entries.length > 0 && (
113
- <ul className="db-git-history-list">
114
- {entries.map((entry) => {
115
- const expanded = expandedSha === entry.sha;
116
- const detail = details.get(entry.sha);
117
- const meta = [
118
- entry.authorName,
119
- entry.sha.slice(0, 7),
120
- formatDate(entry.authorDate),
121
- entry.refs.join(', '),
122
- ]
123
- .filter(Boolean)
124
- .join(' · ');
125
- const body =
126
- detail && !('error' in detail) ? extraBody(detail.body, entry.subject) : '';
127
- return (
128
- <li key={entry.sha} className="db-git-history-item">
129
- <button
130
- type="button"
131
- className="db-git-history-toggle"
132
- aria-expanded={expanded}
133
- onClick={() => handleRowClick(entry.sha)}
134
- >
135
- <span className="db-git-history-subject">{entry.subject}</span>
136
- <span className="db-git-history-meta">{meta}</span>
137
- </button>
138
- {expanded && !detail && <p className="db-git-hint">Loading…</p>}
139
- {expanded && detail && 'error' in detail && (
140
- <p className="db-git-form-error" role="alert">
141
- {detail.error}
142
- </p>
143
- )}
144
- {expanded && detail && !('error' in detail) && (
145
- <>
146
- {body && <pre className="db-git-history-body">{body}</pre>}
147
- <ul className="db-git-history-files">
148
- {detail.files.map((file) => {
149
- const kind = badgeKindFor(file);
150
- return (
151
- <li key={file.path}>
152
- <button
153
- type="button"
154
- className="db-git-history-file"
155
- onClick={() =>
156
- git.openDialog({
157
- kind: 'diff',
158
- path: file.path,
159
- revision: { sha: entry.sha },
160
- })
161
- }
162
- >
163
- <span
164
- className="db-git-file-kind"
165
- aria-label={BADGE_LABELS[kind]}
166
- title={BADGE_LABELS[kind]}
167
- >
168
- {BADGE_GLYPHS[kind]}
169
- </span>
170
- {file.path.replace(/^\/+/, '')}
171
- </button>
172
- </li>
173
- );
174
- })}
175
- </ul>
176
- </>
177
- )}
178
- </li>
179
- );
180
- })}
181
- </ul>
182
- )}
183
- {hasMore && (
184
- <button
185
- type="button"
186
- className="db-git-secondary-btn"
187
- disabled={loading}
188
- onClick={() => void loadPage(entries.length)}
189
- >
190
- Show older commits
191
- </button>
192
- )}
193
- </Dialog>
194
- );
195
- }
@@ -1,157 +0,0 @@
1
- /**
2
- * GitStatusBar — slim sidebar row showing branch, ahead/behind, and dirty
3
- * count, with the repo actions menu (commit, sync, branches, history,
4
- * remote conveniences). Renders nothing unless the active workspace is a
5
- * git repository.
6
- */
7
-
8
- import { useCallback, useEffect, useRef, useState } from 'react';
9
- import { useGitContext } from './GitContext.js';
10
- import { formatAheadBehind, summarizeDirty } from './git-status.js';
11
-
12
- export function GitStatusBar() {
13
- const git = useGitContext();
14
- const [menuOpen, setMenuOpen] = useState(false);
15
- const rootRef = useRef<HTMLDivElement>(null);
16
-
17
- useEffect(() => {
18
- if (!menuOpen) return;
19
- const onPointerDown = (e: PointerEvent) => {
20
- if (rootRef.current && !rootRef.current.contains(e.target as Node)) {
21
- setMenuOpen(false);
22
- }
23
- };
24
- document.addEventListener('pointerdown', onPointerDown);
25
- return () => document.removeEventListener('pointerdown', onPointerDown);
26
- }, [menuOpen]);
27
-
28
- const runItem = useCallback((action: () => void) => {
29
- setMenuOpen(false);
30
- action();
31
- }, []);
32
-
33
- if (!git || !git.repo || !git.status) return null;
34
-
35
- const { status } = git;
36
- const branchLabel = status.detached ? 'detached HEAD' : (status.branch ?? 'no branch');
37
- const aheadBehind = formatAheadBehind(status);
38
- const dirty = summarizeDirty(status);
39
- const merging = status.operation === 'merge';
40
- const chipLabelParts = [`Git: branch ${branchLabel}`];
41
- if (status.ahead > 0) chipLabelParts.push(`${status.ahead} ahead`);
42
- if (status.behind > 0) chipLabelParts.push(`${status.behind} behind`);
43
- if (dirty) chipLabelParts.push(dirty);
44
- if (merging) chipLabelParts.push('merge in progress');
45
-
46
- const canCreatePr =
47
- git.capabilities?.ghAvailable === true && git.remoteWeb?.host === 'github.com';
48
-
49
- return (
50
- <div ref={rootRef} className="db-git-statusbar">
51
- <button
52
- type="button"
53
- className="db-git-statusbar-chip"
54
- onClick={() => setMenuOpen((open) => !open)}
55
- aria-haspopup="menu"
56
- aria-expanded={menuOpen}
57
- aria-label={chipLabelParts.join(', ')}
58
- title={chipLabelParts.join(', ')}
59
- >
60
- <span className="db-git-branch-glyph" aria-hidden="true">
61
- {'⎇'}
62
- </span>
63
- <span className="db-git-statusbar-branch">{branchLabel}</span>
64
- {aheadBehind && <span className="db-git-statusbar-counts">{aheadBehind}</span>}
65
- {dirty && <span className="db-git-statusbar-dirty">{dirty}</span>}
66
- {merging && <span className="db-git-statusbar-merge">merging</span>}
67
- {git.busy && (
68
- <span className="db-git-statusbar-busy" aria-hidden="true">
69
- {'…'}
70
- </span>
71
- )}
72
- </button>
73
-
74
- {menuOpen && (
75
- <div className="db-git-menu" role="menu" aria-label="Git actions">
76
- <button
77
- type="button"
78
- role="menuitem"
79
- className="db-git-menu-item"
80
- disabled={status.changes.length === 0 && !merging}
81
- onClick={() => runItem(() => git.openDialog({ kind: 'commit' }))}
82
- >
83
- {merging ? 'Commit merge…' : 'Commit…'}
84
- </button>
85
- <button
86
- type="button"
87
- role="menuitem"
88
- className="db-git-menu-item"
89
- disabled={git.busy !== null}
90
- onClick={() => runItem(() => void git.push())}
91
- >
92
- {status.upstream === null && !status.unborn ? 'Publish branch' : 'Push'}
93
- </button>
94
- <button
95
- type="button"
96
- role="menuitem"
97
- className="db-git-menu-item"
98
- disabled={git.busy !== null}
99
- onClick={() => runItem(() => void git.pull())}
100
- >
101
- Pull
102
- </button>
103
- <button
104
- type="button"
105
- role="menuitem"
106
- className="db-git-menu-item"
107
- disabled={git.busy !== null}
108
- onClick={() => runItem(() => void git.fetchRemote())}
109
- >
110
- Fetch
111
- </button>
112
- <div className="db-git-menu-divider" role="separator" />
113
- <button
114
- type="button"
115
- role="menuitem"
116
- className="db-git-menu-item"
117
- onClick={() => runItem(() => git.openDialog({ kind: 'branches' }))}
118
- >
119
- Branches…
120
- </button>
121
- <button
122
- type="button"
123
- role="menuitem"
124
- className="db-git-menu-item"
125
- onClick={() => runItem(() => git.openDialog({ kind: 'history' }))}
126
- >
127
- Commit history…
128
- </button>
129
- {(git.remoteWeb || canCreatePr) && (
130
- <div className="db-git-menu-divider" role="separator" />
131
- )}
132
- {git.remoteWeb && (
133
- <button
134
- type="button"
135
- role="menuitem"
136
- className="db-git-menu-item"
137
- onClick={() => runItem(() => git.openOnRemote())}
138
- >
139
- Open on {git.remoteWeb.host}
140
- </button>
141
- )}
142
- {canCreatePr && (
143
- <button
144
- type="button"
145
- role="menuitem"
146
- className="db-git-menu-item"
147
- disabled={git.busy !== null}
148
- onClick={() => runItem(() => void git.createPullRequest())}
149
- >
150
- Create pull request
151
- </button>
152
- )}
153
- </div>
154
- )}
155
- </div>
156
- );
157
- }