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

[For 10.4] Add share indicator in webUI #36572

Merged
merged 2 commits into from
Dec 19, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
24 changes: 16 additions & 8 deletions apps/files/css/files.css
Original file line number Diff line number Diff line change
Expand Up @@ -512,21 +512,29 @@ table td.filename .uploadtext {
}

/* File checkboxes */
html:not(.ie8) #fileList tr td.filename > .selectCheckBox + label:before {
#fileList tr td.filename > .selectCheckBox + label:before {
opacity: 0;
position: absolute;
bottom: 4px;
right: 0;
z-index: 10;
}

html.ie8 #fileList tr td.filename > .selectCheckBox {
filter: alpha(opacity=0);
opacity: 0;
float: left;
top: 0;
margin: 32px 0 4px 32px;
/* bigger clickable area doesn’t work in FF width:2.8em; height:2.4em;*/
#fileList tr:not(:hover):not(.selected) td.filename .thumbnail.sharetree-item:after {
position: absolute;
display: block;
content: '';
bottom: 0px;
right: -5px;
z-index: 10;
background-image: url(../../../core/img/actions/shared.svg);
width: 14px;
height: 14px;
background-repeat: no-repeat;
background-position: center;
background-size: 10px;
background-color: #bfbfbf;
border-radius: 50%;
}

/* Show checkbox when hovering, checked, or selected */
Expand Down
247 changes: 236 additions & 11 deletions apps/files/js/filelist.js
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,13 @@
*/
_sortComparator: null,

/**
* Stores shareTree items and infos
*
* @type Array
*/
_shareTreeCache: {},

