Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to switch between files in Git Diff widget #5965

Merged
merged 40 commits into from
Sep 12, 2017
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
2318d28
CHE-5892: Temporary state
mmorhun Aug 4, 2017
28ea7d4
CHE-5892: Use an object to hold git diff data
mmorhun Aug 7, 2017
5814596
CHE-5892: Draft solution.
mmorhun Aug 9, 2017
9f7d30c
Merge branch 'master' into CHE-5892
mmorhun Aug 9, 2017
88bc819
CHE-5892: Fix build and tests
mmorhun Aug 9, 2017
a3e2c7c
CHE-5892: Fix inverted comparation type
mmorhun Aug 9, 2017
e27895c
CHE-5892: Fix comparation between revisions
mmorhun Aug 10, 2017
72fb977
CHE-5892: Small refactor in ComparePresenter
mmorhun Aug 10, 2017
347b2e0
CHE-5892: Fix Save Changes button
mmorhun Aug 10, 2017
638153b
CHE-5892: Remove unnecessary imports
mmorhun Aug 10, 2017
9f18acd
CHE-5892: Small fixes
mmorhun Aug 10, 2017
3cd740e
CHE-5892: Rename ChangedItems
mmorhun Aug 11, 2017
f22b649
CHE-5892: Fix compare with deleted file bug.
mmorhun Aug 11, 2017
2f82bec
License format
mmorhun Aug 14, 2017
d148050
License Format
mmorhun Aug 14, 2017
5d8744a
CHE-5892: Add AlteredFiles test
mmorhun Aug 14, 2017
6f3ea37
CHE-5892: Code cleanup
mmorhun Aug 14, 2017
241dca7
CHE-5892: Add additional check in AlteredFiles constructor
mmorhun Aug 14, 2017
a1eac87
Merge branch 'master' into CHE-5892
mmorhun Aug 14, 2017
18ed447
Merge branch 'master' into CHE-5892
mmorhun Aug 14, 2017
5a6d745
CHE-5892: Fix constraint mistake
mmorhun Aug 14, 2017
e1bb8f4
CHE-5892: Generalize showCompareForCurrentFile in ComparePresenter. B…
mmorhun Aug 15, 2017
c50272a
CHE-5892: Code cleanup
mmorhun Aug 15, 2017
69715a6
CHE-5892: Code cleanup
mmorhun Aug 15, 2017
96fed94
CHE-5892: Add missing new line
mmorhun Aug 16, 2017
436dc59
CHE-5892: Code cleanup
mmorhun Aug 16, 2017
286339c
Apply new code style
mmorhun Aug 22, 2017
e5208f5
Merge master
mmorhun Aug 22, 2017
d121a3d
Fix build
mmorhun Aug 22, 2017
cd6f922
Add ability to align a button left
mmorhun Aug 23, 2017
89ad74e
CHE-5892: Add current diff number in the widget title
mmorhun Aug 23, 2017
65204e0
CHE-5892: Fix formatting
mmorhun Aug 23, 2017
c4c0cdf
Merge branch 'master' into CHE-5892
mmorhun Sep 4, 2017
bea914d
Draft. Move git diff widget from iframe to IDE
mmorhun Sep 6, 2017
21619ad
CHE-5892: Fix build
mmorhun Sep 6, 2017
eaa74c5
Prevent jumping to non-existing diff with hotkeys
mmorhun Sep 6, 2017
2a1147e
CHE-5892: Temporary state. Moving git diff grom iframe to IDE
mmorhun Sep 7, 2017
7195d82
Merge branch 'master' into CHE-5892
mmorhun Sep 7, 2017
e2b5c84
CHE-5892: Move git diff widget from iframe to IDE
mmorhun Sep 7, 2017
0bd2dd9
CHE-5892: code clean up
mmorhun Sep 8, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,15 @@ public interface GitLocalizationConstant extends Messages {
@Key("button.compare")
String buttonCompare();

@Key("button.save_changes")
String buttonSaveChanges();

@Key("button.next_diff")
String buttonNextDiff();

@Key("button.previous_diff")
String buttonPreviousDiff();

@Key("console.tooltip.clear")
String buttonClear();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,16 @@
import org.eclipse.che.ide.api.resources.Project;
import org.eclipse.che.ide.api.resources.Resource;
import org.eclipse.che.ide.ext.git.client.GitLocalizationConstant;
import org.eclipse.che.ide.ext.git.client.compare.ChangedItems;
import org.eclipse.che.ide.ext.git.client.compare.ComparePresenter;
import org.eclipse.che.ide.ext.git.client.compare.FileStatus.Status;
import org.eclipse.che.ide.ext.git.client.compare.changeslist.ChangesListPresenter;
import org.eclipse.che.ide.api.dialogs.DialogFactory;

import java.util.HashMap;
import java.util.Map;

import static com.google.common.base.Preconditions.checkState;
import static java.util.Collections.singletonList;
import static org.eclipse.che.api.git.shared.DiffType.NAME_STATUS;
import static org.eclipse.che.ide.api.notification.StatusNotification.DisplayMode.NOT_EMERGE_MODE;
import static org.eclipse.che.ide.api.notification.StatusNotification.Status.FAIL;
import static org.eclipse.che.ide.ext.git.client.compare.FileStatus.defineStatus;

/**
* Action for comparing with latest repository version
Expand Down Expand Up @@ -91,21 +87,11 @@ public void actionPerformed(ActionEvent e) {
dialogFactory.createMessageDialog(locale.compareMessageIdenticalContentTitle(),
locale.compareMessageIdenticalContentText(), null).show();
} else {
final String[] changedFiles = diff.split("\n");
if (changedFiles.length == 1) {
project.getFile(changedFiles[0].substring(2)).then(file -> {
if (file.isPresent()) {
comparePresenter.showCompareWithLatest(file.get(),
defineStatus(changedFiles[0].substring(0, 1)),
REVISION);
}
});
ChangedItems changedItems = new ChangedItems(project, diff);
if (changedItems.getFilesQuantity() == 1) {
comparePresenter.showCompareWithLatest(changedItems, null, REVISION);
} else {
Map<String, Status> items = new HashMap<>();
for (String item : changedFiles) {
items.put(item.substring(2, item.length()), defineStatus(item.substring(0, 1)));
}
changesListPresenter.show(items, REVISION, null, project);
changesListPresenter.show(changedItems, REVISION, null);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I personally don't like methods which can accept null values.

Copy link
Contributor Author

@mmorhun mmorhun Aug 10, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, I don't like it too, but here I see no problem. It is well documented and mean undefined.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit out of the scope however in general I agree with @tolusha. In this very example I would recommend to avoid public method calls with null values (even well documented). I think it would be nice if you could add a corresponding method so we could call changesListPresenter.show(changedItems, REVISION) and it would internally recall changesListPresenter.show(changedItems, REVISION, null) or something similar to this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good piece of advice, but not for this case, unfortunately...
Otherwise we have to make additional methods with different names (to cover two nullable parameters), which will cause additional logic on the invocations.

}
}
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
import org.eclipse.che.ide.commons.exception.ServerException;
import org.eclipse.che.ide.ext.git.client.DateTimeFormatter;
import org.eclipse.che.ide.ext.git.client.GitLocalizationConstant;
import org.eclipse.che.ide.ext.git.client.compare.FileStatus.Status;
import org.eclipse.che.ide.ext.git.client.compare.ChangedItems;
import org.eclipse.che.ide.ext.git.client.outputconsole.GitOutputConsole;
import org.eclipse.che.ide.ext.git.client.outputconsole.GitOutputConsoleFactory;
import org.eclipse.che.ide.ext.git.client.compare.changespanel.ChangesPanelPresenter;
Expand All @@ -33,13 +33,9 @@

import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import static com.google.common.base.Strings.isNullOrEmpty;
import static com.google.common.collect.Iterables.getFirst;
import static java.util.Arrays.stream;
import static java.util.Collections.singletonList;
Expand All @@ -50,7 +46,6 @@
import static org.eclipse.che.ide.api.notification.StatusNotification.DisplayMode.NOT_EMERGE_MODE;
import static org.eclipse.che.ide.api.notification.StatusNotification.Status.FAIL;
import static org.eclipse.che.ide.api.notification.StatusNotification.Status.SUCCESS;
import static org.eclipse.che.ide.ext.git.client.compare.FileStatus.defineStatus;
import static org.eclipse.che.ide.util.ExceptionUtils.getErrorCode;

/**
Expand All @@ -76,7 +71,7 @@ public class CommitPresenter implements CommitView.ActionDelegate {
private final ProcessesPanelPresenter consolesPanelPresenter;

private Project project;
private Set<String> allFiles;
private List<String> allFiles;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please explain why we're changing a set for a list? We need to store same files several times?

Copy link
Contributor Author

@mmorhun mmorhun Aug 10, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, we needn't, but git returns modified files in some order, so I just do not want to loose it. Also it is needed to navigate through this list.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May be
private AlteredFiles alteredFiles; ?

private List<String> filesToCommit;

@Inject
Expand Down Expand Up @@ -165,26 +160,18 @@ private void showAskForAmendDialog() {
}

private void show(@Nullable String diff) {
Map<String, Status> files = toFileStatusMap(diff);
ChangedItems changedItems = new ChangedItems(project, diff);
filesToCommit.clear();
allFiles = files.keySet();
allFiles = changedItems.getChangedItemsList();

view.setEnableCommitButton(!view.getMessage().isEmpty());
view.focusInMessageField();
view.showDialog();
changesPanelPresenter.show(files);
changesPanelPresenter.show(changedItems);
view.setMarkedCheckBoxes(stream(appContext.getResources()).map(resource -> resource.getLocation().removeFirstSegments(1))
.collect(Collectors.toSet()));
}

private Map<String, Status> toFileStatusMap(@Nullable String diff) {
Map<String, Status> items = new HashMap<>();
if (!isNullOrEmpty(diff)) {
stream(diff.split("\n")).forEach(item -> items.put(item.substring(2, item.length()), defineStatus(item.substring(0, 1))));
}
return items;
}

@Override
public void onCommitClicked() {
Path location = project.getLocation();
Expand Down Expand Up @@ -279,7 +266,7 @@ public void onFileNodeCheckBoxValueChanged(Path path, boolean newCheckBoxValue)
}

@Override
public Set<String> getChangedFiles() {
public List<String> getChangedFiles() {
return allFiles;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ interface ActionDelegate {
void setAmendCommitMessage();

/** Get list of changed files paths. */
Set<String> getChangedFiles();
List<String> getChangedFiles();
}

