2023-03-28 12:12:32 -04:00
|
|
|
import _ from 'lodash'
|
|
|
|
import type { FileDiff, FileRenamed } from '../services/types/file'
|
2023-04-27 14:45:13 -04:00
|
|
|
import { isFileRemoved } from './file-diff'
|
2023-03-28 12:12:32 -04:00
|
|
|
|
2023-04-27 14:45:13 -04:00
|
|
|
export type FileTreeEntity = {
|
|
|
|
name?: string
|
|
|
|
type?: 'file' | 'folder'
|
|
|
|
children?: FileTreeEntity[]
|
|
|
|
} & FileDiff
|
2023-03-28 12:12:32 -04:00
|
|
|
|
|
|
|
export function reducePathsToTree(
|
|
|
|
currentFileTree: FileTreeEntity[],
|
|
|
|
fileObject: FileTreeEntity
|
|
|
|
) {
|
|
|
|
const filePathParts = fileObject?.pathname?.split('/') ?? ''
|
|
|
|
let currentFileTreeLocation = currentFileTree
|
2023-04-27 14:45:13 -04:00
|
|
|
|
2023-03-28 12:12:32 -04:00
|
|
|
for (let index = 0; index < filePathParts.length; index++) {
|
|
|
|
const pathPart = filePathParts[index]
|
|
|
|
const isFile = index === filePathParts.length - 1
|
2023-04-27 14:45:13 -04:00
|
|
|
|
2023-03-28 12:12:32 -04:00
|
|
|
if (isFile) {
|
2023-04-27 14:45:13 -04:00
|
|
|
const fileTreeEntity: FileTreeEntity = _.clone(fileObject)
|
2023-03-28 12:12:32 -04:00
|
|
|
fileTreeEntity.name = pathPart
|
|
|
|
fileTreeEntity.type = 'file'
|
2023-04-27 14:45:13 -04:00
|
|
|
|
2023-03-28 12:12:32 -04:00
|
|
|
currentFileTreeLocation.push(fileTreeEntity)
|
|
|
|
} else {
|
2023-04-27 14:45:13 -04:00
|
|
|
let fileTreeEntity: FileTreeEntity | undefined = _.find(
|
|
|
|
currentFileTreeLocation,
|
|
|
|
entity => entity.name === pathPart
|
|
|
|
)
|
|
|
|
|
|
|
|
if (fileTreeEntity === undefined) {
|
2023-03-28 12:12:32 -04:00
|
|
|
fileTreeEntity = {
|
|
|
|
name: pathPart,
|
|
|
|
type: 'folder',
|
2023-04-27 14:45:13 -04:00
|
|
|
children: <FileTreeEntity[]>[],
|
|
|
|
pathname: pathPart,
|
2023-03-28 12:12:32 -04:00
|
|
|
}
|
2023-04-27 14:45:13 -04:00
|
|
|
|
2023-03-28 12:12:32 -04:00
|
|
|
currentFileTreeLocation.push(fileTreeEntity)
|
|
|
|
}
|
|
|
|
currentFileTreeLocation = fileTreeEntity.children ?? []
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return currentFileTree
|
|
|
|
}
|
|
|
|
|
2023-04-11 14:08:56 -04:00
|
|
|
export type HistoryDoc = {
|
|
|
|
name: string
|
2023-04-27 14:45:13 -04:00
|
|
|
} & FileDiff
|
2023-04-04 12:00:30 -04:00
|
|
|
|
2023-04-03 12:40:32 -04:00
|
|
|
export type HistoryFileTree = {
|
2023-04-04 12:00:30 -04:00
|
|
|
docs?: HistoryDoc[]
|
2023-03-28 12:12:32 -04:00
|
|
|
folders: HistoryFileTree[]
|
|
|
|
name: string
|
|
|
|
}
|
|
|
|
|
|
|
|
export function fileTreeDiffToFileTreeData(
|
|
|
|
fileTreeDiff: FileTreeEntity[],
|
|
|
|
currentFolderName = 'rootFolder' // default value from angular version
|
|
|
|
): HistoryFileTree {
|
|
|
|
const folders: HistoryFileTree[] = []
|
2023-04-04 12:00:30 -04:00
|
|
|
const docs: HistoryDoc[] = []
|
2023-03-28 12:12:32 -04:00
|
|
|
|
|
|
|
for (const file of fileTreeDiff) {
|
|
|
|
if (file.type === 'file') {
|
2023-04-27 14:45:13 -04:00
|
|
|
const deletedAtV = isFileRemoved(file) ? file.deletedAtV : undefined
|
|
|
|
|
|
|
|
let newDoc: HistoryDoc = {
|
2023-04-11 14:08:56 -04:00
|
|
|
pathname: file.pathname ?? '',
|
2023-03-28 12:12:32 -04:00
|
|
|
name: file.name ?? '',
|
2023-04-27 14:45:13 -04:00
|
|
|
deletedAtV,
|
|
|
|
}
|
|
|
|
|
|
|
|
if ('operation' in file) {
|
|
|
|
newDoc = {
|
|
|
|
...newDoc,
|
|
|
|
operation: file.operation,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
docs.push(newDoc)
|
2023-03-28 12:12:32 -04:00
|
|
|
} else if (file.type === 'folder') {
|
|
|
|
if (file.children) {
|
|
|
|
const folder = fileTreeDiffToFileTreeData(file.children, file.name)
|
|
|
|
folders.push(folder)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
docs,
|
|
|
|
folders,
|
|
|
|
name: currentFolderName,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: refactor the oldPathname/newPathname data
|
|
|
|
// It's an artifact from the angular version.
|
|
|
|
// Our API returns `pathname` and `newPathname` for `renamed` operation
|
|
|
|
// In the angular version, we change the key of the data:
|
|
|
|
// 1. `pathname` -> `oldPathname`
|
|
|
|
// 2. `newPathname` -> `pathname`
|
|
|
|
// 3. Delete the `newPathname` key from the object
|
|
|
|
// This is because the angular version wants to generalize the API usage
|
|
|
|
// In the operation other than the `renamed` operation, the diff API (/project/:id/diff) consumes the `pathname`
|
|
|
|
// But the `renamed` operation consumes the `newPathname` instead of the `pathname` data
|
|
|
|
//
|
|
|
|
// This behaviour can be refactored by introducing a conditional when calling the API
|
|
|
|
// i.e if `renamed` -> use `newPathname`, else -> use `pathname`
|
|
|
|
export function renamePathnameKey(file: FileRenamed): FileRenamed {
|
|
|
|
return {
|
|
|
|
oldPathname: file.pathname,
|
|
|
|
pathname: file.newPathname as string,
|
|
|
|
operation: file.operation,
|
|
|
|
}
|
|
|
|
}
|