Skip to content
This repository was archived by the owner on Oct 19, 2026. It is now read-only.

Commit f3442c6

Browse files
authored
refactor: update files changed UI and path handling (#1722)
1 parent b698d55 commit f3442c6

5 files changed

Lines changed: 91 additions & 21 deletions

File tree

‎moon/apps/web/components/ClView/FileChangeTab.tsx‎

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,50 @@ interface FileChangeTabProps {
1111
}
1212

1313
export const FileChangeTab = React.memo<FileChangeTabProps>(({ id }) => {
14-
const [page] = React.useState(1)
14+
const PER_PAGE = 100
15+
16+
const [page, setPage] = React.useState(1)
17+
const [isScrollLoading, setIsScrollLoading] = React.useState(false)
18+
1519
const { fileChanged: ClFilesChangedData, isLoading: isFileChangeLoading } = useGetClFileChanged(id, {
1620
page,
17-
per_page: 100
21+
per_page: PER_PAGE
1822
})
1923

2024
const { data: treeResponse, isLoading: treeIsLoading } = useGetClFileTree(id)
2125

26+
const totalPages = ClFilesChangedData?.total ?? 0
27+
const hasMoreData = totalPages > 0 && page < totalPages
28+
29+
React.useEffect(() => {
30+
if (!isFileChangeLoading && isScrollLoading) {
31+
setIsScrollLoading(false)
32+
}
33+
}, [isFileChangeLoading, isScrollLoading])
34+
35+
const isInitialLoading =
36+
(isFileChangeLoading || treeIsLoading) &&
37+
page === 1 &&
38+
(!ClFilesChangedData?.items || ClFilesChangedData.items.length === 0)
39+
40+
const isBlockingLoading = isInitialLoading || isScrollLoading
41+
42+
const handleLoadMore = React.useCallback(() => {
43+
if (isScrollLoading || isFileChangeLoading || !hasMoreData) return
44+
setIsScrollLoading(true)
45+
setPage((prev) => prev + 1)
46+
}, [hasMoreData, isFileChangeLoading, isScrollLoading])
47+
2248
return (
2349
<FileDiff
2450
fileChangeData={ClFilesChangedData}
2551
fileChangeIsLoading={isFileChangeLoading}
2652
treeData={treeResponse?.data as CommonResultVecMuiTreeNode['data']}
2753
treeIsLoading={treeIsLoading}
54+
page={page}
55+
hasMoreData={hasMoreData}
56+
isBlockingLoading={isBlockingLoading}
57+
onLoadMore={handleLoadMore}
2858
/>
2959
)
3060
})

‎moon/apps/web/components/CodeView/CommitsView/detail/index.tsx‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,10 @@ export const CommitsDetailView: React.FC = () => {
246246
fileChangeIsLoading={isLoadingFilesChanged}
247247
treeData={treeResponse?.data as CommonResultVecMuiTreeNode['data']}
248248
treeIsLoading={treeIsLoading}
249+
page={1}
250+
hasMoreData={false}
251+
isBlockingLoading={isLoadingFilesChanged || treeIsLoading}
252+
onLoadMore={() => undefined}
249253
/>
250254
) : (
251255
<div className='flex h-[200px] items-center justify-center text-gray-500'>No file changes</div>

‎moon/apps/web/components/DiffView/FileDiff.tsx‎

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -66,15 +66,25 @@ interface FileDiffProps {
6666
fileChangeIsLoading: boolean
6767
treeData: CommonResultVecMuiTreeNode['data']
6868
treeIsLoading: boolean
69+
page: number
70+
hasMoreData: boolean
71+
isBlockingLoading: boolean
72+
onLoadMore: () => void
6973
}
7074

71-
export default function FileDiff({ fileChangeData, fileChangeIsLoading, treeData, treeIsLoading }: FileDiffProps) {
75+
export default function FileDiff({
76+
fileChangeData,
77+
fileChangeIsLoading,
78+
treeData,
79+
treeIsLoading,
80+
page,
81+
hasMoreData,
82+
isBlockingLoading,
83+
onLoadMore
84+
}: FileDiffProps) {
7285
const virtuosoRef = useRef<any>(null)
7386

74-
const [page, setPage] = useState(1)
75-
7687
const [pageDataMap, setPageDataMap] = useState<Map<number, DiffItem[]>>(new Map())
77-
const [totalCount, setTotalCount] = useState(0)
7888

7989
useEffect(() => {
8090
if (fileChangeData?.items && !fileChangeIsLoading) {
@@ -86,8 +96,6 @@ export default function FileDiff({ fileChangeData, fileChangeIsLoading, treeData
8696
}
8797
return newMap
8898
})
89-
90-
setTotalCount(fileChangeData.total)
9199
}
92100
}, [fileChangeData, fileChangeIsLoading, page])
93101

@@ -137,14 +145,10 @@ export default function FileDiff({ fileChangeData, fileChangeIsLoading, treeData
137145
[parsedFiles]
138146
)
139147

140-
const hasMoreData = useMemo(() => {
141-
return fileDiff.length < totalCount
142-
}, [fileDiff.length, totalCount])
143-
144148
const loadMoreDiffs = useCallback(() => {
145149
if (fileChangeIsLoading || !hasMoreData) return
146-
setPage((prev) => prev + 1)
147-
}, [fileChangeIsLoading, hasMoreData])
150+
onLoadMore()
151+
}, [fileChangeIsLoading, hasMoreData, onLoadMore])
148152

149153
useEffect(() => {
150154
setExpandedMap(Object.fromEntries(diffFiles.map((f) => [f.path, false])))
@@ -214,13 +218,21 @@ export default function FileDiff({ fileChangeData, fileChangeIsLoading, treeData
214218
}
215219

216220
return (
217-
<div className='mt-3 flex font-sans'>
221+
<div className='relative mt-3 flex font-sans'>
222+
{isBlockingLoading && (
223+
<div className='fixed inset-0 z-50 flex items-center justify-center bg-white/60'>
224+
<div className='flex items-center rounded-md bg-white px-3 py-2 shadow'>
225+
<LoadingSpinner />
226+
<span className='ml-2 text-sm text-gray-600'>Loading diffs...</span>
227+
</div>
228+
</div>
229+
)}
218230
<div className='sticky top-5 h-[80vh] w-[300px] overflow-y-auto rounded-lg p-2'>
219231
<FileTree treeData={treeData} treeDataLoading={treeIsLoading} onFileClick={scrollToFile} />
220232
</div>
221233

222234
<div className='h-full w-full flex-1 px-4'>
223-
{totalCount === 0 && !fileChangeIsLoading ? (
235+
{fileDiff.length === 0 && !fileChangeIsLoading && page === 1 ? (
224236
<div className='flex h-[85vh] items-center justify-center'>No File Changed</div>
225237
) : (
226238
<Virtuoso
@@ -229,7 +241,7 @@ export default function FileDiff({ fileChangeData, fileChangeIsLoading, treeData
229241
totalCount={parsedFiles.length}
230242
itemContent={DiffItem}
231243
endReached={loadMoreDiffs}
232-
components={{ Footer: () => fileChangeIsLoading && <LoadingSpinner /> }}
244+
components={{ Footer: () => null }}
233245
increaseViewportBy={350}
234246
/>
235247
)}

‎moon/apps/web/components/DiffView/TreeView/TreeUtils.ts‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,14 @@ export const convertToTreeData = (responseData: any): MuiTreeNode[] => {
6565

6666
// Handle the new API format where responseData is the tree structure directly
6767
const convertNode = (node: any, parentPath: string = ''): MuiTreeNode => {
68-
// Build the full path by combining parent path with current node label
69-
const fullPath = parentPath ? `${parentPath}/${node.label}` : node.label
68+
const rawPath: string | undefined = node.path
69+
let fullPath: string
70+
71+
if (typeof rawPath === 'string' && rawPath.length > 0) {
72+
fullPath = rawPath.startsWith('/') ? rawPath.slice(1) : rawPath
73+
} else {
74+
fullPath = parentPath ? `${parentPath}/${node.label}` : node.label
75+
}
7076

7177
return {
7278
id: node.id,

‎moon/apps/web/components/Post/Notes/DragAndDrop.ts‎

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,25 @@
11
import { Extension } from '@tiptap/core'
2+
import { DOMSerializer } from '@tiptap/pm/model'
23
import { NodeSelection, Plugin, PluginKey, TextSelection } from '@tiptap/pm/state'
34
// @ts-ignore
4-
import { __serializeForClipboard, EditorView } from '@tiptap/pm/view'
5+
import { EditorView } from '@tiptap/pm/view'
6+
7+
function serializeForClipboard(view: EditorView, slice: any): { dom: HTMLElement; text: string } {
8+
const wrap = document.createElement('div')
9+
10+
try {
11+
const serializer = DOMSerializer.fromSchema(view.state.schema)
12+
13+
wrap.appendChild(serializer.serializeFragment(slice.content))
14+
} catch (_e) {
15+
// ignored
16+
}
17+
18+
return {
19+
dom: wrap,
20+
text: (wrap.textContent ?? '').toString()
21+
}
22+
}
523

624
interface DragHandleOptions {
725
dragHandleWidth: number
@@ -74,7 +92,7 @@ function DragHandle(options: DragHandleOptions) {
7492
view.dispatch(view.state.tr.setSelection(NodeSelection.create(view.state.doc, nodePos)))
7593

7694
const slice = view.state.selection.content()
77-
const { dom, text } = __serializeForClipboard(view, slice)
95+
const { dom, text } = serializeForClipboard(view, slice)
7896

7997
event.dataTransfer.clearData()
8098
event.dataTransfer.setData('text/html', dom.innerHTML)

0 commit comments

Comments
 (0)