Skip to content

Commit

Permalink
Merge pull request #2484 from CartoDB/2340-privacy-dialog-loading-err…
Browse files Browse the repository at this point in the history
…-states

Add loading+error state for privacy dialog
  • Loading branch information
viddo committed Feb 25, 2015
2 parents 561577e + 666832b commit 50abeac
Show file tree
Hide file tree
Showing 13 changed files with 629 additions and 331 deletions.
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
* Remove tmp and unused files [#2328](https://github.com/CartoDB/cartodb/pull/2328)
* Open privacy dialog directly from items [#2442](https://github.com/CartoDB/cartodb/pull/2442)
* Fixes error handling when adding an erroneous WMS URL.
* Add loading+error state for privacy dialog [#2484](https://github.com/CartoDB/cartodb/pull/2484)

Bugfixes:
* When being in any configuration page remove the arrow from the breadcrumb [#2312](https://github.com/CartoDB/cartodb/pull/2312)
Expand Down
2 changes: 1 addition & 1 deletion config/frontend.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
#This file defines the version of the frontend code that is going to be loaded.
3.7.5
3.7.6
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@
<%= itemName %> privacy
</p>
<p class="DefaultSecondary">
Although we believe in the power of open data, you can also protected your tables.
Although we believe in the power of open data, you can also protect your <%= itemType %>.
</p>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,20 @@ module.exports = cdb.core.View.extend({
'click .js-back' : '_onClickBack'
},

initialize: function(args) {
this._org = args.organization;
this._permission = args.permission;
this._canChangeWriteAccess = args.canChangeWriteAccess;
this._tableMetadata = args.tableMetadata;
initialize: function() {
if (!this.options.viewModel) {
throw new Error('viewModel is compulsory');
}
this._viewModel = this.options.viewModel;
this.add_related_model(this._viewModel);

this._template = cdb.templates.getTemplate('new_dashboard/dialogs/change_privacy/share_view/template');
},

render: function() {
this.clearSubViews();

var usersCount = this._org.users.length;
var usersCount = this._organization().users.length;

this.$el.html(
this._template({
Expand All @@ -42,27 +43,31 @@ module.exports = cdb.core.View.extend({
return this;
},

_organization: function() {
return this._viewModel.get('user').organization;
},

_renderOrganizationPermissionView: function() {
this._appendPermissionView(
new PermissionView({
model: this._org,
permission: this._permission,
canChangeWriteAccess: this._canChangeWriteAccess,
model: this._organization(),
permission: this._viewModel.get('permission'),
canChangeWriteAccess: this._viewModel.canChangeWriteAccess(),
title: 'Default settings for your Organization',
desc: 'New users will have this permission'
})
);
},

_renderUserPermissionViews: function() {
var usersUsingVis = this._usersUsingVis();
var usersUsingVis = this._viewModel.usersUsingVis();

this._org.users.each(function(user) {
this._organization().users.each(function(user) {
this._appendPermissionView(
new PermissionView({
model: user,
permission: this._permission,
canChangeWriteAccess: this._canChangeWriteAccess,
permission: this._viewModel.get('permission'),
canChangeWriteAccess: this._viewModel.canChangeWriteAccess(),
title: user.get('username'),
desc: user.get('name'),
avatarUrl: user.get('avatar_url'),
Expand All @@ -72,30 +77,18 @@ module.exports = cdb.core.View.extend({
}, this);
},

_usersUsingVis: function() {
return _.chain(_.union(
this._tableMetadata.get('dependent_visualizations'),
this._tableMetadata.get('non_dependent_visualizations')
))
.compact()
.map(function(visData) {
return visData.permission.owner;
})
.value();
},

_appendPermissionView: function(view) {
this.$('.js-permissions').append(view.render().el);
this.addView(view);
},

_onClickBack: function(ev) {
this.killEvent(ev);
this.trigger('click:back');
this._viewModel.changeState('Start');
},

_onClickSave: function(ev) {
this.killEvent(ev);
this.trigger('click:save');
this._viewModel.save();
}
});
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
var cdb = require('cartodb.js');
var _ = require('underscore');
var $ = require('jquery');

var DISABLED_SAVE_CLASS_NAME = 'is-disabled';

Expand All @@ -13,45 +14,48 @@ module.exports = cdb.core.View.extend({
'click .js-save' : '_onClickSave',
'click .js-option' : '_selectOption',
'click .js-share' : '_onClickShare',
'keyup .js-password-input' : '_updatePassword',
'blur .js-password-input' : 'render' // make sure the view is consistently rendered after writing password
'keyup .js-password-input' : '_updatePassword'
},

initialize: function(args) {
this.vis = args.vis; // of model cdb.admin.Visualization
this.user = args.user;
this.upgradeUrl = args.upgradeUrl;
this.privacyOptions = args.privacyOptions;
initialize: function() {
if (!this.options.viewModel) {
throw new Error('viewModel is compulsory');
}
this._viewModel = this.options.viewModel;
this._viewModel.get('privacyOptions').bind('change', this.render, this);
this.add_related_model(this._viewModel);

this.template = cdb.templates.getTemplate('new_dashboard/dialogs/change_privacy/start_view_template');

this.privacyOptions.bind('change', this.render, this);
this.add_related_model(this.privacyOptions);
},

render: function() {
var pwdOption = this.privacyOptions.passwordOption();
var selectedOption = this.privacyOptions.selectedOption();
var org = this.user.organization;
this.clearSubViews();

var privacyOptions = this._viewModel.get('privacyOptions');
var pwdOption = privacyOptions.passwordOption();
var selectedOption = privacyOptions.selectedOption();
var upgradeUrl = this._viewModel.get('upgradeUrl');

this.$el.html(
this.template({
itemName: this.vis.get('name'),
options: this.privacyOptions,
itemName: this._viewModel.get('vis').get('name'),
options: privacyOptions,
showPasswordInput: pwdOption === selectedOption,
pwdOption: pwdOption,
saveBtnClassNames: selectedOption.canSave() ? '' : DISABLED_SAVE_CLASS_NAME,
showUpgradeBanner: !!this.upgradeUrl && this.privacyOptions.any(function(option) { return !!option.get('disabled'); }),
upgradeUrl: this.upgradeUrl,
showShareBanner: !!org
showUpgradeBanner: upgradeUrl && privacyOptions.any(function(o) { return !!o.get('disabled'); }),
upgradeUrl: upgradeUrl,
showShareBanner: this._viewModel.shouldShowShareBanner()
})
);

return this;
},

_selectOption: function(ev) {
var option = this.privacyOptions.at( $(ev.target).closest('.js-option').attr('data-index') );
var i = $(ev.target).closest('.js-option').data('index');
var option = this._viewModel.get('privacyOptions').at(i);

if (!option.get('disabled')) {
option.set('selected', true);
}
Expand All @@ -60,19 +64,19 @@ module.exports = cdb.core.View.extend({
_updatePassword: function(ev) {
// Reflect state directly in DOM instead of re-rendering to avoid loosing the focus on input
var pwd = ev.target.value;
this.privacyOptions.passwordOption().set({ password: pwd }, { silent: true });
this._viewModel.get('privacyOptions').passwordOption().set({ password: pwd }, { silent: true });
this.$('.js-save')[ _.isEmpty(pwd) ? 'addClass' : 'removeClass' ](DISABLED_SAVE_CLASS_NAME);
},

_onClickShare: function(ev) {
if (this.privacyOptions.selectedOption().canSave()) {
if (this._viewModel.canSave()) {
this.killEvent(ev);
this.trigger('click:share');
this._viewModel.changeState('Share');
}
},

_onClickSave: function(ev) {
this.killEvent(ev);
this.trigger('click:save');
this._viewModel.save();
}
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
var cdb = require('cartodb.js');
var _ = require('underscore');
var PrivacyOptions = require('./options_collection');

/**
* View model for a change privacy dialog
*/
module.exports = cdb.core.Model.extend({

defaults: {
vis: undefined,
user: undefined,
upgradeUrl: '',
state: 'Start',
hasPermissionsChanged: false,
privacyOptions: undefined
},

initialize: function(attrs) {
if (!attrs.vis) {
throw new Error('vis is required');
}
if (!attrs.user) {
throw new Error('user is required');
}
this.set('privacyOptions', PrivacyOptions.byVisAndUser(attrs.vis, attrs.user));

if (attrs.user.organization) {
this._setupSharePrerequisities();
}
},

changeState: function(newState) {
// Force a change event
this.set('state', undefined, { silent: true });
this.set('state', newState);
},

canShare: function() {
return !!this.get('permission');
},

usersUsingVis: function() {
var metadata = this.get('vis').tableMetadata();
return _.chain(_.union(
metadata.get('dependent_visualizations'),
metadata.get('non_dependent_visualizations')
))
.compact()
.map(function(d) {
return d.permission.owner;
})
.value();
},

shouldShowShareBanner: function() {
return this.get('user').organization;
},

shouldRenderDialogWithExpandedLayout: function() {
return this.get('state') === 'Share';
},

canChangeWriteAccess: function() {
return !this.get('vis').isVisualization();
},

canSave: function() {
return this.get('privacyOptions').selectedOption().canSave();
},

save: function() {
var selectedOption = this.get('privacyOptions').selectedOption();
if (selectedOption.canSave()) {
this.changeState('Saving');
var self = this;
selectedOption.saveToVis(this.get('vis'))
.done(function() {
self.get('hasPermissionsChanged') ? self._savePermissionChanges() : self._saveDone();
})
.fail(this._saveFail.bind(this));
}
},

_setupSharePrerequisities: function() {
var vis = this.get('vis');
this.set('permission', vis.permission.clone());
this.get('permission').acl.bind('all', function() {
this.set('hasPermissionsChanged', true);
}, this);

if (!vis.isVisualization()) {
var self = this;
vis.tableMetadata().fetch({
silent: true,
success: function() {
if (self.get('state') === 'Share') {
self.changeState('Share');
}
}
});
}
},

_savePermissionChanges: function() {
var originalPermission = this.get('vis').permission;
originalPermission.overwriteAcl(this.get('permission'));
originalPermission.save()
.done(this._saveDone.bind(this))
.fail(this._saveFail.bind(this));
},

_saveDone: function() {
this.changeState('SaveDone');
},

_saveFail: function() {
this.changeState('SaveFail');
}

});
Loading

0 comments on commit 50abeac

Please sign in to comment.