file-tree.ts 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. import _ from 'lodash'
  2. import type { FileDiff, FileRenamed } from '../services/types/file'
  3. import { isFileRemoved } from './file-diff'
  4. export type FileTreeEntity = {
  5. name?: string
  6. type?: 'file' | 'folder'
  7. children?: FileTreeEntity[]
  8. } & FileDiff
  9. export function reducePathsToTree(
  10. currentFileTree: FileTreeEntity[],
  11. fileObject: FileTreeEntity
  12. ) {
  13. const filePathParts = fileObject?.pathname?.split('/') ?? ''
  14. let currentFileTreeLocation = currentFileTree
  15. for (let index = 0; index < filePathParts.length; index++) {
  16. const pathPart = filePathParts[index]
  17. const isFile = index === filePathParts.length - 1
  18. if (isFile) {
  19. const fileTreeEntity: FileTreeEntity = _.clone(fileObject)
  20. fileTreeEntity.name = pathPart
  21. fileTreeEntity.type = 'file'
  22. currentFileTreeLocation.push(fileTreeEntity)
  23. } else {
  24. let fileTreeEntity: FileTreeEntity | undefined = _.find(
  25. currentFileTreeLocation,
  26. entity => entity.name === pathPart
  27. )
  28. if (fileTreeEntity === undefined) {
  29. fileTreeEntity = {
  30. name: pathPart,
  31. type: 'folder',
  32. children: <FileTreeEntity[]>[],
  33. pathname: pathPart,
  34. }
  35. currentFileTreeLocation.push(fileTreeEntity)
  36. }
  37. currentFileTreeLocation = fileTreeEntity.children ?? []
  38. }
  39. }
  40. return currentFileTree
  41. }
  42. export type HistoryDoc = {
  43. name: string
  44. } & FileDiff
  45. export type HistoryFileTree = {
  46. docs?: HistoryDoc[]
  47. folders: HistoryFileTree[]
  48. name: string
  49. }
  50. export function fileTreeDiffToFileTreeData(
  51. fileTreeDiff: FileTreeEntity[],
  52. currentFolderName = 'rootFolder' // default value from angular version
  53. ): HistoryFileTree {
  54. const folders: HistoryFileTree[] = []
  55. const docs: HistoryDoc[] = []
  56. for (const file of fileTreeDiff) {
  57. if (file.type === 'file') {
  58. const deletedAtV = isFileRemoved(file) ? file.deletedAtV : undefined
  59. let newDoc: HistoryDoc = {
  60. pathname: file.pathname ?? '',
  61. name: file.name ?? '',
  62. deletedAtV,
  63. }
  64. if ('operation' in file) {
  65. newDoc = {
  66. ...newDoc,
  67. operation: file.operation,
  68. }
  69. }
  70. docs.push(newDoc)
  71. } else if (file.type === 'folder') {
  72. if (file.children) {
  73. const folder = fileTreeDiffToFileTreeData(file.children, file.name)
  74. folders.push(folder)
  75. }
  76. }
  77. }
  78. return {
  79. docs,
  80. folders,
  81. name: currentFolderName,
  82. }
  83. }
  84. // TODO: refactor the oldPathname/newPathname data
  85. // It's an artifact from the angular version.
  86. // Our API returns `pathname` and `newPathname` for `renamed` operation
  87. // In the angular version, we change the key of the data:
  88. // 1. `pathname` -> `oldPathname`
  89. // 2. `newPathname` -> `pathname`
  90. // 3. Delete the `newPathname` key from the object
  91. // This is because the angular version wants to generalize the API usage
  92. // In the operation other than the `renamed` operation, the diff API (/project/:id/diff) consumes the `pathname`
  93. // But the `renamed` operation consumes the `newPathname` instead of the `pathname` data
  94. //
  95. // This behaviour can be refactored by introducing a conditional when calling the API
  96. // i.e if `renamed` -> use `newPathname`, else -> use `pathname`
  97. export function renamePathnameKey(file: FileRenamed): FileRenamed {
  98. return {
  99. oldPathname: file.pathname,
  100. pathname: file.newPathname as string,
  101. operation: file.operation,
  102. }
  103. }