/** @return entered message */
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*******************************************************************************
* Copyright (c) 2012-2017 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.ide.ext.git.client.compare;

import org.eclipse.che.ide.api.resources.Project;
import org.eclipse.che.ide.ext.git.client.compare.FileStatus.Status;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import static org.eclipse.che.ide.ext.git.client.compare.FileStatus.defineStatus;

/**
* Describes changed files in git comparison process.
*
* @author Mykola Morhun
*/
public class ChangedItems {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ModifiedFiles ?

Copy link
Contributor Author

@mmorhun mmorhun Aug 10, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if it is added or deleted?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dont think that Modified or Changed are good words for this class because such words are present in Git Status. This object can contain not only modified/changed but new or deleted
How about DiffFiles?

Copy link
Contributor Author

@mmorhun mmorhun Aug 10, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think TouchedItems is worse. But still open for discussion.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I understand why do we use term Item here if we're talking exactly about files only according to javadoc? What do you think about something like AlteredFiles? In general I think we can't just name this class ChangedItems as it does not reflect it's nature, personally I would split it into several classes something like ChangedItemParser, ChangedItemHolder and ChangedItem itself, what do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AlteredFiles is good name, think no one will be against it.
As about splitting, I see no point to do this. Constructor just do its own work. Its logic isn't complicated to move into separate class. And according to current representation of diff, storing data into internal object will make it more complicated and add small overhead I think.


private final Project project;
private final LinkedHashMap<String, Status> changedFilesStatuses;
private final List<String> changedFilesList;
private final int length;

/**
* Creates user-friendly representation of git diff.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you mean user-frendly? How does it related to user?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well, programmer friendly)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

realy? 😄

*
* @param project
* the project under diff operation
* @param diff
* plain result of git diff operation
*/
public ChangedItems(Project project, String diff) {
this.project = project;

changedFilesStatuses = new LinkedHashMap<>();
for (String item : diff.split("\n")) {
changedFilesStatuses.put(item.substring(2, item.length()), defineStatus(item.substring(0, 1)));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if diff.isEmpty() then you will have an issue

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sure item.length() > 2
If defineStatus(item.substring(0, 1)) throws IllegalArgumentException then catch it

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To have clear code extract variables for item.substring(2, item.length()) and defineStatus(item.substring(0, 1))

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it will end up with empty diff

}

changedFilesList = new ArrayList<>(changedFilesStatuses.keySet());

length = changedFilesList.size();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Redundant field

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just cached. But ok, I'll get rid of it.

}

public Project getProject() {
return project;
}

/**
* @return number of files in the diff
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer not to use single @return annotation in javadoc, but to have something like: "Returns number of files in the diff"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

*/
public int getFilesQuantity() {
return length;
}

public boolean isEmpty() {
return 0 == length;
}

public Map<String, Status> getChangedItemsMap() {
return changedFilesStatuses;
}

public List<String> getChangedItemsList() {
return changedFilesList;
}

public Status getStatusByPath(String pathToChangedItem) {
return changedFilesStatuses.get(pathToChangedItem);
}

public Status getStatusByIndex(int index) {
return changedFilesStatuses.get(changedFilesList.get(index));
}

public String getItemByIndex(int index) {
return changedFilesList.get(index);
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ChangedItems that = (ChangedItems)o;
return Objects.equals(project, that.project) &&
Objects.equals(changedFilesStatuses, that.changedFilesStatuses) &&
Objects.equals(changedFilesList, that.changedFilesList);
}

@Override
public int hashCode() {
return Objects.hash(project, changedFilesStatuses, changedFilesList);
}

}
Loading