file-tree.ts 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. import _ from 'lodash'
  2. import type { FileDiff, FileRenamed } from '../services/types/file'
  3. import { isFileChanged, isFileEditable, 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. editable: false,
  35. }
  36. currentFileTreeLocation.push(fileTreeEntity)
  37. }
  38. currentFileTreeLocation = fileTreeEntity.children ?? []
  39. }
  40. }
  41. return currentFileTree
  42. }
  43. export type HistoryDoc = {
  44. name: string
  45. } & FileDiff
  46. export type HistoryFileTree = {
  47. docs?: HistoryDoc[]
  48. folders: HistoryFileTree[]
  49. name: string
  50. }
  51. export function fileTreeDiffToFileTreeData(
  52. fileTreeDiff: FileTreeEntity[],
  53. currentFolderName = 'rootFolder' // default value from angular version
  54. ): HistoryFileTree {
  55. const folders: HistoryFileTree[] = []
  56. const docs: HistoryDoc[] = []
  57. for (const fileDiff of fileTreeDiff) {
  58. if (fileDiff.type === 'file') {
  59. if (isFileChanged(fileDiff)) {
  60. docs.push({
  61. pathname: fileDiff.pathname ?? '',
  62. name: fileDiff.name ?? '',
  63. editable: isFileEditable(fileDiff),
  64. operation: fileDiff.operation,
  65. deletedAtV: isFileRemoved(fileDiff) ? fileDiff.deletedAtV : undefined,
  66. })
  67. } else {
  68. docs.push({
  69. pathname: fileDiff.pathname ?? '',
  70. name: fileDiff.name ?? '',
  71. editable: isFileEditable(fileDiff),
  72. })
  73. }
  74. } else if (fileDiff.type === 'folder') {
  75. if (fileDiff.children) {
  76. const folder = fileTreeDiffToFileTreeData(
  77. fileDiff.children,
  78. fileDiff.name
  79. )
  80. folders.push(folder)
  81. }
  82. }
  83. }
  84. return {
  85. docs,
  86. folders,
  87. name: currentFolderName,
  88. }
  89. }
  90. // TODO: refactor the oldPathname/newPathname data
  91. // It's an artifact from the angular version.
  92. // Our API returns `pathname` and `newPathname` for `renamed` operation
  93. // In the angular version, we change the key of the data:
  94. // 1. `pathname` -> `oldPathname`
  95. // 2. `newPathname` -> `pathname`
  96. // 3. Delete the `newPathname` key from the object
  97. // This is because the angular version wants to generalize the API usage
  98. // In the operation other than the `renamed` operation, the diff API (/project/:id/diff) consumes the `pathname`
  99. // But the `renamed` operation consumes the `newPathname` instead of the `pathname` data
  100. //
  101. // This behaviour can be refactored by introducing a conditional when calling the API
  102. // i.e if `renamed` -> use `newPathname`, else -> use `pathname`
  103. export function renamePathnameKey(file: FileRenamed): FileRenamed {
  104. return {
  105. oldPathname: file.pathname,
  106. pathname: file.newPathname as string,
  107. operation: file.operation,
  108. editable: file.editable,
  109. }
  110. }