3.5 KB109 lines
Blame
1/**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8import type {Set as ImSet} from 'immutable';
9import type {ChangedFile, ChangedFileStatus, RepoRelativePath} from './types';
10import type {UIChangedFile, VisualChangedFileStatus} from './UncommittedChanges';
11
12import {minimalDisambiguousPaths} from 'shared/minimalDisambiguousPaths';
13import {notEmpty} from 'shared/utils';
14import {t} from './i18n';
15import {ChangedFileMode} from './types';
16
17export function processChangedFiles(
18 files: Array<ChangedFile>,
19 submodulePaths: ImSet<RepoRelativePath> | undefined,
20): Array<UIChangedFile> {
21 const disambiguousPaths = minimalDisambiguousPaths(files.map(file => file.path));
22 const copySources = new Set(files.map(file => file.copy).filter(notEmpty));
23 const removedFiles = new Set(files.filter(file => file.status === 'R').map(file => file.path));
24
25 return (
26 files
27 .map((file, i) => {
28 const minimalName = disambiguousPaths[i];
29 const mode =
30 submodulePaths && submodulePaths.has(file.path)
31 ? ChangedFileMode.Submodule
32 : ChangedFileMode.Regular;
33 let fileLabel = minimalName;
34 let tooltip = `${nameForStatus(file.status)}: ${file.path}`;
35 let copiedFrom;
36 let renamedFrom;
37 let visualStatus: VisualChangedFileStatus = file.status;
38 if (file.copy != null) {
39 // Disambiguate between original file and the newly copy's name,
40 // instead of disambiguating among all file names.
41 const [originalName, copiedName] = minimalDisambiguousPaths([file.copy, file.path]);
42 fileLabel = `${originalName} → ${copiedName}`;
43 if (removedFiles.has(file.copy)) {
44 renamedFrom = file.copy;
45 tooltip = t('$newPath\n\nThis file was renamed from $originalPath', {
46 replace: {$newPath: file.path, $originalPath: file.copy},
47 });
48 visualStatus = 'Renamed';
49 } else {
50 copiedFrom = file.copy;
51 tooltip = t('$newPath\n\nThis file was copied from $originalPath', {
52 replace: {$newPath: file.path, $originalPath: file.copy},
53 });
54 visualStatus = 'Copied';
55 }
56 }
57
58 return {
59 path: file.path,
60 label: fileLabel,
61 status: file.status,
62 mode,
63 visualStatus,
64 copiedFrom,
65 renamedFrom,
66 tooltip,
67 };
68 })
69 // Hide files that were renamed. This comes after the map since we need to use the index to refer to minimalDisambiguousPaths
70 .filter(file => !(file.status === 'R' && copySources.has(file.path)))
71 .sort((a, b) =>
72 a.visualStatus === b.visualStatus
73 ? a.path.localeCompare(b.path)
74 : sortKeyForStatus[a.visualStatus] - sortKeyForStatus[b.visualStatus],
75 )
76 );
77}
78
79const sortKeyForStatus: Record<VisualChangedFileStatus, number> = {
80 M: 0,
81 Renamed: 1,
82 A: 2,
83 Copied: 3,
84 R: 4,
85 '!': 5,
86 '?': 6,
87 U: 7,
88 Resolved: 8,
89};
90
91function nameForStatus(status: ChangedFileStatus): string {
92 switch (status) {
93 case '!':
94 return t('Missing');
95 case '?':
96 return t('Untracked');
97 case 'A':
98 return t('Added');
99 case 'M':
100 return t('Modified');
101 case 'R':
102 return t('Removed');
103 case 'U':
104 return t('Unresolved');
105 case 'Resolved':
106 return t('Resolved');
107 }
108}
109