first commit
This commit is contained in:
@@ -0,0 +1,155 @@
|
||||
import { useCallback, useEffect } from 'react'
|
||||
|
||||
import { useUserContext } from '../../../shared/context/user-context'
|
||||
import { useFileTreeData } from '../../../shared/context/file-tree-data-context'
|
||||
import { useFileTreeSelectable } from '../contexts/file-tree-selectable'
|
||||
import { findInTree, findInTreeOrThrow } from '../util/find-in-tree'
|
||||
import { useIdeContext } from '@/shared/context/ide-context'
|
||||
import { useSnapshotContext } from '@/features/ide-react/context/snapshot-context'
|
||||
|
||||
export function useFileTreeSocketListener(onDelete: (entity: any) => void) {
|
||||
const user = useUserContext()
|
||||
const {
|
||||
dispatchRename,
|
||||
dispatchDelete,
|
||||
dispatchMove,
|
||||
dispatchCreateFolder,
|
||||
dispatchCreateDoc,
|
||||
dispatchCreateFile,
|
||||
fileTreeData,
|
||||
} = useFileTreeData()
|
||||
const { selectedEntityIds, selectedEntityParentIds, select, unselect } =
|
||||
useFileTreeSelectable()
|
||||
const { socket } = useIdeContext()
|
||||
const { fileTreeFromHistory } = useSnapshotContext()
|
||||
|
||||
const selectEntityIfCreatedByUser = useCallback(
|
||||
// hack to automatically re-open refreshed linked files
|
||||
(entityId, entityName, userId) => {
|
||||
// If the created entity's user exists and is the current user
|
||||
if (userId && user?.id === userId) {
|
||||
// And we're expecting a refreshed socket for this entity
|
||||
if (window.expectingLinkedFileRefreshedSocketFor === entityName) {
|
||||
// Then select it
|
||||
select(entityId)
|
||||
window.expectingLinkedFileRefreshedSocketFor = null
|
||||
}
|
||||
}
|
||||
},
|
||||
[user, select]
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
if (fileTreeFromHistory) return
|
||||
function handleDispatchRename(entityId: string, name: string) {
|
||||
dispatchRename(entityId, name)
|
||||
}
|
||||
if (socket) socket.on('reciveEntityRename', handleDispatchRename)
|
||||
return () => {
|
||||
if (socket)
|
||||
socket.removeListener('reciveEntityRename', handleDispatchRename)
|
||||
}
|
||||
}, [socket, dispatchRename, fileTreeFromHistory])
|
||||
|
||||
useEffect(() => {
|
||||
if (fileTreeFromHistory) return
|
||||
function handleDispatchDelete(entityId: string) {
|
||||
const entity = findInTree(fileTreeData, entityId)
|
||||
unselect(entityId)
|
||||
if (selectedEntityParentIds.has(entityId)) {
|
||||
// we're deleting a folder with a selected children so we need to
|
||||
// unselect its selected children first
|
||||
for (const selectedEntityId of selectedEntityIds) {
|
||||
if (
|
||||
findInTreeOrThrow(fileTreeData, selectedEntityId).path.includes(
|
||||
entityId
|
||||
)
|
||||
) {
|
||||
unselect(selectedEntityId)
|
||||
}
|
||||
}
|
||||
}
|
||||
dispatchDelete(entityId)
|
||||
if (onDelete) {
|
||||
onDelete(entity)
|
||||
}
|
||||
}
|
||||
if (socket) socket.on('removeEntity', handleDispatchDelete)
|
||||
return () => {
|
||||
if (socket) socket.removeListener('removeEntity', handleDispatchDelete)
|
||||
}
|
||||
}, [
|
||||
socket,
|
||||
unselect,
|
||||
dispatchDelete,
|
||||
fileTreeData,
|
||||
selectedEntityIds,
|
||||
selectedEntityParentIds,
|
||||
onDelete,
|
||||
fileTreeFromHistory,
|
||||
])
|
||||
|
||||
useEffect(() => {
|
||||
if (fileTreeFromHistory) return
|
||||
function handleDispatchMove(entityId: string, toFolderId: string) {
|
||||
dispatchMove(entityId, toFolderId)
|
||||
}
|
||||
if (socket) socket.on('reciveEntityMove', handleDispatchMove)
|
||||
return () => {
|
||||
if (socket) socket.removeListener('reciveEntityMove', handleDispatchMove)
|
||||
}
|
||||
}, [socket, dispatchMove, fileTreeFromHistory])
|
||||
|
||||
useEffect(() => {
|
||||
if (fileTreeFromHistory) return
|
||||
function handleDispatchCreateFolder(parentFolderId: string, folder: any) {
|
||||
dispatchCreateFolder(parentFolderId, folder)
|
||||
}
|
||||
if (socket) socket.on('reciveNewFolder', handleDispatchCreateFolder)
|
||||
return () => {
|
||||
if (socket)
|
||||
socket.removeListener('reciveNewFolder', handleDispatchCreateFolder)
|
||||
}
|
||||
}, [socket, dispatchCreateFolder, fileTreeFromHistory])
|
||||
|
||||
useEffect(() => {
|
||||
if (fileTreeFromHistory) return
|
||||
function handleDispatchCreateDoc(
|
||||
parentFolderId: string,
|
||||
doc: any,
|
||||
_source: unknown
|
||||
) {
|
||||
dispatchCreateDoc(parentFolderId, doc)
|
||||
}
|
||||
if (socket) socket.on('reciveNewDoc', handleDispatchCreateDoc)
|
||||
return () => {
|
||||
if (socket) socket.removeListener('reciveNewDoc', handleDispatchCreateDoc)
|
||||
}
|
||||
}, [socket, dispatchCreateDoc, fileTreeFromHistory])
|
||||
|
||||
useEffect(() => {
|
||||
if (fileTreeFromHistory) return
|
||||
function handleDispatchCreateFile(
|
||||
parentFolderId: string,
|
||||
file: any,
|
||||
_source: unknown,
|
||||
linkedFileData: any,
|
||||
userId: string
|
||||
) {
|
||||
dispatchCreateFile(parentFolderId, file)
|
||||
if (linkedFileData) {
|
||||
selectEntityIfCreatedByUser(file._id, file.name, userId)
|
||||
}
|
||||
}
|
||||
if (socket) socket.on('reciveNewFile', handleDispatchCreateFile)
|
||||
return () => {
|
||||
if (socket)
|
||||
socket.removeListener('reciveNewFile', handleDispatchCreateFile)
|
||||
}
|
||||
}, [
|
||||
socket,
|
||||
dispatchCreateFile,
|
||||
selectEntityIfCreatedByUser,
|
||||
fileTreeFromHistory,
|
||||
])
|
||||
}
|
@@ -0,0 +1,36 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { getJSON } from '../../../infrastructure/fetch-json'
|
||||
import { fileCollator } from '../util/file-collator'
|
||||
import useAbortController from '../../../shared/hooks/use-abort-controller'
|
||||
|
||||
export type Entity = {
|
||||
path: string
|
||||
}
|
||||
|
||||
const alphabetical = (a: Entity, b: Entity) =>
|
||||
fileCollator.compare(a.path, b.path)
|
||||
|
||||
export function useProjectEntities(projectId?: string) {
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [data, setData] = useState<Entity[] | null>(null)
|
||||
const [error, setError] = useState<any>(false)
|
||||
|
||||
const { signal } = useAbortController()
|
||||
|
||||
useEffect(() => {
|
||||
if (projectId) {
|
||||
setLoading(true)
|
||||
setError(false)
|
||||
setData(null)
|
||||
|
||||
getJSON(`/project/${projectId}/entities`, { signal })
|
||||
.then(data => {
|
||||
setData(data.entities.sort(alphabetical))
|
||||
})
|
||||
.catch(error => setError(error))
|
||||
.finally(() => setLoading(false))
|
||||
}
|
||||
}, [projectId, signal])
|
||||
|
||||
return { loading, data, error }
|
||||
}
|
@@ -0,0 +1,58 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { postJSON } from '../../../infrastructure/fetch-json'
|
||||
import { fileCollator } from '../util/file-collator'
|
||||
import useAbortController from '../../../shared/hooks/use-abort-controller'
|
||||
|
||||
export type OutputEntity = {
|
||||
path: string
|
||||
clsiServerId: string
|
||||
compileGroup: string
|
||||
build: string
|
||||
}
|
||||
|
||||
const alphabetical = (a: OutputEntity, b: OutputEntity) =>
|
||||
fileCollator.compare(a.path, b.path)
|
||||
|
||||
export function useProjectOutputFiles(projectId?: string) {
|
||||
const [loading, setLoading] = useState<boolean>(false)
|
||||
const [data, setData] = useState<OutputEntity[] | null>(null)
|
||||
const [error, setError] = useState<any>(false)
|
||||
|
||||
const { signal } = useAbortController()
|
||||
|
||||
useEffect(() => {
|
||||
if (projectId) {
|
||||
setLoading(true)
|
||||
setError(false)
|
||||
setData(null)
|
||||
|
||||
postJSON(`/project/${projectId}/compile`, {
|
||||
body: {
|
||||
check: 'silent',
|
||||
draft: false,
|
||||
incrementalCompilesEnabled: false,
|
||||
},
|
||||
signal,
|
||||
})
|
||||
.then(data => {
|
||||
if (data.status === 'success') {
|
||||
const filteredFiles = data.outputFiles.filter(
|
||||
(file: OutputEntity) =>
|
||||
file.path.match(/.*\.(pdf|png|jpeg|jpg|gif)/)
|
||||
)
|
||||
data.outputFiles.forEach((file: OutputEntity) => {
|
||||
file.clsiServerId = data.clsiServerId
|
||||
file.compileGroup = data.compileGroup
|
||||
})
|
||||
setData(filteredFiles.sort(alphabetical))
|
||||
} else {
|
||||
setError('linked-project-compile-error')
|
||||
}
|
||||
})
|
||||
.catch(error => setError(error))
|
||||
.finally(() => setLoading(false))
|
||||
}
|
||||
}, [projectId, signal])
|
||||
|
||||
return { loading, data, error }
|
||||
}
|
@@ -0,0 +1,32 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { getJSON } from '../../../infrastructure/fetch-json'
|
||||
import { fileCollator } from '../util/file-collator'
|
||||
import useAbortController from '../../../shared/hooks/use-abort-controller'
|
||||
|
||||
export type Project = {
|
||||
_id: string
|
||||
name: string
|
||||
accessLevel: string
|
||||
}
|
||||
|
||||
const alphabetical = (a: Project, b: Project) =>
|
||||
fileCollator.compare(a.name, b.name)
|
||||
|
||||
export function useUserProjects() {
|
||||
const [loading, setLoading] = useState(true)
|
||||
const [data, setData] = useState<Project[] | null>(null)
|
||||
const [error, setError] = useState<any>(false)
|
||||
|
||||
const { signal } = useAbortController()
|
||||
|
||||
useEffect(() => {
|
||||
getJSON('/user/projects', { signal })
|
||||
.then(data => {
|
||||
setData(data.projects.sort(alphabetical))
|
||||
})
|
||||
.catch(error => setError(error))
|
||||
.finally(() => setLoading(false))
|
||||
}, [signal])
|
||||
|
||||
return { loading, data, error }
|
||||
}
|
Reference in New Issue
Block a user