Initial commit
This commit is contained in:
@@ -0,0 +1,160 @@
|
||||
const _ = require('underscore');
|
||||
const $ = require('jquery');
|
||||
const Backbone = require('backbone');
|
||||
const CoreView = require('backbone/core-view');
|
||||
const PagedSearchView = require('dashboard/components/paged-search/paged-search-view');
|
||||
const PagedSearchModel = require('dashboard/data/paged-search-model');
|
||||
const PasswordValidatedForm = require('dashboard/helpers/password-validated-form');
|
||||
const ModalsServiceModel = require('builder/components/modals/modals-service-model');
|
||||
const template = require('./add-group-users-view.tpl');
|
||||
const loadingView = require('builder/components/loading/render-loading.js');
|
||||
const requestErrorTemplate = require('dashboard/views/data-library/content/request-error-template.tpl');
|
||||
const responseParser = require('dashboard/helpers/response-parser');
|
||||
const errorTemplate = require('dashboard/views/data-library/content/error-template.tpl');
|
||||
const GroupUsersListView = require('dashboard/views/organization/groups-admin/group-users-list/group-users-list-view');
|
||||
|
||||
const checkAndBuildOpts = require('builder/helpers/required-opts');
|
||||
|
||||
const REQUIRED_OPTS = [
|
||||
'group',
|
||||
'orgUsers',
|
||||
'userModel',
|
||||
'modalModel'
|
||||
];
|
||||
|
||||
/**
|
||||
* Dialog to add custom basemap to current map.
|
||||
*/
|
||||
module.exports = CoreView.extend({
|
||||
events: {
|
||||
'click .ok': 'ok'
|
||||
},
|
||||
|
||||
initialize: function (options) {
|
||||
checkAndBuildOpts(options, REQUIRED_OPTS, this);
|
||||
this.model = new Backbone.Model();
|
||||
|
||||
// Include current user in fetch results
|
||||
this._orgUsers.excludeCurrentUser(false);
|
||||
|
||||
this._modals = new ModalsServiceModel();
|
||||
|
||||
this._initBinds();
|
||||
this._initViews();
|
||||
},
|
||||
|
||||
clean: function () {
|
||||
// restore org users
|
||||
this._orgUsers.restoreExcludeCurrentUser();
|
||||
CoreView.prototype.clean.apply(this);
|
||||
},
|
||||
|
||||
/**
|
||||
* @override cdb.ui.common.Dialog.prototype.render
|
||||
*/
|
||||
render: function () {
|
||||
this.$el.html(this.render_content());
|
||||
this.$el.addClass('Dialog-contentWrapper');
|
||||
this._onChangeSelected();
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* @implements cdb.ui.common.Dialog.prototype.render_content
|
||||
*/
|
||||
render_content: function () {
|
||||
switch (this.model.get('state')) {
|
||||
case 'saving':
|
||||
return loadingView({
|
||||
title: 'Adding users to group'
|
||||
});
|
||||
case 'passwordConfirmationFail':
|
||||
return requestErrorTemplate({
|
||||
msg: this.model.get('failMessage')
|
||||
});
|
||||
case 'saveFail':
|
||||
return errorTemplate({
|
||||
msg: ''
|
||||
});
|
||||
default:
|
||||
const $content = $(template());
|
||||
$content.find('.js-dlg-body').replaceWith(this._PagedSearchView.render().el);
|
||||
return $content;
|
||||
}
|
||||
},
|
||||
|
||||
ok: function () {
|
||||
const selectedUsers = this._selectedUsers();
|
||||
|
||||
if (!selectedUsers.length) return;
|
||||
|
||||
if (!this._userModel.needsPasswordConfirmation()) {
|
||||
this.model.set('state', 'saving');
|
||||
return this._addUsers();
|
||||
}
|
||||
|
||||
PasswordValidatedForm.showPasswordModal({
|
||||
modalService: this._modals,
|
||||
onPasswordTyped: password => {
|
||||
this.model.set('state', 'saving');
|
||||
this._addUsers(password);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
_initViews: function () {
|
||||
this._PagedSearchView = new PagedSearchView({
|
||||
isUsedInDialog: true,
|
||||
pagedSearchModel: new PagedSearchModel({
|
||||
per_page: 50,
|
||||
order: 'username'
|
||||
}),
|
||||
collection: this._orgUsers,
|
||||
createListView: this._createUsersListView.bind(this)
|
||||
});
|
||||
|
||||
this.addView(this._PagedSearchView);
|
||||
},
|
||||
|
||||
_createUsersListView: function () {
|
||||
return new GroupUsersListView({
|
||||
users: this._orgUsers
|
||||
});
|
||||
},
|
||||
|
||||
_initBinds: function () {
|
||||
this.listenTo(this._orgUsers, 'change:selected', this._onChangeSelected);
|
||||
this.listenTo(this.model, 'change:state', this.render);
|
||||
},
|
||||
|
||||
_onChangeSelected: function () {
|
||||
this.$('.ok').toggleClass('is-disabled', this._selectedUsers().length === 0);
|
||||
},
|
||||
|
||||
_selectedUsers: function () {
|
||||
return this._orgUsers.where({ selected: true });
|
||||
},
|
||||
|
||||
_addUsers: function (password) {
|
||||
const selectedUsers = this._selectedUsers();
|
||||
const ids = _.pluck(selectedUsers, 'id');
|
||||
|
||||
this._group.users.addInBatch(ids, password)
|
||||
.done(() => {
|
||||
this._group.users.add(selectedUsers);
|
||||
this._modalModel.destroy();
|
||||
})
|
||||
.fail(response => {
|
||||
const errors = responseParser(response) || '';
|
||||
|
||||
if (errors.indexOf('Confirmation password') > -1) {
|
||||
return this.model.set({
|
||||
state: 'passwordConfirmationFail',
|
||||
failMessage: errors || ''
|
||||
});
|
||||
}
|
||||
|
||||
this.model.set({ state: 'saveFail' });
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
<div class="CDB-Text Dialog-content Dialog-content--expanded">
|
||||
<div class="Dialog-header Dialog-header--expanded CreateDialog-header">
|
||||
<ul class="CreateDialog-headerSteps">
|
||||
<li class="CreateDialog-headerStep CreateDialog-headerStep--single">
|
||||
<div class="Dialog-headerIcon Dialog-headerIcon--neutral">
|
||||
<i class="CDB-IconFont CDB-IconFont-boss"></i>
|
||||
</div>
|
||||
<p class="Dialog-headerTitle">Add users to this group</p>
|
||||
<p class="Dialog-headerText">When sharing a dataset or map with a group all the users within that group will get the same permissions.</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="CDB-Text js-dlg-body"></div>
|
||||
|
||||
<div class="Dialog-stickyFooter">
|
||||
<div class="Dialog-footer ChangePrivacy-shareFooter u-inner">
|
||||
<div></div>
|
||||
<button class="CDB-Button CDB-Button--primary ok is-disabled">
|
||||
<span class="CDB-Button-Text CDB-Text is-semibold CDB-Size-small u-upperCase">Add users</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,96 @@
|
||||
const Backbone = require('backbone');
|
||||
const CoreView = require('backbone/core-view');
|
||||
const loadingView = require('builder/components/loading/render-loading');
|
||||
const createGroupTemplate = require('./create-group.tpl');
|
||||
const checkAndBuildOpts = require('builder/helpers/required-opts');
|
||||
|
||||
const REQUIRED_OPTS = [
|
||||
'group',
|
||||
'onCreated',
|
||||
'flashMessageModel'
|
||||
];
|
||||
|
||||
/**
|
||||
* View to create a new group for an organization.
|
||||
*/
|
||||
module.exports = CoreView.extend({
|
||||
|
||||
tagName: 'form',
|
||||
|
||||
events: {
|
||||
'click .js-create': '_onClickCreate',
|
||||
'keyup .js-name': '_onChangeName'
|
||||
},
|
||||
|
||||
initialize: function (options) {
|
||||
checkAndBuildOpts(options, REQUIRED_OPTS, this);
|
||||
|
||||
this.model = new Backbone.Model();
|
||||
this._initBinds();
|
||||
},
|
||||
|
||||
render: function () {
|
||||
if (this.model.get('isLoading')) {
|
||||
this.$el.html(
|
||||
loadingView({
|
||||
title: 'Creating group'
|
||||
})
|
||||
);
|
||||
} else {
|
||||
this.$el.html(createGroupTemplate());
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
_initBinds: function () {
|
||||
this.listenTo(this.model, 'change:isLoading', this.render);
|
||||
},
|
||||
|
||||
_onClickCreate: function (ev) {
|
||||
this.killEvent(ev);
|
||||
|
||||
const name = this._name();
|
||||
|
||||
if (name) {
|
||||
this.model.set('isLoading', true);
|
||||
|
||||
this._group.save(
|
||||
{ display_name: name },
|
||||
{
|
||||
wait: true,
|
||||
success: this._onCreated,
|
||||
error: this._showErrors.bind(this)
|
||||
}
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
_showErrors: function (message, response, request) {
|
||||
this.model.set('isLoading', false);
|
||||
|
||||
let flashMessage = 'Could not create group for some unknown reason, please try again';
|
||||
let jsonData;
|
||||
|
||||
try {
|
||||
jsonData = response && JSON.parse(response.responseText);
|
||||
} catch (e) {
|
||||
jsonData = {};
|
||||
}
|
||||
|
||||
if (jsonData && jsonData.errors) {
|
||||
flashMessage = jsonData.errors.join('. ');
|
||||
}
|
||||
|
||||
this._flashMessageModel.show(flashMessage, 'error');
|
||||
},
|
||||
|
||||
_onChangeName: function () {
|
||||
this._flashMessageModel.hide();
|
||||
this.$('.js-create').toggleClass('is-disabled', this._name().length === 0);
|
||||
},
|
||||
|
||||
_name: function () {
|
||||
return this.$('.js-name').val();
|
||||
}
|
||||
|
||||
});
|
||||
@@ -0,0 +1,16 @@
|
||||
<div class="FormAccount-separator"></div>
|
||||
<div class="FormAccount-row">
|
||||
<div class="FormAccount-rowLabel">
|
||||
<label class="CDB-Text CDB-Size-medium is-semibold u-mainTextColor" for="group-name">Group name</label>
|
||||
</div>
|
||||
<div class="FormAccount-rowData">
|
||||
<input type="text" class="CDB-InputText CDB-Text js-name" id="group-name" size="30" maxlength="28" placeholder="Enter a name of group" />
|
||||
<div class="FormAccount-rowInfo FormAccount-rowInfo--marginLeft">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="FormAccount-footer u-justifyEnd">
|
||||
<button class="CDB-Button CDB-Button--primary is-disabled js-create">
|
||||
<span class="CDB-Button-Text CDB-Text is-semibold CDB-Size-small u-upperCase">Create group</span>
|
||||
</button>
|
||||
</div>
|
||||
@@ -0,0 +1,139 @@
|
||||
const Backbone = require('backbone');
|
||||
const CoreView = require('backbone/core-view');
|
||||
const loadingView = require('builder/components/loading/render-loading');
|
||||
const PasswordValidatedForm = require('dashboard/helpers/password-validated-form');
|
||||
const template = require('./edit-group.tpl');
|
||||
|
||||
const checkAndBuildOpts = require('builder/helpers/required-opts');
|
||||
|
||||
const REQUIRED_OPTS = [
|
||||
'group',
|
||||
'userModel',
|
||||
'flashMessageModel',
|
||||
'modals',
|
||||
'onSaved',
|
||||
'onDeleted'
|
||||
];
|
||||
|
||||
/**
|
||||
* View to edit an organization group.
|
||||
*/
|
||||
module.exports = CoreView.extend({
|
||||
tagName: 'form',
|
||||
|
||||
events: {
|
||||
'click .js-delete': '_onClickDelete',
|
||||
'click .js-save': '_onClickSave',
|
||||
'submit form': '_onClickSave',
|
||||
'keyup .js-name': '_onChangeName'
|
||||
},
|
||||
|
||||
initialize: function (options) {
|
||||
checkAndBuildOpts(options, REQUIRED_OPTS, this);
|
||||
|
||||
this.model = new Backbone.Model();
|
||||
this._initBinds();
|
||||
},
|
||||
|
||||
render: function () {
|
||||
if (this.model.get('isLoading')) {
|
||||
this.$el.html(
|
||||
loadingView({
|
||||
title: this.model.get('loadingText')
|
||||
})
|
||||
);
|
||||
} else {
|
||||
this.$el.html(
|
||||
template({ displayName: this._group.get('display_name') })
|
||||
);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
_initBinds: function () {
|
||||
this.listenTo(this.model, 'change:isLoading', this.render);
|
||||
},
|
||||
|
||||
_onClickSave: function (ev) {
|
||||
this.killEvent(ev);
|
||||
|
||||
const name = this._name();
|
||||
|
||||
if (name && name !== this._group.get('display_name')) {
|
||||
this._setLoading('Saving changes');
|
||||
this._group.save(
|
||||
{ display_name: name },
|
||||
{
|
||||
wait: true,
|
||||
success: this._onSaved,
|
||||
error: this._showErrors.bind(this)
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
_onClickDelete: function (ev) {
|
||||
this.killEvent(ev);
|
||||
|
||||
if (!this._userModel.needsPasswordConfirmation()) {
|
||||
return this._destroyGroup();
|
||||
}
|
||||
|
||||
PasswordValidatedForm.showPasswordModal({
|
||||
modalService: this._modals,
|
||||
onPasswordTyped: password => this._destroyGroup(password)
|
||||
});
|
||||
},
|
||||
|
||||
_destroyGroup: function (password) {
|
||||
this._setLoading('Deleting group');
|
||||
|
||||
this._group.destroy({
|
||||
wait: true,
|
||||
data: JSON.stringify({
|
||||
...this._group.attributes,
|
||||
password_confirmation: password
|
||||
}),
|
||||
contentType: 'application/json; charset=utf-8',
|
||||
success: this._onDeleted,
|
||||
error: this._showErrors.bind(this)
|
||||
});
|
||||
},
|
||||
|
||||
_setLoading: function (msg) {
|
||||
this._flashMessageModel.hide();
|
||||
|
||||
this.model.set({
|
||||
isLoading: !!msg,
|
||||
loadingText: msg
|
||||
});
|
||||
},
|
||||
|
||||
_showErrors: function (message, response, request) {
|
||||
this._setLoading('');
|
||||
|
||||
let flashMessage = 'Could not update group for some unknown reason, please try again';
|
||||
let jsonData;
|
||||
|
||||
try {
|
||||
jsonData = response && JSON.parse(response.responseText);
|
||||
} catch (e) {
|
||||
jsonData = {};
|
||||
}
|
||||
|
||||
if (jsonData && jsonData.errors) {
|
||||
flashMessage = jsonData.errors.join('. ');
|
||||
}
|
||||
|
||||
this._flashMessageModel.show(flashMessage, 'error');
|
||||
},
|
||||
|
||||
_onChangeName: function () {
|
||||
this.$('.js-save').toggleClass('is-disabled', this._name().length === 0);
|
||||
this._flashMessageModel.hide();
|
||||
},
|
||||
|
||||
_name: function () {
|
||||
return this.$('.js-name').val();
|
||||
}
|
||||
|
||||
});
|
||||
@@ -0,0 +1,21 @@
|
||||
<div class="FormAccount-separator"></div>
|
||||
|
||||
<div class="FormAccount-row">
|
||||
<div class="FormAccount-rowLabel">
|
||||
<label class="CDB-Text CDB-Size-medium is-semibold u-mainTextColor" for="group-name">Group name</label>
|
||||
</div>
|
||||
<div class="FormAccount-rowData">
|
||||
<input type="text" class="CDB-InputText CDB-Text FormAccount-input FormAccount-input--med js-name" id="group-name" size="30" maxlength="28" value="<%- displayName %>" placeholder="Enter a name of group" />
|
||||
<div class="FormAccount-rowInfo FormAccount-rowInfo--marginLeft">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="FormAccount-footer">
|
||||
<button type="submit" class="CDB-Button CDB-Button--error js-delete">
|
||||
<span class="CDB-Button-Text CDB-Text is-semibold CDB-Size-small u-upperCase">Delete this group</span>
|
||||
</button>
|
||||
|
||||
<button type="submit" class="CDB-Button CDB-Button--primary js-save">
|
||||
<span class="CDB-Button-Text CDB-Text is-semibold CDB-Size-small u-upperCase">Save changes</span>
|
||||
</button>
|
||||
</div>
|
||||
@@ -0,0 +1,124 @@
|
||||
const _ = require('underscore');
|
||||
const CoreView = require('backbone/core-view');
|
||||
const AddGroupUsersView = require('dashboard/views/organization/groups-admin/add-group-users/add-group-users-view');
|
||||
const template = require('./add-or-remove-group-users-filters-extra.tpl');
|
||||
const ViewFactory = require('builder/components/view-factory');
|
||||
const ModalsServiceModel = require('builder/components/modals/modals-service-model');
|
||||
const PasswordValidatedForm = require('dashboard/helpers/password-validated-form');
|
||||
const loadingView = require('builder/components/loading/render-loading.js');
|
||||
const requestErrorTemplate = require('dashboard/views/data-library/content/request-error-template.tpl');
|
||||
const errorTemplate = require('dashboard/views/data-library/content/error-template.tpl');
|
||||
const responseParser = require('dashboard/helpers/response-parser');
|
||||
const randomQuote = require('builder/components/loading/random-quote');
|
||||
|
||||
const checkAndBuildOpts = require('builder/helpers/required-opts');
|
||||
|
||||
const REQUIRED_OPTS = [
|
||||
'group',
|
||||
'orgUsers',
|
||||
'userModel'
|
||||
];
|
||||
|
||||
/**
|
||||
* View for the add/remove button in the filters part.
|
||||
*/
|
||||
module.exports = CoreView.extend({
|
||||
className: 'Filters-group',
|
||||
|
||||
events: {
|
||||
'click .js-add-users': '_onClickAddUsers',
|
||||
'click .js-rm-users': '_onClickRemoveUsers'
|
||||
},
|
||||
|
||||
initialize: function (options) {
|
||||
checkAndBuildOpts(options, REQUIRED_OPTS, this);
|
||||
|
||||
this._modals = new ModalsServiceModel();
|
||||
|
||||
this.listenTo(this._group.users, 'change:selected', this._onChangeSelectedUser);
|
||||
this.listenTo(this._group.users, 'add remove reset', this.render);
|
||||
},
|
||||
|
||||
render: function () {
|
||||
this.$el.html(template());
|
||||
return this;
|
||||
},
|
||||
|
||||
_onClickAddUsers: function (event) {
|
||||
this.killEvent(event);
|
||||
this._openAddGroupsUsersDialog();
|
||||
},
|
||||
|
||||
_openAddGroupsUsersDialog: function () {
|
||||
this._modals.create(modalModel => {
|
||||
return new AddGroupUsersView({
|
||||
group: this._group,
|
||||
orgUsers: this._orgUsers,
|
||||
modalModel,
|
||||
userModel: this._userModel
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
_onChangeSelectedUser: function () {
|
||||
const hasSelectedUsers = this._selectedUsers().length > 0;
|
||||
this.$('.js-add-users').toggle(!hasSelectedUsers);
|
||||
this.$('.js-rm-users').toggle(hasSelectedUsers);
|
||||
},
|
||||
|
||||
_onClickRemoveUsers: function (ev) {
|
||||
this.killEvent(ev);
|
||||
|
||||
if (!this._userModel.needsPasswordConfirmation()) {
|
||||
return this._removeUsers();
|
||||
}
|
||||
|
||||
PasswordValidatedForm.showPasswordModal({
|
||||
modalService: this._modals,
|
||||
onPasswordTyped: password => this._removeUsers(password)
|
||||
});
|
||||
},
|
||||
|
||||
_removeUsers: function (password) {
|
||||
const selectedUsers = this._selectedUsers();
|
||||
|
||||
if (selectedUsers.length > 0) {
|
||||
const userIds = _.pluck(selectedUsers, 'id');
|
||||
|
||||
const modalModel = this._modals.create(() => {
|
||||
return this._createLoadingView();
|
||||
});
|
||||
|
||||
this._group.users.removeInBatch(userIds, password)
|
||||
.always(function () {
|
||||
modalModel.destroy();
|
||||
})
|
||||
.fail(response => {
|
||||
modalModel.destroy();
|
||||
|
||||
const errors = responseParser(response) || '';
|
||||
|
||||
if (errors.indexOf('Confirmation password') > -1) {
|
||||
return this._modals.create(function (modalModel) {
|
||||
return ViewFactory.createByHTML(requestErrorTemplate({ msg: errors }));
|
||||
});
|
||||
}
|
||||
|
||||
this._modals.create(function (modalModel) {
|
||||
return ViewFactory.createByHTML(errorTemplate({ msg: errors }));
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
_createLoadingView: function () {
|
||||
return ViewFactory.createByHTML(loadingView({
|
||||
title: 'Removing users',
|
||||
descHTML: randomQuote()
|
||||
}));
|
||||
},
|
||||
|
||||
_selectedUsers: function () {
|
||||
return this._group.users.where({ selected: true });
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,6 @@
|
||||
<button class="CDB-Button CDB-Button--primary js-add-users">
|
||||
<span class="CDB-Button-Text CDB-Text is-semibold CDB-Size-small u-upperCase">Add users</span>
|
||||
</button>
|
||||
<button class="CDB-Button CDB-Button--error js-rm-users" style="display: none;">
|
||||
<span class="CDB-Button-Text CDB-Text is-semibold CDB-Size-small u-upperCase">Remove from group</span>
|
||||
</button>
|
||||
@@ -0,0 +1,101 @@
|
||||
const _ = require('underscore');
|
||||
const CoreView = require('backbone/core-view');
|
||||
const ViewFactory = require('builder/components/view-factory');
|
||||
const template = require('./empty-group-filters-extra.tpl');
|
||||
const ModalsServiceModel = require('builder/components/modals/modals-service-model');
|
||||
const PasswordValidatedForm = require('dashboard/helpers/password-validated-form');
|
||||
const loadingView = require('builder/components/loading/render-loading.js');
|
||||
const requestErrorTemplate = require('dashboard/views/data-library/content/request-error-template.tpl');
|
||||
const errorTemplate = require('dashboard/views/data-library/content/error-template.tpl');
|
||||
const responseParser = require('dashboard/helpers/response-parser');
|
||||
const randomQuote = require('builder/components/loading/random-quote');
|
||||
|
||||
const checkAndBuildOpts = require('builder/helpers/required-opts');
|
||||
|
||||
const REQUIRED_OPTS = [
|
||||
'groupUsers',
|
||||
'orgUsers',
|
||||
'userModel'
|
||||
];
|
||||
|
||||
/**
|
||||
* View for the add users button and state.
|
||||
*/
|
||||
module.exports = CoreView.extend({
|
||||
className: 'Filters-group',
|
||||
|
||||
events: {
|
||||
'click .js-add-users': '_onClickAddUsers'
|
||||
},
|
||||
|
||||
initialize: function (options) {
|
||||
checkAndBuildOpts(options, REQUIRED_OPTS, this);
|
||||
|
||||
this._modals = new ModalsServiceModel();
|
||||
|
||||
// Init binds
|
||||
this.listenTo(this._orgUsers, 'change:selected', this._onChangeSelectedUser);
|
||||
},
|
||||
|
||||
render: function () {
|
||||
this.$el.html(template());
|
||||
return this;
|
||||
},
|
||||
|
||||
_onChangeSelectedUser: function () {
|
||||
this.$('.js-add-users').toggleClass('is-disabled', this._selectedUsers().length === 0);
|
||||
},
|
||||
|
||||
_onClickAddUsers: function (ev) {
|
||||
this.killEvent(ev);
|
||||
|
||||
if (!this._userModel.needsPasswordConfirmation()) {
|
||||
return this._addUsers();
|
||||
}
|
||||
|
||||
PasswordValidatedForm.showPasswordModal({
|
||||
modalService: this._modals,
|
||||
onPasswordTyped: password => this._addUsers(password)
|
||||
});
|
||||
},
|
||||
|
||||
_addUsers: function (password) {
|
||||
const selectedUsers = this._selectedUsers();
|
||||
|
||||
if (selectedUsers.length > 0) {
|
||||
const userIds = _.pluck(selectedUsers, 'id');
|
||||
|
||||
const modalModel = this._modals.create(modalModel => {
|
||||
return this._createLoadingView();
|
||||
});
|
||||
|
||||
this._groupUsers.addInBatch(userIds, password)
|
||||
.always(() => modalModel.destroy())
|
||||
.fail(response => {
|
||||
const errors = responseParser(response) || '';
|
||||
|
||||
if (errors.indexOf('Confirmation password') > -1) {
|
||||
return this._modals.create(function (modalModel) {
|
||||
return ViewFactory.createByHTML(requestErrorTemplate({ msg: errors }));
|
||||
});
|
||||
}
|
||||
|
||||
this._modals.create(function (modalModel) {
|
||||
return ViewFactory.createByHTML(errorTemplate({ msg: errors }));
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
_createLoadingView: function () {
|
||||
return ViewFactory.createByHTML(loadingView({
|
||||
title: 'Adding users',
|
||||
descHTML: randomQuote()
|
||||
}));
|
||||
},
|
||||
|
||||
_selectedUsers: function () {
|
||||
return this._orgUsers.where({ selected: true });
|
||||
}
|
||||
|
||||
});
|
||||
@@ -0,0 +1,3 @@
|
||||
<button class="CDB-Button CDB-Button--primary is-disabled js-add-users">
|
||||
<span class="CDB-Button-Text CDB-Text is-semibold CDB-Size-small u-upperCase">Add users</span>
|
||||
</button>
|
||||
@@ -0,0 +1,65 @@
|
||||
const $ = require('jquery');
|
||||
const CoreView = require('backbone/core-view');
|
||||
const pluralizeString = require('dashboard/helpers/pluralize');
|
||||
const template = require('./group-header.tpl');
|
||||
const checkAndBuildOpts = require('builder/helpers/required-opts');
|
||||
|
||||
const REQUIRED_OPTS = [
|
||||
'group',
|
||||
'urls'
|
||||
];
|
||||
|
||||
/**
|
||||
* Header view when looking at details of a specific group.
|
||||
*/
|
||||
module.exports = CoreView.extend({
|
||||
initialize: function (options) {
|
||||
checkAndBuildOpts(options, REQUIRED_OPTS, this);
|
||||
|
||||
this._initBinds();
|
||||
},
|
||||
|
||||
_initBinds: function () {
|
||||
this.listenTo(this._group, 'change:display_name', this.render);
|
||||
this.listenTo(this._group.users, 'reset add remove', this.render);
|
||||
},
|
||||
|
||||
render: function () {
|
||||
this._$orgSubheader().hide();
|
||||
|
||||
const isNewGroup = this._group.isNew();
|
||||
const templateData = {
|
||||
backUrl: this._urls.root,
|
||||
title: this._group.get('display_name') || 'Create new group',
|
||||
isNewGroup: isNewGroup,
|
||||
usersUrl: false
|
||||
};
|
||||
|
||||
if (isNewGroup) {
|
||||
templateData.editUrl = window.location;
|
||||
templateData.editUrl.isCurrent = true;
|
||||
} else {
|
||||
templateData.editUrl = this._urls.edit;
|
||||
templateData.usersUrl = this._urls.users;
|
||||
|
||||
const usersCount = this._group.users.length;
|
||||
templateData.usersLabel = usersCount === 0 ? 'Users' : `${usersCount} ${pluralizeString('User', 'Users', usersCount)}`;
|
||||
|
||||
if (!this._urls.users.isCurrent) {
|
||||
templateData.backUrl = this._urls.users;
|
||||
}
|
||||
}
|
||||
|
||||
this.$el.html(template(templateData));
|
||||
return this;
|
||||
},
|
||||
|
||||
_$orgSubheader: function () {
|
||||
return $('.js-org-subheader');
|
||||
},
|
||||
|
||||
clean: function () {
|
||||
this._$orgSubheader().show();
|
||||
CoreView.prototype.clean.call(this);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,33 @@
|
||||
<div class="Filters is-relative">
|
||||
<span class="Filters-separator"></span>
|
||||
<div class="Filters-inner">
|
||||
<div class="Filters-row">
|
||||
<ul class="Filters-group CDB-Text CDB-Size-medium">
|
||||
<li class="u-flex u-alignCenter">
|
||||
<a href="<%- backUrl %>" class="u-actionTextColor u-flex u-alignCenter">
|
||||
<i class="CDB-IconFont CDB-IconFont-arrowPrev u-rSpace--xl"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li class="Filters-typeItem">
|
||||
<div class="FormAccount-title">
|
||||
<p class="CDB-Text CDB-Size-medium is-semibold u-mainTextColor"><%- title %></p>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="Filters-group CDB-Text CDB-Size-medium">
|
||||
<% if (usersUrl) { %>
|
||||
<li class="Filters-typeItem">
|
||||
<a href="<%- usersUrl %>" class="CDB-Text CDB-Size-medium u-mainTextColor Filters-typeLink <%- usersUrl.isCurrent ? 'is-selected' : '' %>">
|
||||
<%- usersLabel %>
|
||||
</a>
|
||||
</li>
|
||||
<% } %>
|
||||
<li class="Filters-typeItem">
|
||||
<a href="<%- editUrl %>" class="CDB-Text CDB-Size-medium u-mainTextColor Filters-typeLink <%- editUrl.isCurrent ? 'is-selected' : '' %>">
|
||||
Settings
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,3 @@
|
||||
<a href="<%- createGroupUrl %>" class="CDB-Button CDB-Button--primary">
|
||||
<span class="CDB-Button-Text CDB-Text is-semibold CDB-Size-small u-upperCase">Create new group</span>
|
||||
</a>
|
||||
@@ -0,0 +1,66 @@
|
||||
const CoreView = require('backbone/core-view');
|
||||
const GroupsListView = require('dashboard/views/organization/groups-admin/groups-list/groups-list-view');
|
||||
const groupsIndexFiltersExtraTemplate = require('./group-index-filters-extra.tpl');
|
||||
const PagedSearchView = require('dashboard/components/paged-search/paged-search-view');
|
||||
const PagedSearchModel = require('dashboard/data/paged-search-model');
|
||||
const ViewFactory = require('builder/components/view-factory');
|
||||
|
||||
const checkAndBuildOpts = require('builder/helpers/required-opts');
|
||||
|
||||
const REQUIRED_OPTS = [
|
||||
'groups',
|
||||
'router',
|
||||
'newGroupUrl'
|
||||
];
|
||||
|
||||
/**
|
||||
* Index view of groups to list groups of an organization
|
||||
*/
|
||||
module.exports = CoreView.extend({
|
||||
|
||||
initialize: function (options) {
|
||||
checkAndBuildOpts(options, REQUIRED_OPTS, this);
|
||||
},
|
||||
|
||||
render: function () {
|
||||
this.clearSubViews();
|
||||
|
||||
const pagedSearchView = new PagedSearchView({
|
||||
pagedSearchModel: new PagedSearchModel({
|
||||
fetch_users: true,
|
||||
fetch_shared_maps_count: true,
|
||||
fetch_shared_tables_count: true
|
||||
}),
|
||||
collection: this._groups,
|
||||
createListView: this._createGroupsView.bind(this),
|
||||
thinFilters: true,
|
||||
filtersExtrasView: this._createFiltersExtraView(),
|
||||
noResults: {
|
||||
icon: 'CDB-IconFont-group',
|
||||
title: 'You have not created any groups yet',
|
||||
msg: 'Creating groups enables you to visualize and search for user members assigned to a business group or team in your organization.'
|
||||
}
|
||||
});
|
||||
this.addView(pagedSearchView);
|
||||
|
||||
this.$el.empty();
|
||||
this.$el.append(pagedSearchView.render().el);
|
||||
return this;
|
||||
},
|
||||
|
||||
_createGroupsView: function () {
|
||||
return new GroupsListView({
|
||||
groups: this._groups,
|
||||
newGroupUrl: this._newGroupUrl
|
||||
});
|
||||
},
|
||||
|
||||
_createFiltersExtraView: function () {
|
||||
return ViewFactory.createByTemplate(groupsIndexFiltersExtraTemplate, {
|
||||
createGroupUrl: this._router._rootUrl.urlToPath('new')
|
||||
}, {
|
||||
className: 'Filters-group'
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
@@ -0,0 +1,54 @@
|
||||
const CoreView = require('backbone/core-view');
|
||||
const template = require('./group-user.tpl');
|
||||
const pluralizeStr = require('dashboard/helpers/pluralize');
|
||||
|
||||
const checkAndBuildOpts = require('builder/helpers/required-opts');
|
||||
|
||||
const REQUIRED_OPTS = [
|
||||
'model'
|
||||
];
|
||||
|
||||
/**
|
||||
* View of a single group user.
|
||||
*/
|
||||
module.exports = CoreView.extend({
|
||||
tagName: 'li',
|
||||
className: 'OrganizationList-user is-selectable',
|
||||
events: {
|
||||
'click': '_onClick'
|
||||
},
|
||||
|
||||
initialize: function (options) {
|
||||
checkAndBuildOpts(options, REQUIRED_OPTS, this);
|
||||
|
||||
this._initBinds();
|
||||
},
|
||||
|
||||
_initBinds: function () {
|
||||
this.listenTo(this.model, 'change:selected', this._onChangeSelected);
|
||||
},
|
||||
|
||||
render: function () {
|
||||
this.$el.html(
|
||||
template({
|
||||
avatarUrl: this.model.get('avatar_url'),
|
||||
username: this.model.get('username'),
|
||||
email: this.model.get('email'),
|
||||
maps_count: pluralizeStr.prefixWithCount('map', 'maps', this.model.get('all_visualization_count')),
|
||||
table_count: pluralizeStr.prefixWithCount('dataset', 'datasets', this.model.get('table_count'))
|
||||
})
|
||||
);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
_onChangeSelected: function (model, isSelected) {
|
||||
this.$el.toggleClass('is-selected', !!isSelected);
|
||||
},
|
||||
|
||||
_onClick: function (ev) {
|
||||
this.killEvent(ev);
|
||||
this.model.set('selected', !this.model.get('selected'));
|
||||
}
|
||||
|
||||
});
|
||||
@@ -0,0 +1,25 @@
|
||||
<a class="CDB-Text OrganizationList-userLink">
|
||||
<div class="OrganizationList-userAvatar UserAvatar">
|
||||
<img src="<%- avatarUrl %>" alt="<%- username %>" src="<%- username %>" class="UserAvatar-img UserAvatar-img--medium-large OrganizationList-userAvatar--img" />
|
||||
</div>
|
||||
<div class="OrganizationList-userInfo">
|
||||
<div class="OrganizationList-userInfoName">
|
||||
<h3 class="CDB-Size-medium OrganizationList-userInfoTitle u-ellipsLongText" title="<%- username %>">
|
||||
<%- username %>
|
||||
</h3>
|
||||
<h4 class="CDB-Text CDB-Size-small u-ellipis u-secondaryTextColor" title="<%- email %>">
|
||||
<%- email %>
|
||||
</h4>
|
||||
</div>
|
||||
<div class="OrganizationList-userInfoData CDB-Text CDB-Size-small u-altTextColor u-alignCenter">
|
||||
<p class="u-flex u-alignCenter">
|
||||
<i class="CDB-IconFont CDB-IconFont-map OrganizationList-userInfoData--paragraph-icon"></i>
|
||||
<%- maps_count %>
|
||||
</p>
|
||||
<p class="u-flex u-alignCenter u-lSpace--xl">
|
||||
<i class="CDB-IconFont CDB-IconFont-rows OrganizationList-userInfoData--paragraph-icon"></i>
|
||||
<%- table_count %>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
@@ -0,0 +1,43 @@
|
||||
const CoreView = require('backbone/core-view');
|
||||
const GroupUserView = require('dashboard/views/organization/groups-admin/group-user/group-user-view');
|
||||
|
||||
const checkAndBuildOpts = require('builder/helpers/required-opts');
|
||||
|
||||
const REQUIRED_OPTS = [
|
||||
'users'
|
||||
];
|
||||
|
||||
/**
|
||||
* View of group users.
|
||||
*/
|
||||
module.exports = CoreView.extend({
|
||||
tagName: 'ul',
|
||||
className: 'OrganizationList',
|
||||
|
||||
initialize: function (options) {
|
||||
checkAndBuildOpts(options, REQUIRED_OPTS, this);
|
||||
|
||||
// init binds
|
||||
this.listenTo(this._users, 'reset add remove', this.render);
|
||||
},
|
||||
|
||||
render: function () {
|
||||
this.clearSubViews();
|
||||
this._renderUsers();
|
||||
return this;
|
||||
},
|
||||
|
||||
_renderUsers: function () {
|
||||
this._users.each(this._createUserView, this);
|
||||
},
|
||||
|
||||
_createUserView: function (user) {
|
||||
const view = new GroupUserView({
|
||||
model: user
|
||||
});
|
||||
|
||||
this.addView(view);
|
||||
this.$el.append(view.render().el);
|
||||
}
|
||||
|
||||
});
|
||||
@@ -0,0 +1,144 @@
|
||||
const Backbone = require('backbone');
|
||||
const CoreView = require('backbone/core-view');
|
||||
const PagedSearchView = require('dashboard/components/paged-search/paged-search-view');
|
||||
const PagedSearchModel = require('dashboard/data/paged-search-model');
|
||||
const ViewFactory = require('builder/components/view-factory');
|
||||
const loadingTemplate = require('builder/components/loading/loading.tpl');
|
||||
const randomQuote = require('builder/components/loading/random-quote');
|
||||
const AddRemoveFiltersExtraView = require('dashboard/views/organization/groups-admin/filters/add-or-remove-group-users-filters-extra-view');
|
||||
const EmptyGroupFiltersExtraView = require('dashboard/views/organization/groups-admin/filters/empty-group-filters-extra-view');
|
||||
const GroupUsersListView = require('dashboard/views/organization/groups-admin/group-users-list/group-users-list-view');
|
||||
const checkAndBuildOpts = require('builder/helpers/required-opts');
|
||||
|
||||
const REQUIRED_OPTS = [
|
||||
'group',
|
||||
'orgUsers',
|
||||
'userModel'
|
||||
];
|
||||
|
||||
/**
|
||||
* View to manage users of a group
|
||||
* It basically has two states, each which relies on its own collection:
|
||||
* - Empty group: i.e. no users, show organization users and allow to add users directly by selecting
|
||||
* - Group users: allow to add or remove users from group.
|
||||
*/
|
||||
module.exports = CoreView.extend({
|
||||
initialize: function (options) {
|
||||
checkAndBuildOpts(options, REQUIRED_OPTS, this);
|
||||
|
||||
this._groupUsers = this._group.users;
|
||||
this._hasPrefetchedGroupUsers = false;
|
||||
this._orgUsers.excludeCurrentUser(false);
|
||||
|
||||
this.model = new Backbone.Model({
|
||||
hasPrefetchedGroupUsers: false,
|
||||
lastRendered: null //, 'groupUsers', 'empty'
|
||||
});
|
||||
|
||||
// Init binds
|
||||
this.listenTo(this._groupUsers, 'sync', this._onResetGroupUsers);
|
||||
|
||||
// Pre-fetch to know what view to render
|
||||
this._groupUsers.fetch({
|
||||
success: () => {
|
||||
this.model.set('hasPrefetchedGroupUsers', true);
|
||||
this.render();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
render: function () {
|
||||
this.clearSubViews();
|
||||
this.$el.empty();
|
||||
|
||||
let view;
|
||||
if (this.model.get('hasPrefetchedGroupUsers')) {
|
||||
view = this._groupUsers.totalCount() > 0
|
||||
? this._createViewForGroupUsers()
|
||||
: this._createViewForEmptyGroup();
|
||||
} else {
|
||||
view = this._createInitialPreloadingView();
|
||||
}
|
||||
|
||||
this.addView(view);
|
||||
this.$el.append(view.render().el);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
clean: function () {
|
||||
this._orgUsers.restoreExcludeCurrentUser();
|
||||
CoreView.prototype.clean.apply(this);
|
||||
},
|
||||
|
||||
_createInitialPreloadingView: function () {
|
||||
return ViewFactory.createByTemplate(loadingTemplate, {
|
||||
title: 'Getting users',
|
||||
descHTML: randomQuote()
|
||||
});
|
||||
},
|
||||
|
||||
_createViewForGroupUsers: function () {
|
||||
this.model.set('lastRendered', 'groupUsers');
|
||||
|
||||
const filtersExtrasView = new AddRemoveFiltersExtraView({
|
||||
group: this._group,
|
||||
orgUsers: this._orgUsers,
|
||||
userModel: this._userModel
|
||||
});
|
||||
this.addView(filtersExtrasView);
|
||||
|
||||
return new PagedSearchView({
|
||||
pagedSearchModel: new PagedSearchModel(),
|
||||
collection: this._groupUsers,
|
||||
createListView: this._createGroupUsersListView.bind(this, this._groupUsers),
|
||||
thinFilters: true,
|
||||
filtersExtrasView
|
||||
});
|
||||
},
|
||||
|
||||
_createViewForEmptyGroup: function () {
|
||||
this.model.set('lastRendered', 'empty');
|
||||
|
||||
const filtersExtrasView = new EmptyGroupFiltersExtraView({
|
||||
groupUsers: this._groupUsers,
|
||||
orgUsers: this._orgUsers,
|
||||
userModel: this._userModel
|
||||
});
|
||||
this.addView(filtersExtrasView);
|
||||
|
||||
return new PagedSearchView({
|
||||
pagedSearchModel: new PagedSearchModel(),
|
||||
collection: this._orgUsers,
|
||||
createListView: this._createGroupUsersListView.bind(this, this._orgUsers),
|
||||
thinFilters: true,
|
||||
filtersExtrasView
|
||||
});
|
||||
},
|
||||
|
||||
_createGroupUsersListView: function (usersCollection) {
|
||||
return new GroupUsersListView({
|
||||
users: usersCollection
|
||||
});
|
||||
},
|
||||
|
||||
_onResetGroupUsers: function () {
|
||||
// just this.render() is not enough, because each sub-view re-renders its view on state changes,
|
||||
// Instead, only re-render when hitting the edge-cases after a rest
|
||||
const lastRendered = this.model.get('lastRendered');
|
||||
const totalGroupUsersCount = this._groupUsers.totalCount();
|
||||
|
||||
if (lastRendered === 'empty') {
|
||||
// scenario: added at least one user, so group is no longer empty => change to group users view to add users
|
||||
if (totalGroupUsersCount > 0) {
|
||||
this.render();
|
||||
}
|
||||
} else if (lastRendered === 'groupUsers') {
|
||||
// scenario: removed last group user(s), so the group is now "empty" => change to org users view to add users
|
||||
if (totalGroupUsersCount === 0) {
|
||||
this.render();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
@@ -0,0 +1,40 @@
|
||||
const CoreView = require('backbone/core-view');
|
||||
const template = require('./group.tpl');
|
||||
const pluralizeStr = require('dashboard/helpers/pluralize');
|
||||
const checkAndBuildOpts = require('builder/helpers/required-opts');
|
||||
|
||||
const REQUIRED_OPTS = [
|
||||
'model',
|
||||
'url'
|
||||
];
|
||||
|
||||
/**
|
||||
* View for an individual group.
|
||||
*/
|
||||
module.exports = CoreView.extend({
|
||||
tagName: 'li',
|
||||
className: 'OrganizationList-user',
|
||||
_PREVIEW_COUNT: 3,
|
||||
|
||||
initialize: function (options) {
|
||||
checkAndBuildOpts(options, REQUIRED_OPTS, this);
|
||||
},
|
||||
|
||||
render: function () {
|
||||
const sharedMapsCount = this.model.get('shared_maps_count');
|
||||
const sharedDatasetsCount = this.model.get('shared_tables_count');
|
||||
|
||||
this.$el.html(
|
||||
template({
|
||||
displayName: this.model.get('display_name'),
|
||||
sharedMapsCount: pluralizeStr('1 shared map', `${sharedMapsCount} shared maps`, sharedMapsCount),
|
||||
sharedDatasetsCount: pluralizeStr('1 shared dataset', `${sharedDatasetsCount} shared datasets`, sharedDatasetsCount),
|
||||
url: this._url,
|
||||
previewUsers: this.model.users.toArray().slice(0, this._PREVIEW_COUNT),
|
||||
usersCount: Math.max(this.model.users.length - this._PREVIEW_COUNT, 0)
|
||||
})
|
||||
);
|
||||
return this;
|
||||
}
|
||||
|
||||
});
|
||||
@@ -0,0 +1,26 @@
|
||||
<a class="CDB-Text OrganizationList-userLink" href="<%- url %>">
|
||||
<div class="OrganizationList-userInfo">
|
||||
<div class="OrganizationList-userInfoName">
|
||||
<h3 class="CDB-Size-medium OrganizationList-userInfoTitle u-ellipsLongText" title="<%- displayName %>">
|
||||
<%- displayName %>
|
||||
</h3>
|
||||
<h4 class="OrganizationList-userInfoSubtitle u-ellipsLongText">
|
||||
<%- sharedMapsCount %> • <%- sharedDatasetsCount %>
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div class="OrganizationList-userInfoData">
|
||||
<% previewUsers.forEach(function(u) { %>
|
||||
<span class="UserAvatar is-in-list">
|
||||
<img class="UserAvatar-img UserAvatar-img--medium" src="<%- u.get('avatar_url') %>" title="<%- u.nameOrUsername() %>" />
|
||||
</span>
|
||||
<% }) %>
|
||||
<% if (usersCount > 0) { %>
|
||||
<span class="UserAvatar is-in-list">
|
||||
<span class="UserAvatar-img UserAvatar-img--medium UserAvatar-img--textReplacement">
|
||||
+<%- usersCount %>
|
||||
</span>
|
||||
</span>
|
||||
<% } %>
|
||||
</div>
|
||||
</a>
|
||||
@@ -0,0 +1,41 @@
|
||||
const CoreView = require('backbone/core-view');
|
||||
const GroupView = require('dashboard/views/organization/groups-admin/group-view/group-view');
|
||||
const ViewFactory = require('builder/components/view-factory');
|
||||
const checkAndBuildOpts = require('builder/helpers/required-opts');
|
||||
|
||||
const REQUIRED_OPTS = [
|
||||
'groups',
|
||||
'newGroupUrl'
|
||||
];
|
||||
|
||||
module.exports = CoreView.extend({
|
||||
initialize: function (options) {
|
||||
checkAndBuildOpts(options, REQUIRED_OPTS, this);
|
||||
},
|
||||
|
||||
render: function () {
|
||||
this.clearSubViews();
|
||||
this.$el.empty();
|
||||
this._renderGroupsView();
|
||||
return this;
|
||||
},
|
||||
|
||||
_renderGroupsView: function () {
|
||||
const view = ViewFactory.createListView(this._createGroupViews(), {
|
||||
tagName: 'ul',
|
||||
className: 'OrganizationList'
|
||||
});
|
||||
this.addView(view);
|
||||
this.$el.append(view.render().el);
|
||||
},
|
||||
|
||||
_createGroupViews: function () {
|
||||
return this._groups.map(model => {
|
||||
return () => new GroupView({
|
||||
model,
|
||||
url: this._newGroupUrl(model)
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
@@ -0,0 +1,55 @@
|
||||
const $ = require('jquery');
|
||||
const CoreView = require('backbone/core-view');
|
||||
const navigateThroughRouter = require('builder/helpers/navigate-through-router');
|
||||
const checkAndBuildOpts = require('builder/helpers/required-opts');
|
||||
|
||||
const REQUIRED_OPTS = [
|
||||
'routerModel'
|
||||
];
|
||||
|
||||
/**
|
||||
* Controller view, managing view state of the groups entry point
|
||||
*/
|
||||
module.exports = CoreView.extend({
|
||||
events: {
|
||||
'click': '_onClick'
|
||||
},
|
||||
|
||||
initialize: function (options) {
|
||||
checkAndBuildOpts(options, REQUIRED_OPTS, this);
|
||||
|
||||
this._initBinds();
|
||||
},
|
||||
|
||||
render: function () {
|
||||
this.clearSubViews();
|
||||
this.$el.html(this._contentView().render().el);
|
||||
return this;
|
||||
},
|
||||
|
||||
_initBinds: function () {
|
||||
this.listenTo(this._routerModel.model, 'change:view', this._onChangeView);
|
||||
},
|
||||
|
||||
_onChangeView: function (model) {
|
||||
model.previous('view').clean();
|
||||
this.render();
|
||||
},
|
||||
|
||||
_contentView: function () {
|
||||
return this._routerModel.model.get('view');
|
||||
},
|
||||
|
||||
_onClick: function (event) {
|
||||
if (!this._isEventTriggeredOutsideOf(event, 'a')) {
|
||||
const url = $(event.target).closest('a').attr('href');
|
||||
if (this._routerModel.isWithinCurrentRoutes(url)) {
|
||||
navigateThroughRouter.apply(this, arguments);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_isEventTriggeredOutsideOf: function (ev, selector) {
|
||||
return $(ev.target).closest(selector).length === 0;
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,56 @@
|
||||
const Backbone = require('backbone');
|
||||
const ViewFactory = require('builder/components/view-factory');
|
||||
const loadingTemplate = require('builder/components/loading/loading.tpl');
|
||||
const errorTemplate = require('dashboard/views/data-library/content/error-template.tpl');
|
||||
const randomQuote = require('builder/components/loading/random-quote');
|
||||
|
||||
/**
|
||||
* Model representing the router state
|
||||
*/
|
||||
module.exports = Backbone.Model.extend({
|
||||
defaults: {
|
||||
view: ''
|
||||
},
|
||||
|
||||
createGroupView: function (groups, id, fetchedCallback) {
|
||||
const group = groups.newGroupById(id);
|
||||
fetchedCallback = fetchedCallback.bind(this, group);
|
||||
|
||||
const setFetchedCallbackView = () => {
|
||||
this.set('view', fetchedCallback());
|
||||
};
|
||||
|
||||
if (group.get('display_name')) {
|
||||
setFetchedCallbackView();
|
||||
} else {
|
||||
// No display name == model not fetched yet, so show loading msg meanwhile
|
||||
this.createLoadingView('Loading group details');
|
||||
|
||||
group.fetch({
|
||||
data: {
|
||||
fetch_users: true
|
||||
},
|
||||
success: function () {
|
||||
groups.add(group);
|
||||
setFetchedCallbackView();
|
||||
},
|
||||
error: this.createErrorView.bind(this)
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
createLoadingView: function (msg) {
|
||||
this.set('view', ViewFactory.createByTemplate(loadingTemplate, {
|
||||
title: msg,
|
||||
descHTML: randomQuote()
|
||||
}));
|
||||
},
|
||||
|
||||
createErrorView: function () {
|
||||
// Generic error view for now
|
||||
this.set('view', ViewFactory.createByTemplate(errorTemplate, {
|
||||
msg: ''
|
||||
}));
|
||||
}
|
||||
|
||||
});
|
||||
Reference in New Issue
Block a user