Merge pull request #5621 from nextcloud/fix-sorting-of-favorite-files-in-file-list

Fix sorting of favorite files in file list
pull/5643/head
Morris Jobke 2017-07-05 17:31:41 +07:00 committed by GitHub
commit ca565644b3
6 changed files with 227 additions and 15 deletions

@ -1566,11 +1566,16 @@
this._sort = sort;
this._sortDirection = (direction === 'desc')?'desc':'asc';
this._sortComparator = function(fileInfo1, fileInfo2) {
if(fileInfo1.isFavorite && !fileInfo2.isFavorite) {
var isFavorite = function(fileInfo) {
return fileInfo.tags && fileInfo.tags.indexOf(OC.TAG_FAVORITE) >= 0;
};
if (isFavorite(fileInfo1) && !isFavorite(fileInfo2)) {
return -1;
} else if(!fileInfo1.isFavorite && fileInfo2.isFavorite) {
} else if (!isFavorite(fileInfo1) && isFavorite(fileInfo2)) {
return 1;
}
return direction === 'asc' ? comparator(fileInfo1, fileInfo2) : -comparator(fileInfo1, fileInfo2);
};

@ -2476,6 +2476,120 @@ describe('OCA.Files.FileList tests', function() {
sortStub.restore();
});
describe('with favorites', function() {
it('shows favorite files on top', function() {
testFiles.push(new FileInfo({
id: 5,
type: 'file',
name: 'ZZY Before last file in ascending order',
mimetype: 'text/plain',
mtime: 999999998,
size: 9999998,
// Tags would be added by TagsPlugin
tags: [OC.TAG_FAVORITE],
}), new FileInfo({
id: 6,
type: 'file',
name: 'ZZZ Last file in ascending order',
mimetype: 'text/plain',
mtime: 999999999,
size: 9999999,
// Tags would be added by TagsPlugin
tags: [OC.TAG_FAVORITE],
}));
fileList.setFiles(testFiles);
// Sort by name in ascending order (default sorting is by name
// in ascending order, but setFiles does not trigger a sort, so
// the files must be sorted before being set or a sort must be
// triggered afterwards by clicking on the header).
fileList.$el.find('.column-name .columntitle').click();
fileList.$el.find('.column-name .columntitle').click();
expect(fileList.findFileEl('ZZY Before last file in ascending order').index()).toEqual(0);
expect(fileList.findFileEl('ZZZ Last file in ascending order').index()).toEqual(1);
expect(fileList.findFileEl('somedir').index()).toEqual(2);
expect(fileList.findFileEl('One.txt').index()).toEqual(3);
expect(fileList.findFileEl('Three.pdf').index()).toEqual(4);
expect(fileList.findFileEl('Two.jpg').index()).toEqual(5);
// Sort by size in ascending order
fileList.$el.find('.column-size .columntitle').click();
fileList.$el.find('.column-size .columntitle').click();
expect(fileList.findFileEl('ZZY Before last file in ascending order').index()).toEqual(0);
expect(fileList.findFileEl('ZZZ Last file in ascending order').index()).toEqual(1);
expect(fileList.findFileEl('One.txt').index()).toEqual(2);
expect(fileList.findFileEl('somedir').index()).toEqual(3);
expect(fileList.findFileEl('Two.jpg').index()).toEqual(4);
expect(fileList.findFileEl('Three.pdf').index()).toEqual(5);
// Sort by modification time in ascending order
fileList.$el.find('.column-mtime .columntitle').click();
fileList.$el.find('.column-mtime .columntitle').click();
expect(fileList.findFileEl('ZZY Before last file in ascending order').index()).toEqual(0);
expect(fileList.findFileEl('ZZZ Last file in ascending order').index()).toEqual(1);
expect(fileList.findFileEl('One.txt').index()).toEqual(2);
expect(fileList.findFileEl('somedir').index()).toEqual(3);
expect(fileList.findFileEl('Three.pdf').index()).toEqual(4);
expect(fileList.findFileEl('Two.jpg').index()).toEqual(5);
});
it('shows favorite files on top also when using descending order', function() {
testFiles.push(new FileInfo({
id: 5,
type: 'file',
name: 'AAB Before last file in descending order',
mimetype: 'text/plain',
mtime: 2,
size: 2,
// Tags would be added by TagsPlugin
tags: [OC.TAG_FAVORITE],
}), new FileInfo({
id: 6,
type: 'file',
name: 'AAA Last file in descending order',
mimetype: 'text/plain',
mtime: 1,
size: 1,
// Tags would be added by TagsPlugin
tags: [OC.TAG_FAVORITE],
}));
fileList.setFiles(testFiles);
// Sort by name in descending order
fileList.$el.find('.column-name .columntitle').click();
expect(fileList.findFileEl('AAB Before last file in descending order').index()).toEqual(0);
expect(fileList.findFileEl('AAA Last file in descending order').index()).toEqual(1);
expect(fileList.findFileEl('Two.jpg').index()).toEqual(2);
expect(fileList.findFileEl('Three.pdf').index()).toEqual(3);
expect(fileList.findFileEl('One.txt').index()).toEqual(4);
expect(fileList.findFileEl('somedir').index()).toEqual(5);
// Sort by size in descending order
fileList.$el.find('.column-size .columntitle').click();
expect(fileList.findFileEl('AAB Before last file in descending order').index()).toEqual(0);
expect(fileList.findFileEl('AAA Last file in descending order').index()).toEqual(1);
expect(fileList.findFileEl('Three.pdf').index()).toEqual(2);
expect(fileList.findFileEl('Two.jpg').index()).toEqual(3);
expect(fileList.findFileEl('somedir').index()).toEqual(4);
expect(fileList.findFileEl('One.txt').index()).toEqual(5);
// Sort by modification time in descending order
fileList.$el.find('.column-mtime .columntitle').click();
expect(fileList.findFileEl('AAB Before last file in descending order').index()).toEqual(0);
expect(fileList.findFileEl('AAA Last file in descending order').index()).toEqual(1);
expect(fileList.findFileEl('Two.jpg').index()).toEqual(2);
expect(fileList.findFileEl('Three.pdf').index()).toEqual(3);
expect(fileList.findFileEl('somedir').index()).toEqual(4);
expect(fileList.findFileEl('One.txt').index()).toEqual(5);
});
});
});
describe('create file', function() {
var deferredCreate;

@ -304,13 +304,6 @@
data.hasPreview = true;
}
var isFavorite = props['{' + Client.NS_OWNCLOUD + '}favorite'];
if (!_.isUndefined(isFavorite)) {
data.isFavorite = isFavorite === '1';
} else {
data.isFavorite = false;
}
var contentType = props[Client.PROPERTY_GETCONTENTTYPE];
if (!_.isUndefined(contentType)) {
data.mimetype = contentType;

@ -132,12 +132,7 @@
/**
* @type boolean
*/
hasPreview: true,
/**
* @type boolean
*/
isFavorite: false
hasPreview: true
};
if (!OC.Files) {

@ -68,3 +68,22 @@ Feature: app-files
And I see that the "Sharing" tab in the details view is eventually loaded
When I open the input field for tags in the details view
Then I see that the input field for tags in the details view is shown
Scenario: marking a file as favorite causes the file list to be sorted again
Given I am logged in
And I create a new folder named "A name alphabetically lower than welcome.txt"
And I see that "A name alphabetically lower than welcome.txt" precedes "welcome.txt" in the file list
When I mark "welcome.txt" as favorite
Then I see that "welcome.txt" is marked as favorite
And I see that "welcome.txt" precedes "A name alphabetically lower than welcome.txt" in the file list
Scenario: unmarking a file as favorite causes the file list to be sorted again
Given I am logged in
And I create a new folder named "A name alphabetically lower than welcome.txt"
And I see that "A name alphabetically lower than welcome.txt" precedes "welcome.txt" in the file list
And I mark "welcome.txt" as favorite
And I see that "welcome.txt" is marked as favorite
And I see that "welcome.txt" precedes "A name alphabetically lower than welcome.txt" in the file list
When I unmark "welcome.txt" as favorite
Then I see that "welcome.txt" is not marked as favorite
And I see that "A name alphabetically lower than welcome.txt" precedes "welcome.txt" in the file list

@ -213,6 +213,40 @@ class FilesAppContext implements Context, ActorAwareInterface {
describedAs("Password protect working icon in the details view in Files app");
}
/**
* @return Locator
*/
public static function createMenuButton() {
return Locator::forThe()->css("#controls .button.new")->
descendantOf(self::currentSectionMainView())->
describedAs("Create menu button in Files app");
}
/**
* @return Locator
*/
public static function createNewFolderMenuItem() {
return self::createMenuItemFor("New folder");
}
/**
* @return Locator
*/
public static function createNewFolderMenuItemNameInput() {
return Locator::forThe()->css(".filenameform input")->
descendantOf(self::createNewFolderMenuItem())->
describedAs("Name input in create new folder menu item in Files app");
}
/**
* @return Locator
*/
private static function createMenuItemFor($newType) {
return Locator::forThe()->xpath("//div[contains(concat(' ', normalize-space(@class), ' '), ' newFileMenu ')]//span[normalize-space() = '$newType']/ancestor::li")->
descendantOf(self::currentSectionMainView())->
describedAs("Create $newType menu item in Files app");
}
/**
* @return Locator
*/
@ -222,6 +256,15 @@ class FilesAppContext implements Context, ActorAwareInterface {
describedAs("Row for file $fileName in Files app");
}
/**
* @return Locator
*/
public static function rowForFilePreceding($fileName1, $fileName2) {
return Locator::forThe()->xpath("//preceding-sibling::tr//span[contains(concat(' ', normalize-space(@class), ' '), ' nametext ') and normalize-space() = '$fileName1']/ancestor::tr")->
descendantOf(self::rowForFile($fileName2))->
describedAs("Row for file $fileName1 preceding $fileName2 in Files app");
}
/**
* @return Locator
*/
@ -230,6 +273,14 @@ class FilesAppContext implements Context, ActorAwareInterface {
describedAs("Favorite action for file $fileName in Files app");
}
/**
* @return Locator
*/
public static function notFavoritedStateIconForFile($fileName) {
return Locator::forThe()->css(".icon-star")->descendantOf(self::favoriteActionForFile($fileName))->
describedAs("Not favorited state icon for file $fileName in Files app");
}
/**
* @return Locator
*/
@ -293,6 +344,16 @@ class FilesAppContext implements Context, ActorAwareInterface {
describedAs($itemText . " item in file actions menu in Files app");
}
/**
* @Given I create a new folder named :folderName
*/
public function iCreateANewFolderNamed($folderName) {
$this->actor->find(self::createMenuButton(), 10)->click();
$this->actor->find(self::createNewFolderMenuItem(), 2)->click();
$this->actor->find(self::createNewFolderMenuItemNameInput(), 2)->setValue($folderName . "\r");
}
/**
* @Given I open the :section section
*/
@ -327,6 +388,17 @@ class FilesAppContext implements Context, ActorAwareInterface {
* @Given I mark :fileName as favorite
*/
public function iMarkAsFavorite($fileName) {
$this->iSeeThatIsNotMarkedAsFavorite($fileName);
$this->actor->find(self::favoriteActionForFile($fileName), 10)->click();
}
/**
* @Given I unmark :fileName as favorite
*/
public function iUnmarkAsFavorite($fileName) {
$this->iSeeThatIsMarkedAsFavorite($fileName);
$this->actor->find(self::favoriteActionForFile($fileName), 10)->click();
}
@ -413,6 +485,13 @@ class FilesAppContext implements Context, ActorAwareInterface {
}
}
/**
* @Then I see that :fileName1 precedes :fileName2 in the file list
*/
public function iSeeThatPrecedesInTheFileList($fileName1, $fileName2) {
PHPUnit_Framework_Assert::assertNotNull($this->actor->find(self::rowForFilePreceding($fileName1, $fileName2), 10));
}
/**
* @Then I see that :fileName is marked as favorite
*/
@ -420,6 +499,13 @@ class FilesAppContext implements Context, ActorAwareInterface {
PHPUnit_Framework_Assert::assertNotNull($this->actor->find(self::favoritedStateIconForFile($fileName), 10));
}
/**
* @Then I see that :fileName is not marked as favorite
*/
public function iSeeThatIsNotMarkedAsFavorite($fileName) {
PHPUnit_Framework_Assert::assertNotNull($this->actor->find(self::notFavoritedStateIconForFile($fileName), 10));
}
/**
* @Then I see that the input field for tags in the details view is shown
*/