/**
* Whether to do a client side sort.
* When false, clicking on a table header will call reload().
Expand Down Expand Up @@ -293,11 +300,11 @@
breadcrumbOptions.onDrop = _.bind(this._onDropOnBreadCrumb, this);
breadcrumbOptions.onOver = function() {
self.$el.find('td.filename.ui-droppable').droppable('disable');
}
};
breadcrumbOptions.onOut = function() {
self.$el.find('td.filename.ui-droppable').droppable('enable');
};
}
}
this.breadcrumb = new OCA.Files.BreadCrumb(breadcrumbOptions);

var $controls = this.$el.find('#controls');
Expand Down Expand Up @@ -379,6 +386,7 @@
// remove summary
this.$el.find('tfoot tr.summary').remove();
this.$fileList.empty();

},

/**
Expand Down Expand Up @@ -1048,6 +1056,7 @@
$(window).scrollTop(0);

this.$fileList.trigger(jQuery.Event('updated'));

_.defer(function() {
self.$el.closest('#app-content').trigger(jQuery.Event('apprendered'));
});
Expand Down Expand Up @@ -1389,6 +1398,10 @@
tr.addClass('hidden-file');
}

if(_.keys(this._shareTreeCache).length) {
jvillafanez marked this conversation as resolved.
Show resolved Hide resolved
filenameTd.find('.thumbnail:not(.sharetree-item)').addClass('sharetree-item');
}

// display actions
this.fileActions.display(filenameTd, !options.silent, this);

Expand Down Expand Up @@ -1440,21 +1453,32 @@
* @param {boolean} [changeUrl=true] if the URL must not be changed (defaults to true)
* @param {boolean} [force=false] set to true to force changing directory
* @param {string} [fileId] optional file id, if known, to be appended in the URL
* @return {Promise} empty
*/
changeDirectory: function(targetDir, changeUrl, force, fileId) {
var self = this;
var currentDir = this.getCurrentDirectory();
targetDir = targetDir || '/';
if (!force && currentDir === targetDir) {
return;
}
this._setCurrentDir(targetDir, changeUrl, fileId);
// discard finished uploads list, we'll get it through a regular reload
this._uploads = {};
this.reload().then(function(success){
if (!success) {
self.changeDirectory(currentDir, true);

return new Promise(function(resolve, reject) {
felixheidecke marked this conversation as resolved.
Show resolved Hide resolved

if (!force && currentDir === targetDir) {
resolve();
return;
}
self._setCurrentDir(targetDir, changeUrl, fileId);
// discard finished uploads list, we'll get it through a regular reload
self._uploads = {};
self.reload().then(function(success){
if (!success) {
self.changeDirectory(currentDir, true);
reject();
}
self._updateShareTree().then(function() {
self._setShareTreeIcons();
});
resolve();
});
});
},
linkTo: function(dir) {
Expand Down Expand Up @@ -1723,6 +1747,207 @@
return OC.linkToRemoteBase('dav') + '/files/' + uid + encodedPath;
},

/**
* Fetch shareTypes of a certain directory
* @param {String} dir directory string
* @return {Promise} object with name and shareTypes
*/
getDirShareInfo: function(dir) {
// Dir can't be empty
if (typeof dir !== 'string' || dir.length === 0) {
return Promise.reject('getDirShareInfo(). param must be typeof string and can not be empty!');
}

// avoiding a unnessesary API calls
if (typeof this._shareTreeCache[dir] !== 'undefined' || dir === '/') {
return Promise.resolve();
}

// trim trailing slashes
dir = dir.replace(/\/$/, "");

var self = this;
var client = this.filesClient;
var options = {
properties : ['{' + OC.Files.Client.NS_OWNCLOUD + '}share-types']
};

return new Promise( function(resolve, reject) {
client.getFileInfo(dir, options).done(function(s, dir) {

var path = OC.joinPaths(dir.path, dir.name);

if (dir.shareTypes !== undefined) {
// Fetch all shares for directory in question
$.get( OC.linkToOCS('apps/files_sharing/api/v1', 2) + 'shares?' + OC.buildQueryString({format: 'json', path: path, reshares : true }), function(e) {
self._shareTreeCache[path] = {
name : dir.name,
shares : e.ocs.data
};
resolve();
});
} else {
resolve();
}
}).fail(function(error) {
reject(error);
});
});
},

/**
* Fetch shareInfos recursively from current
* directory down to root
* @param {String} dir directory string
* @return {Promise} array of objects with name and shareTypes
*/
getPathShareInfo: function(path) {
if (typeof path !== 'string') {
console.error('getDirShareInfo(). param must be typeof string!');
return Promise.reject();
}

var crumbs = [];
var pathToHere = '';
var parts = (path === '/' || path.length === 0) ? ['/'] : path.split('/');

for (var i = 0; i < parts.length; i++) {
var part = parts[i];
pathToHere += part + '/';

crumbs.push(this.getDirShareInfo(pathToHere));
}

return Promise.all(crumbs);
},

_updateShareTree: function() {
var self = this;
var dir = this.getCurrentDirectory();

// Purge shareTreeCache in root dir
if (dir === '/') {
this._purgeShareTreeCache();
return Promise.resolve();
}

return this.getPathShareInfo(dir).then(function () {
var breadcrumbs = dir.split('/');

// Diff keys in shareTreeCache agains the current dir
// removing deeper nested shares
var cache = _.omit(self._shareTreeCache, function(value, key) {
var diffs = _.difference(key.split('/'), breadcrumbs);
return diffs.length > 0;
});

self._setShareTreeCache(cache);
});
},

_setShareTreeCache: function(data) {
this._shareTreeCache = data;
},

_purgeShareTreeCache: function() {
this._setShareTreeCache({});
},

_setShareTreeIcons: function() {
// Add share-tree icon to files and folders
// each per <tr> in the table

if (_.keys(this._shareTreeCache).length > 0) {
this.$fileList.find('tr td.filename .thumbnail:not(.sharetree-item)').addClass('sharetree-item');
} else {
this.$fileList.find('tr td.filename .thumbnail.sharetree-item').removeClass('sharetree-item');
}
},

_setShareTreeUserGroupView: function() {
var self = this;
var $list = $('<ul>', { id : 'shareTreeUserGroupList' });

if (! _.keys(self._shareTreeCache).length > 0) {
return;
}

$('.shareeTreeUserGroupListView').html($list);

// Shared folders
_.each(self._shareTreeCache, function(folder) {

var shares = _.filter(folder.shares, function(share) {
return (
share.share_type === OC.Share.SHARE_TYPE_USER ||
share.share_type === OC.Share.SHARE_TYPE_GROUP ||
share.share_type === OC.Share.SHARE_TYPE_GUEST ||
share.share_type === OC.Share.SHARE_TYPE_REMOTE );
});

_.each(shares, function(share) {

var shareWith = share.share_with_displayname;

if (share.share_type === OC.Share.SHARE_TYPE_GROUP) {
shareWith += ' (' + t('core', 'group') + ')';
} else if (share.share_type === OC.Share.SHARE_TYPE_REMOTE) {
shareWith += ' (' + t('files_sharing', 'Remote share') + ')';
}

var $path = $('<span>', { class : 'shareTree-item-path', text : t('core', 'via') + " " + folder.name });
var $name = $('<strong>', { class : 'shareTree-item-name', text : shareWith });
var $icon = $('<div>', { class : 'shareTree-item-avatar' });

$icon.avatar(share.share_with, 32);

$('<li class="shareTree-item">').append( $icon, $name, $path).appendTo($list).click(function() {
self.changeDirectory(share.path.replace(folder.name, ''), true).then(function() {
self._updateDetailsView(folder.name, true);
}).catch(function(e) {
console.error(e);
});
});
});
});
},

_setShareTreeLinkView: function() {
var self = this;
var $list = $('<ul>', { id : 'shareTreeLinkList' });

if (! _.keys(self._shareTreeCache).length > 0) {
return;
}

$('.shareeTreeLinkListView').html($list);

// Shared folders
_.each(self._shareTreeCache, function(folder) {

var shares = _.filter(folder.shares, function(share) {
return share.share_type === OC.Share.SHARE_TYPE_LINK;
});

_.each(shares, function(share) {

var shareName = (!_.isEmpty(share.name)) ? share.name : share.token;

var $path = $('<span>', { class : 'shareTree-item-path', text : t('core', 'via') + " " + folder.name });
var $name = $('<strong>', { class : 'shareTree-item-name', text : shareName });
var $icon = $('<span>', { class : 'shareTree-item-icon link-entry--icon icon-public-white' });

$('<li class="shareTree-item">').append( $icon, $name, $path).appendTo($list).click(function() {
self.changeDirectory(share.path.replace(folder.name, ''), true).then(function() {
self._updateDetailsView(folder.name, true);
}).catch(function(e) {
console.error(e);
});
});
});
});
},

/**
* Generates a preview URL based on the URL space.
* @param urlSpec attributes for the URL
Expand Down
18 changes: 18 additions & 0 deletions apps/files/tests/js/filelistSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -1024,6 +1024,24 @@ describe('OCA.Files.FileList tests', function() {
expect($summary.find('.dirinfo').hasClass('hidden')).toEqual(true);
expect($summary.find('.fileinfo').text()).toEqual('1 file');
});
it('shows icon for shareTree items if parent is shared', function() {
fileList._setShareTreeCache({
'/folder' : {
name: "folder",
shares : [{
share_type: 0,
share_with_displayname: "Demo user",
}]
}
});
fileList.setFiles(testFiles);
expect($('#fileList tr:first-of-type td .sharetree-item').length).toEqual(1);
});
it('does not show shareTree items if shareTree is empty', function() {
fileList._purgeShareTreeCache();
fileList.setFiles(testFiles);
expect($('#fileList tr td .sharetree-item').length).toEqual(0);
});
});
describe('Filtered list rendering', function() {
it('filters the list of files using filter()', function() {
Expand Down
Loading