Commit 867c55d7 authored by Stuart Langley's avatar Stuart Langley Committed by Commit Bot

Add a directory entry for "Computers" in the directory tree.

Add support for /drive/Computers in volume_info and directory_tree,
for displaying a users backed up Computers, if they have any. The
logic here is very similar to the logic for team drives, where we will
only display the '/Computers' entry if there is a sub-directory under
it. Hence a lot of the code is cargo culted from the team drives
implementation.

Potentially come back and refactor the common code between Computers
and Team Drives once this stabilizes.

Bug: 884020
Change-Id: I1ebf52ba64e5cb5bd809b64cc52bf182e3d11f19
Reviewed-on: https://chromium-review.googlesource.com/c/1255084
Commit-Queue: Stuart Langley <slangley@chromium.org>
Reviewed-by: default avatarBrian White <bcwhite@chromium.org>
Reviewed-by: default avatarNoel Gordon <noel@chromium.org>
Reviewed-by: default avatarLuciano Pacheco <lucmult@chromium.org>
Cr-Commit-Position: refs/heads/master@{#600650}
parent 27df0590
...@@ -47,6 +47,9 @@ ...@@ -47,6 +47,9 @@
<message name="IDS_FILE_BROWSER_DRIVE_TEAM_DRIVES_LABEL" desc="A label for the 'Team Drives' collection of Google Drive."> <message name="IDS_FILE_BROWSER_DRIVE_TEAM_DRIVES_LABEL" desc="A label for the 'Team Drives' collection of Google Drive.">
Team Drives Team Drives
</message> </message>
<message name="IDS_FILE_BROWSER_DRIVE_COMPUTERS_LABEL" desc="A label for the 'Computers' collection of Google Drive.">
Computers
</message>
<message name="IDS_FILE_BROWSER_DRIVE_SHARED_WITH_ME_COLLECTION_LABEL" desc="A label for the 'shared with me' collection of Google Drive."> <message name="IDS_FILE_BROWSER_DRIVE_SHARED_WITH_ME_COLLECTION_LABEL" desc="A label for the 'shared with me' collection of Google Drive.">
Shared with me Shared with me
</message> </message>
......
5bab14e41979f9abcb3430747ff722cbee84b069
\ No newline at end of file
...@@ -131,6 +131,7 @@ void AddStringsForDrive(base::DictionaryValue* dict) { ...@@ -131,6 +131,7 @@ void AddStringsForDrive(base::DictionaryValue* dict) {
SET_STRING("DRIVE_MY_DRIVE_LABEL", IDS_FILE_BROWSER_DRIVE_MY_DRIVE_LABEL); SET_STRING("DRIVE_MY_DRIVE_LABEL", IDS_FILE_BROWSER_DRIVE_MY_DRIVE_LABEL);
SET_STRING("DRIVE_TEAM_DRIVES_LABEL", SET_STRING("DRIVE_TEAM_DRIVES_LABEL",
IDS_FILE_BROWSER_DRIVE_TEAM_DRIVES_LABEL); IDS_FILE_BROWSER_DRIVE_TEAM_DRIVES_LABEL);
SET_STRING("DRIVE_COMPUTERS_LABEL", IDS_FILE_BROWSER_DRIVE_COMPUTERS_LABEL);
SET_STRING("DRIVE_NOT_REACHED", IDS_FILE_BROWSER_DRIVE_NOT_REACHED); SET_STRING("DRIVE_NOT_REACHED", IDS_FILE_BROWSER_DRIVE_NOT_REACHED);
SET_STRING("DRIVE_OFFLINE_COLLECTION_LABEL", SET_STRING("DRIVE_OFFLINE_COLLECTION_LABEL",
IDS_FILE_BROWSER_DRIVE_OFFLINE_COLLECTION_LABEL); IDS_FILE_BROWSER_DRIVE_OFFLINE_COLLECTION_LABEL);
......
...@@ -33126,6 +33126,18 @@ uploading your change for review. ...@@ -33126,6 +33126,18 @@ uploading your change for review.
</summary> </summary>
</histogram> </histogram>
<histogram name="FileBrowser.ComputersCount" units="Computers"
expires_after="M76">
<owner>slangley@chromium.org</owner>
<owner>weifangsun@chromium.org</owner>
<summary>
Chrome OS File Browser: number of Computers a user has available in the
Files app. Computed every time the File Browser is opened (including file
picker dialogs). NOTE: This data is biased towards users that use the Files
App more often.
</summary>
</histogram>
<histogram name="FileBrowser.Create" enum="FileDialogType"> <histogram name="FileBrowser.Create" enum="FileDialogType">
<owner>sashab@chromium.org</owner> <owner>sashab@chromium.org</owner>
<owner>slangley@chromium.org</owner> <owner>slangley@chromium.org</owner>
...@@ -31,6 +31,13 @@ VolumeInfo.prototype.displayRoot; ...@@ -31,6 +31,13 @@ VolumeInfo.prototype.displayRoot;
*/ */
VolumeInfo.prototype.teamDriveDisplayRoot; VolumeInfo.prototype.teamDriveDisplayRoot;
/**
* The display root path of Computers directory. It is null before finishing
* to resolve the entry. Valid only for Drive volume.
* @type {DirectoryEntry}
*/
VolumeInfo.prototype.computersDisplayRoot;
/** /**
* The volume's fake entries such as Recent, Offline, Shared with me, etc... * The volume's fake entries such as Recent, Offline, Shared with me, etc...
* in Google Drive. * in Google Drive.
......
...@@ -37,7 +37,9 @@ function EntryLocationImpl(volumeInfo, rootType, isRootEntry, isReadOnly) { ...@@ -37,7 +37,9 @@ function EntryLocationImpl(volumeInfo, rootType, isRootEntry, isReadOnly) {
this.rootType === VolumeManagerCommon.RootType.DRIVE_RECENT || this.rootType === VolumeManagerCommon.RootType.DRIVE_RECENT ||
this.rootType === VolumeManagerCommon.RootType.DRIVE_OFFLINE || this.rootType === VolumeManagerCommon.RootType.DRIVE_OFFLINE ||
this.rootType === VolumeManagerCommon.RootType.TEAM_DRIVES_GRAND_ROOT || this.rootType === VolumeManagerCommon.RootType.TEAM_DRIVES_GRAND_ROOT ||
this.rootType === VolumeManagerCommon.RootType.TEAM_DRIVE; this.rootType === VolumeManagerCommon.RootType.TEAM_DRIVE ||
this.rootType === VolumeManagerCommon.RootType.COMPUTERS_GRAND_ROOT ||
this.rootType === VolumeManagerCommon.RootType.COMPUTER;
/** @override */ /** @override */
this.isReadOnly = isReadOnly; this.isReadOnly = isReadOnly;
......
...@@ -47,6 +47,7 @@ function VolumeInfoImpl( ...@@ -47,6 +47,7 @@ function VolumeInfoImpl(
this.label_ = label; this.label_ = label;
this.displayRoot_ = null; this.displayRoot_ = null;
this.teamDriveDisplayRoot_ = null; this.teamDriveDisplayRoot_ = null;
this.computersDisplayRoot_ = null;
/** /**
* @type {FilesAppEntry} an entry to be used as prefix of this volume on * @type {FilesAppEntry} an entry to be used as prefix of this volume on
...@@ -125,6 +126,14 @@ VolumeInfoImpl.prototype = /** @struct */ { ...@@ -125,6 +126,14 @@ VolumeInfoImpl.prototype = /** @struct */ {
get teamDriveDisplayRoot() { get teamDriveDisplayRoot() {
return this.teamDriveDisplayRoot_; return this.teamDriveDisplayRoot_;
}, },
/**
* @return {DirectoryEntry} The display root path of Computers directory.
* It is null before finishing to resolve the entry. Valid only for Drive
* volume.
*/
get computersDisplayRoot() {
return this.computersDisplayRoot_;
},
/** /**
* @return {Object<!FakeEntry>} Fake entries. * @return {Object<!FakeEntry>} Fake entries.
*/ */
...@@ -259,6 +268,31 @@ VolumeInfoImpl.prototype.resolveTeamDrivesRoot_ = function() { ...@@ -259,6 +268,31 @@ VolumeInfoImpl.prototype.resolveTeamDrivesRoot_ = function() {
}); });
}; };
/**
* Sets |computersDisplayRoot_| if Computers are enabled.
*
* If Computers are not enabled, resolveFileSystemUrl_ will return a
* 'NotFoundError' which will be caught here. Any other errors will be rethrown.
*
* The return value will resolve once this operation is complete.
* @return {!Promise<void>}
*/
VolumeInfoImpl.prototype.resolveComputersRoot_ = function() {
return VolumeInfoImpl
.resolveFileSystemUrl_(
this.fileSystem_.root.toURL() +
VolumeManagerCommon.COMPUTERS_DIRECTORY_NAME)
.then(
(computersRoot) => {
this.computersDisplayRoot_ = computersRoot;
},
(error) => {
if (error.name != 'NotFoundError') {
throw error;
}
});
};
/** /**
* @override * @override
*/ */
...@@ -281,7 +315,8 @@ VolumeInfoImpl.prototype.resolveDisplayRoot = function(opt_onSuccess, ...@@ -281,7 +315,8 @@ VolumeInfoImpl.prototype.resolveDisplayRoot = function(opt_onSuccess,
Promise Promise
.all([ .all([
VolumeInfoImpl.resolveFileSystemUrl_(displayRootURL), VolumeInfoImpl.resolveFileSystemUrl_(displayRootURL),
this.resolveTeamDrivesRoot_() this.resolveTeamDrivesRoot_(),
this.resolveComputersRoot_(),
]) ])
.then(([root]) => { .then(([root]) => {
return root; return root;
......
...@@ -1148,6 +1148,9 @@ util.getRootTypeLabel = function(locationInfo) { ...@@ -1148,6 +1148,9 @@ util.getRootTypeLabel = function(locationInfo) {
// By this reason, we return the label of the Team Drives grand root here. // By this reason, we return the label of the Team Drives grand root here.
case VolumeManagerCommon.RootType.TEAM_DRIVES_GRAND_ROOT: case VolumeManagerCommon.RootType.TEAM_DRIVES_GRAND_ROOT:
return str('DRIVE_TEAM_DRIVES_LABEL'); return str('DRIVE_TEAM_DRIVES_LABEL');
case VolumeManagerCommon.RootType.COMPUTER:
case VolumeManagerCommon.RootType.COMPUTERS_GRAND_ROOT:
return str('DRIVE_COMPUTERS_LABEL');
case VolumeManagerCommon.RootType.DRIVE_OFFLINE: case VolumeManagerCommon.RootType.DRIVE_OFFLINE:
return str('DRIVE_OFFLINE_COLLECTION_LABEL'); return str('DRIVE_OFFLINE_COLLECTION_LABEL');
case VolumeManagerCommon.RootType.DRIVE_SHARED_WITH_ME: case VolumeManagerCommon.RootType.DRIVE_SHARED_WITH_ME:
......
...@@ -41,6 +41,9 @@ DirectoryItemTreeBaseMethods.getItemByEntry = function(entry) { ...@@ -41,6 +41,9 @@ DirectoryItemTreeBaseMethods.getItemByEntry = function(entry) {
if (util.isTeamDriveEntry(entry) && item instanceof DriveVolumeItem) if (util.isTeamDriveEntry(entry) && item instanceof DriveVolumeItem)
return item.getItemByEntry(entry); return item.getItemByEntry(entry);
if (util.isComputersEntry(entry) && item instanceof DriveVolumeItem)
return item.getItemByEntry(entry);
if (util.isDescendantEntry(item.entry, entry)) if (util.isDescendantEntry(item.entry, entry))
return item.getItemByEntry(entry); return item.getItemByEntry(entry);
} }
...@@ -70,6 +73,11 @@ DirectoryItemTreeBaseMethods.searchAndSelectByEntry = function(entry) { ...@@ -70,6 +73,11 @@ DirectoryItemTreeBaseMethods.searchAndSelectByEntry = function(entry) {
return true; return true;
} }
if (util.isComputersEntry(entry) && item instanceof DriveVolumeItem) {
item.selectByEntry(entry);
return true;
}
if (util.isDescendantEntry(item.entry, entry) || if (util.isDescendantEntry(item.entry, entry) ||
util.isSameEntry(item.entry, entry)) { util.isSameEntry(item.entry, entry)) {
item.selectByEntry(entry); item.selectByEntry(entry);
...@@ -222,6 +230,9 @@ DirectoryItem.prototype = { ...@@ -222,6 +230,9 @@ DirectoryItem.prototype = {
locationInfo.rootType === locationInfo.rootType ===
VolumeManagerCommon.RootType.TEAM_DRIVES_GRAND_ROOT || VolumeManagerCommon.RootType.TEAM_DRIVES_GRAND_ROOT ||
locationInfo.rootType === VolumeManagerCommon.RootType.TEAM_DRIVE || locationInfo.rootType === VolumeManagerCommon.RootType.TEAM_DRIVE ||
locationInfo.rootType ===
VolumeManagerCommon.RootType.COMPUTERS_GRAND_ROOT ||
locationInfo.rootType === VolumeManagerCommon.RootType.COMPUTER ||
locationInfo.rootType === VolumeManagerCommon.RootType.DRIVE_OFFLINE || locationInfo.rootType === VolumeManagerCommon.RootType.DRIVE_OFFLINE ||
locationInfo.rootType === locationInfo.rootType ===
VolumeManagerCommon.RootType.DRIVE_SHARED_WITH_ME || VolumeManagerCommon.RootType.DRIVE_SHARED_WITH_ME ||
...@@ -1043,7 +1054,7 @@ DriveVolumeItem.prototype.handleClick = function(e) { ...@@ -1043,7 +1054,7 @@ DriveVolumeItem.prototype.handleClick = function(e) {
* Since we don't currently support any functionality with just the grand root * Since we don't currently support any functionality with just the grand root
* (e.g. you can't create a new team drive from the root yet), remove/don't * (e.g. you can't create a new team drive from the root yet), remove/don't
* create the grand root so it can't be reached via keyboard. * create the grand root so it can't be reached via keyboard.
* If there is at least one Team Drive, add/show the Team Drives trand root. * If there is at least one Team Drive, add/show the Team Drives grand root.
* *
* @return {!Promise<SubDirectoryItem>} Resolved with Team Drive Grand Root * @return {!Promise<SubDirectoryItem>} Resolved with Team Drive Grand Root
* SubDirectoryItem instance, or undefined when it shouldn't exist. * SubDirectoryItem instance, or undefined when it shouldn't exist.
...@@ -1072,7 +1083,7 @@ DriveVolumeItem.prototype.createTeamDrivesGrandRoot_ = function() { ...@@ -1072,7 +1083,7 @@ DriveVolumeItem.prototype.createTeamDrivesGrandRoot_ = function() {
metrics.recordSmallCount('TeamDrivesCount', results.length); metrics.recordSmallCount('TeamDrivesCount', results.length);
// Only create grand root if there is at least 1 child/result. // Only create grand root if there is at least 1 child/result.
if (results.length) { if (results.length) {
if (index) { if (index !== undefined) {
this.items[index].hidden = false; this.items[index].hidden = false;
resolve(this.items[index]); resolve(this.items[index]);
return; return;
...@@ -1102,6 +1113,76 @@ DriveVolumeItem.prototype.createTeamDrivesGrandRoot_ = function() { ...@@ -1102,6 +1113,76 @@ DriveVolumeItem.prototype.createTeamDrivesGrandRoot_ = function() {
}); });
}; };
/**
* Creates Computers root if there is any computer. If there is no computer,
* then it removes the root.
*
* Since we don't currently support any functionality with just the grand root
* (e.g. you can't create a new computer from the root yet), remove/don't
* create the grand root so it can't be reached via keyboard.
* If there is at least one Computer, add/show the Computer grand root.
*
* @return {!Promise<SubDirectoryItem>} Resolved with Computer Grand Root
* SubDirectoryItem instance, or undefined when it shouldn't exist.
* @private
*/
DriveVolumeItem.prototype.createComputersGrandRoot_ = function() {
return new Promise(resolve => {
const computerGrandRoot = this.volumeInfo_.computersDisplayRoot;
if (!computerGrandRoot) {
// Computer is disabled.
resolve();
return;
}
let index;
for (let i = 0; i < this.items.length; i++) {
const entry = this.items[i] && this.items[i].entry;
if (entry && util.isSameEntry(entry, computerGrandRoot)) {
index = i;
break;
}
}
const reader = computerGrandRoot.createReader();
reader.readEntries((results) => {
metrics.recordSmallCount('ComputersCount', results.length);
// Only create grand root if there is at least 1 child/result.
if (results.length) {
if (index !== undefined) {
this.items[index].hidden = false;
resolve(this.items[index]);
return;
}
// Create if it doesn't exist yet.
const label = util.getEntryLabel(
this.parentTree_.volumeManager_.getLocationInfo(
computerGrandRoot),
computerGrandRoot) ||
'';
const item = new SubDirectoryItem(
label, computerGrandRoot, this, this.parentTree_);
// We want to show "Computers" after "Team Drives", the
// computersIndexPosition_() helper function will work out the correct
// index to place "Computers" at.
const position = this.computersIndexPosition_();
this.addAt(item, position);
item.updateSubDirectories(false);
resolve(item);
return;
} else {
// When there is no computer, the grand root should be removed.
if (index && this.items[index].parentItem) {
this.items[index].parentItem.remove(this.items[index]);
}
resolve();
return;
}
});
});
};
/** /**
* Retrieves the latest subdirectories and update them on the tree. * Retrieves the latest subdirectories and update them on the tree.
* @param {boolean} recursive True if the update is recursively. * @param {boolean} recursive True if the update is recursively.
...@@ -1118,6 +1199,11 @@ DriveVolumeItem.prototype.updateSubDirectories = function(recursive) { ...@@ -1118,6 +1199,11 @@ DriveVolumeItem.prototype.updateSubDirectories = function(recursive) {
entries.push(teamDrivesDisplayRoot); entries.push(teamDrivesDisplayRoot);
} }
var computersDisplayRoot = this.volumeInfo_.computersDisplayRoot;
if (!!computersDisplayRoot) {
entries.push(computersDisplayRoot);
}
// Drive volume has children including fake entries (offline, recent, ...) // Drive volume has children including fake entries (offline, recent, ...)
var fakeEntries = []; var fakeEntries = [];
if (this.parentTree_.fakeEntriesVisible_) { if (this.parentTree_.fakeEntriesVisible_) {
...@@ -1137,6 +1223,8 @@ DriveVolumeItem.prototype.updateSubDirectories = function(recursive) { ...@@ -1137,6 +1223,8 @@ DriveVolumeItem.prototype.updateSubDirectories = function(recursive) {
const entry = entries[i]; const entry = entries[i];
if (entry === teamDrivesDisplayRoot) { if (entry === teamDrivesDisplayRoot) {
this.createTeamDrivesGrandRoot_(); this.createTeamDrivesGrandRoot_();
} else if (entry === computersDisplayRoot) {
this.createComputersGrandRoot_();
} else { } else {
const label = const label =
util.getEntryLabel( util.getEntryLabel(
...@@ -1162,21 +1250,30 @@ DriveVolumeItem.prototype.updateSubDirectories = function(recursive) { ...@@ -1162,21 +1250,30 @@ DriveVolumeItem.prototype.updateSubDirectories = function(recursive) {
* @override * @override
*/ */
DriveVolumeItem.prototype.updateItemByEntry = function(changedDirectoryEntry) { DriveVolumeItem.prototype.updateItemByEntry = function(changedDirectoryEntry) {
// The first item is My Drive, and the second item is Team Drives.
// Keep in sync with |fixedEntries| in |updateSubDirectories|.
const isTeamDriveChild = util.isTeamDriveEntry(changedDirectoryEntry); const isTeamDriveChild = util.isTeamDriveEntry(changedDirectoryEntry);
const index = isTeamDriveChild ? 1 : 0;
// If Team Drive grand root has been removed and we receive an update for an // If Team Drive grand root has been removed and we receive an update for an
// team drive, we need to create the Team Drive grand root. // team drive, we need to create the Team Drive grand root.
if (isTeamDriveChild) { if (isTeamDriveChild) {
this.createTeamDrivesGrandRoot_().then(teamDriveGranRootItem => { this.createTeamDrivesGrandRoot_().then(teamDriveGrandRootItem => {
if (teamDriveGranRootItem) if (teamDriveGrandRootItem)
this.items[index].updateItemByEntry(changedDirectoryEntry); teamDriveGrandRootItem.updateItemByEntry(changedDirectoryEntry);
}); });
} else { return;
this.items[index].updateItemByEntry(changedDirectoryEntry); }
const isComputersChild = util.isComputersEntry(changedDirectoryEntry);
// If Computers grand root has been removed and we receive an update for an
// computer, we need to create the Computers grand root.
if (isComputersChild) {
this.createComputersGrandRoot_().then(computersGrandRootItem => {
if (computersGrandRootItem)
computersGrandRootItem.updateItemByEntry(changedDirectoryEntry);
});
return;
} }
// Must be under "My Drive", which is always the first item.
this.items[0].updateItemByEntry(changedDirectoryEntry);
}; };
/** /**
...@@ -1190,6 +1287,27 @@ DriveVolumeItem.prototype.selectByEntry = function(entry) { ...@@ -1190,6 +1287,27 @@ DriveVolumeItem.prototype.selectByEntry = function(entry) {
this.searchAndSelectByEntry(entry); this.searchAndSelectByEntry(entry);
}; };
/**
* Return the index where we want to display the "Computers" root.
* @private
*/
DriveVolumeItem.prototype.computersIndexPosition_ = function() {
// We want the order to be
// - My Drive
// - Team Drives (if the user has any)
// - Computers (if the user has any)
// So if the user has team drives we want index position 2, otherwise index
// position 1.
for (let i = 0; i < this.items.length; i++) {
const item = this.items[i];
if (!item.entry)
continue;
if (util.isTeamDriveEntry(item.entry))
return 2;
}
return 1;
};
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// ShortcutItem // ShortcutItem
......
...@@ -16,6 +16,7 @@ loadTimeData.data = { ...@@ -16,6 +16,7 @@ loadTimeData.data = {
DRIVE_DIRECTORY_LABEL: 'Google Drive', DRIVE_DIRECTORY_LABEL: 'Google Drive',
DRIVE_MY_DRIVE_LABEL: 'My Drive', DRIVE_MY_DRIVE_LABEL: 'My Drive',
DRIVE_TEAM_DRIVES_LABEL: 'Team Drives', DRIVE_TEAM_DRIVES_LABEL: 'Team Drives',
DRIVE_COMPUTERS_LABEL: 'Computers',
DRIVE_OFFLINE_COLLECTION_LABEL: 'Offline', DRIVE_OFFLINE_COLLECTION_LABEL: 'Offline',
DRIVE_SHARED_WITH_ME_COLLECTION_LABEL: 'Shared with me', DRIVE_SHARED_WITH_ME_COLLECTION_LABEL: 'Shared with me',
REMOVABLE_DIRECTORY_LABEL: 'External Storage', REMOVABLE_DIRECTORY_LABEL: 'External Storage',
...@@ -78,7 +79,7 @@ function getDirectoryTreeItemLabelsAsAList(directoryTree) { ...@@ -78,7 +79,7 @@ function getDirectoryTreeItemLabelsAsAList(directoryTree) {
/** /**
* Test case for typical creation of directory tree. * Test case for typical creation of directory tree.
* This test expect that the following tree is built. * This test expects that the following tree is built.
* *
* Google Drive * Google Drive
* - My Drive * - My Drive
...@@ -138,7 +139,7 @@ function testCreateDirectoryTree(callback) { ...@@ -138,7 +139,7 @@ function testCreateDirectoryTree(callback) {
/** /**
* Test case for creating tree with Team Drives. * Test case for creating tree with Team Drives.
* This test expect that the following tree is built. * This test expects that the following tree is built.
* *
* Google Drive * Google Drive
* - My Drive * - My Drive
...@@ -262,6 +263,211 @@ function testCreateDirectoryTreeWithEmptyTeamDrive(callback) { ...@@ -262,6 +263,211 @@ function testCreateDirectoryTreeWithEmptyTeamDrive(callback) {
callback); callback);
} }
/**
* Test case for creating tree with Computers.
* This test expects that the following tree is built.
*
* Google Drive
* - My Drive
* - Computers (only if there is a child computer).
* - Shared with me
* - Offline
* Downloads
*
* @param {!function(boolean)} callback A callback function which is called with
* test result.
*/
function testCreateDirectoryTreeWithComputers(callback) {
// Create elements.
let parentElement = document.createElement('div');
let directoryTree = document.createElement('div');
directoryTree.metadataModel = mockMetadataModel();
parentElement.appendChild(directoryTree);
// Create mocks.
let directoryModel = new MockDirectoryModel();
let volumeManager = new MockVolumeManager();
const fileOperationManager = {addEventListener: function(name, callback) {}};
// Set entry which is returned by
// window.webkitResolveLocalFileSystemURLResults.
const driveFileSystem = volumeManager.volumeInfoList.item(0).fileSystem;
window.webkitResolveLocalFileSystemURLEntries['filesystem:drive/root'] =
new MockDirectoryEntry(driveFileSystem, '/root');
window.webkitResolveLocalFileSystemURLEntries['filesystem:drive/Computers'] =
new MockDirectoryEntry(driveFileSystem, '/Computers');
window.webkitResolveLocalFileSystemURLEntries
['filesystem:drive/Comuters/My Laptop'] =
new MockDirectoryEntry(driveFileSystem, '/Computers/My Laptop');
// Populate the directory tree with the mock filesystem.
DirectoryTree.decorate(
directoryTree, directoryModel, volumeManager, null, fileOperationManager,
true);
directoryTree.dataModel = new MockNavigationListModel(volumeManager);
directoryTree.redraw(true);
// At top level, Drive and downloads should be listed.
assertEquals(2, directoryTree.items.length);
assertEquals(str('DRIVE_DIRECTORY_LABEL'), directoryTree.items[0].label);
assertEquals(str('DOWNLOADS_DIRECTORY_LABEL'), directoryTree.items[1].label);
const driveItem = directoryTree.items[0];
reportPromise(
waitUntil(function() {
// Under the drive item, there exist 4 entries.
return driveItem.items.length == 4;
}).then(function() {
// There exist 1 my drive entry and 3 fake entries under the drive item.
assertEquals(str('DRIVE_MY_DRIVE_LABEL'), driveItem.items[0].label);
assertEquals(str('DRIVE_COMPUTERS_LABEL'), driveItem.items[1].label);
assertEquals(
str('DRIVE_SHARED_WITH_ME_COLLECTION_LABEL'),
driveItem.items[2].label);
assertEquals(
str('DRIVE_OFFLINE_COLLECTION_LABEL'), driveItem.items[3].label);
}),
callback);
}
/**
* Test case for creating tree with empty Computers.
* The Computers subtree should be removed if the user has no computers.
*
* @param {!function(boolean)} callback A callback function which is called with
* test result.
*/
function testCreateDirectoryTreeWithEmptyComputers(callback) {
// Create elements.
let parentElement = document.createElement('div');
let directoryTree = document.createElement('div');
directoryTree.metadataModel = mockMetadataModel();
parentElement.appendChild(directoryTree);
// Create mocks.
let directoryModel = new MockDirectoryModel();
let volumeManager = new MockVolumeManager();
const fileOperationManager = {addEventListener: function(name, callback) {}};
// Set entry which is returned by
// window.webkitResolveLocalFileSystemURLResults.
const driveFileSystem = volumeManager.volumeInfoList.item(0).fileSystem;
window.webkitResolveLocalFileSystemURLEntries['filesystem:drive/root'] =
new MockDirectoryEntry(driveFileSystem, '/root');
window.webkitResolveLocalFileSystemURLEntries['filesystem:drive/Computers'] =
new MockDirectoryEntry(driveFileSystem, '/Computers');
// No directories exist under Team Drives
// Populate the directory tree with the mock filesystem.
DirectoryTree.decorate(
directoryTree, directoryModel, volumeManager, null, fileOperationManager,
true);
directoryTree.dataModel = new MockNavigationListModel(volumeManager);
directoryTree.redraw(true);
const driveItem = directoryTree.items[0];
// Ensure we do not have a "Computers" item in drive, as it does not contain
// any children.
reportPromise(
waitUntil(function() {
// Root entries under Drive volume is generated, Computers isn't
// included because it has no child.
// See testCreateDirectoryTreeWithComputers for detail.
return driveItem.items.length == 3;
}).then(function() {
let teamDrivesItemFound = false;
for (let i = 0; i < driveItem.items.length; i++) {
if (driveItem.items[i].label == str('DRIVE_COMPUTERS_LABEL')) {
teamDrivesItemFound = true;
break;
}
}
assertFalse(teamDrivesItemFound, 'Computers should NOT be generated');
}),
callback);
}
/**
* Test case for creating tree with Team Drives & Computers.
* This test expects that the following tree is built.
*
* Google Drive
* - My Drive
* - Team Drives
* - Computers
* - Shared with me
* - Offline
* Downloads
*
* @param {!function(boolean)} callback A callback function which is called with
* test result.
*/
function testCreateDirectoryTreeWithTeamDrivesAndComputers(callback) {
// Create elements.
let parentElement = document.createElement('div');
let directoryTree = document.createElement('div');
directoryTree.metadataModel = mockMetadataModel();
parentElement.appendChild(directoryTree);
// Create mocks.
let directoryModel = new MockDirectoryModel();
let volumeManager = new MockVolumeManager();
const fileOperationManager = {addEventListener: function(name, callback) {}};
// Set entry which is returned by
// window.webkitResolveLocalFileSystemURLResults.
const driveFileSystem = volumeManager.volumeInfoList.item(0).fileSystem;
window.webkitResolveLocalFileSystemURLEntries['filesystem:drive/root'] =
new MockDirectoryEntry(driveFileSystem, '/root');
window
.webkitResolveLocalFileSystemURLEntries['filesystem:drive/team_drives'] =
new MockDirectoryEntry(driveFileSystem, '/team_drives');
window.webkitResolveLocalFileSystemURLEntries
['filesystem:drive/team_drives/a'] =
new MockDirectoryEntry(driveFileSystem, '/team_drives/a');
window.webkitResolveLocalFileSystemURLEntries['filesystem:drive/Computers'] =
new MockDirectoryEntry(driveFileSystem, '/Computers');
window.webkitResolveLocalFileSystemURLEntries
['filesystem:drive/Comuters/My Laptop'] =
new MockDirectoryEntry(driveFileSystem, '/Computers/My Laptop');
// Populate the directory tree with the mock filesystem.
DirectoryTree.decorate(
directoryTree, directoryModel, volumeManager, null, fileOperationManager,
true);
directoryTree.dataModel = new MockNavigationListModel(volumeManager);
directoryTree.redraw(true);
// At top level, Drive and downloads should be listed.
assertEquals(2, directoryTree.items.length);
assertEquals(str('DRIVE_DIRECTORY_LABEL'), directoryTree.items[0].label);
assertEquals(str('DOWNLOADS_DIRECTORY_LABEL'), directoryTree.items[1].label);
const driveItem = directoryTree.items[0];
reportPromise(
waitUntil(function() {
// Under the drive item, there exist 4 entries.
return driveItem.items.length == 5;
}).then(function() {
// There exist 1 my drive entry and 3 fake entries under the drive item.
assertEquals(str('DRIVE_MY_DRIVE_LABEL'), driveItem.items[0].label);
assertEquals(str('DRIVE_TEAM_DRIVES_LABEL'), driveItem.items[1].label);
assertEquals(str('DRIVE_COMPUTERS_LABEL'), driveItem.items[2].label);
assertEquals(
str('DRIVE_SHARED_WITH_ME_COLLECTION_LABEL'),
driveItem.items[3].label);
assertEquals(
str('DRIVE_OFFLINE_COLLECTION_LABEL'), driveItem.items[4].label);
}),
callback);
}
/** /**
* Test case for updateSubElementsFromList setting section-start attribute. * Test case for updateSubElementsFromList setting section-start attribute.
* *
...@@ -570,6 +776,156 @@ function testRemoveLastTeamDrive(callback) { ...@@ -570,6 +776,156 @@ function testRemoveLastTeamDrive(callback) {
callback); callback);
} }
/**
* Test adding the first computer for a user.
* Computers subtree should be shown after the change notification is
* delivered.
*
* @param {!function(boolean)} callback A callback function which is called with
* test result.
*/
function testAddFirstComputer(callback) {
// Create elements.
let parentElement = document.createElement('div');
let directoryTree = document.createElement('div');
directoryTree.metadataModel = mockMetadataModel();
parentElement.appendChild(directoryTree);
// Create mocks.
let directoryModel = new MockDirectoryModel();
let volumeManager = new MockVolumeManager();
const fileOperationManager = {addEventListener: function(name, callback) {}};
// Set entry which is returned by
// window.webkitResolveLocalFileSystemURLResults.
var driveFileSystem = volumeManager.volumeInfoList.item(0).fileSystem;
window.webkitResolveLocalFileSystemURLEntries['filesystem:drive/root'] =
new MockDirectoryEntry(driveFileSystem, '/root');
window.webkitResolveLocalFileSystemURLEntries['filesystem:drive/Computers'] =
new MockDirectoryEntry(driveFileSystem, '/Computers');
// No directories exist under Computers
// Populate the directory tree with the mock filesystem.
DirectoryTree.decorate(
directoryTree, directoryModel, volumeManager, null, fileOperationManager,
true);
directoryTree.dataModel = new MockNavigationListModel(volumeManager);
directoryTree.redraw(true);
let driveItem = directoryTree.items[0];
// Test that we initially do not have a Computers item under druve, and that
// adding a filesystem "/Computers/a" results in the Computers item being
// displayed under drive.
reportPromise(
waitUntil(() => {
return driveItem.items.length == 3;
})
.then(() => {
window.webkitResolveLocalFileSystemURLEntries
['filesystem:drive/Computers/a'] =
new MockDirectoryEntry(driveFileSystem, '/Computers/a');
let event = {
entry: window.webkitResolveLocalFileSystemURLEntries
['filesystem:drive/Computers'],
eventType: 'changed',
};
for (let listener of onDirectoryChangedListeners) {
listener(event);
}
})
.then(() => {
return waitUntil(() => {
for (let i = 0; i < driveItem.items.length; i++) {
if (driveItem.items[i].label == str('DRIVE_COMPUTERS_LABEL')) {
return !driveItem.items[i].hidden;
}
}
return false;
});
}),
callback);
}
/**
* Test removing the last computer for a user.
* Computerss subtree should be removed after the change notification is
* delivered.
*
* @param {!function(boolean)} callback A callback function which is called with
* test result.
*/
function testRemoveLastComputer(callback) {
// Create elements.
let parentElement = document.createElement('div');
let directoryTree = document.createElement('div');
directoryTree.metadataModel = mockMetadataModel();
parentElement.appendChild(directoryTree);
// Create mocks.
let directoryModel = new MockDirectoryModel();
let volumeManager = new MockVolumeManager();
const fileOperationManager = {addEventListener: function(name, callback) {}};
// Set entry which is returned by
// window.webkitResolveLocalFileSystemURLResults.
var driveFileSystem = volumeManager.volumeInfoList.item(0).fileSystem;
window.webkitResolveLocalFileSystemURLEntries['filesystem:drive/root'] =
new MockDirectoryEntry(driveFileSystem, '/root');
window.webkitResolveLocalFileSystemURLEntries['filesystem:drive/Computers'] =
new MockDirectoryEntry(driveFileSystem, '/Computers');
window
.webkitResolveLocalFileSystemURLEntries['filesystem:drive/Computers/a'] =
new MockDirectoryEntry(driveFileSystem, '/Computers/a');
// Populate the directory tree with the mock filesystem.
DirectoryTree.decorate(
directoryTree, directoryModel, volumeManager, null, fileOperationManager,
true);
directoryTree.dataModel = new MockNavigationListModel(volumeManager);
directoryTree.redraw(true);
const driveItem = directoryTree.items[0];
// Check that removing the local computer "a" results in the entire
// "Computers" element being removed, as it has no children.
reportPromise(
waitUntil(() => {
return driveItem.items.length == 4;
})
.then(() => {
return new Promise(resolve => {
window
.webkitResolveLocalFileSystemURLEntries
['filesystem:drive/Computers/a']
.remove(resolve);
});
})
.then(() => {
let event = {
entry: window.webkitResolveLocalFileSystemURLEntries
['filesystem:drive/Computers'],
eventType: 'changed',
};
for (let listener of onDirectoryChangedListeners) {
listener(event);
}
})
.then(() => {
// Wait team drive grand root to appear.
return waitUntil(() => {
for (let i = 0; i < driveItem.items.length; i++) {
if (driveItem.items[i].label == str('DRIVE_COMPUTERS_LABEL')) {
return false;
}
}
return true;
});
}),
callback);
}
/** /**
* Test DirectoryItem.insideMyDrive property, which should return true when * Test DirectoryItem.insideMyDrive property, which should return true when
......
...@@ -16,7 +16,7 @@ const mockVolumeManager = new MockVolumeManager(); ...@@ -16,7 +16,7 @@ const mockVolumeManager = new MockVolumeManager();
mockVolumeManager mockVolumeManager
.getCurrentProfileVolumeInfo(VolumeManagerCommon.VolumeType.DRIVE) .getCurrentProfileVolumeInfo(VolumeManagerCommon.VolumeType.DRIVE)
.fileSystem) .fileSystem)
.populate(['/root/', '/team_drives/']); .populate(['/root/', '/team_drives/', '/Computers/']);
/** /**
* Suppress compiler warning for overwriting chrome.fileManagerPrivate. * Suppress compiler warning for overwriting chrome.fileManagerPrivate.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment