222 lines
5.8 KiB
JavaScript
222 lines
5.8 KiB
JavaScript
|
|
/**
|
|
* Header sync info when visualization is table type
|
|
*
|
|
* - If there is any change in the state, it will be rendered again.
|
|
*
|
|
* new cdb.admin.SyncInfo({
|
|
* model: synchronization_model
|
|
* });
|
|
*/
|
|
|
|
cdb.admin.SyncInfo = cdb.core.View.extend({
|
|
|
|
tagName: 'div',
|
|
className: 'sync_info',
|
|
|
|
_SYNC_GAP: 15, // Gap necessary to perform next synchronization
|
|
// Value in MINUTES
|
|
_POLLING_GAP: 15, // Gap necessary to start polling and checking
|
|
// synchronization. Value in SECONDS
|
|
|
|
_TEXTS: {
|
|
enabled: _t('This table will be synced again <%- run_at %>'),
|
|
few_moments: _t('in a few moments'),
|
|
sync_now_disabled: _t('You will be able to sync manually <%- gap %> minutes after your last synchronization')
|
|
},
|
|
|
|
events: {
|
|
'click a.sync_options': '_onClickOptions',
|
|
'click a.sync_now': '_onClickSyncNow'
|
|
},
|
|
|
|
initialize: function() {
|
|
_.bindAll(this, '_startSync');
|
|
|
|
this.dataLayer = this.options.dataLayer;
|
|
this.table = this.dataLayer.table;
|
|
this.model = this.table.synchronization;
|
|
this.template = cdb.templates.getTemplate('table/header/views/sync_info_content');
|
|
this.model.bind('change', this.render, this);
|
|
|
|
// Check sync now button
|
|
if (this._isSyncing()) {
|
|
this._showSyncNow();
|
|
this._startSync();
|
|
}
|
|
},
|
|
|
|
render: function() {
|
|
var attrs = _.clone(this.model.attributes);
|
|
var self = this;
|
|
|
|
// Destroy tipsy just in case
|
|
this._destroyTipsy();
|
|
|
|
attrs.ran_at = moment(attrs.ran_at || new Date()).fromNow();
|
|
|
|
// Due to the time we need to polling, we have to display to the user
|
|
// that the sync will be in a moment
|
|
if (!attrs.run_at || (new Date(attrs.run_at) <= new Date())) {
|
|
attrs.run_at = this._TEXTS.few_moments;
|
|
} else {
|
|
attrs.run_at = moment(attrs.run_at).fromNow();
|
|
}
|
|
|
|
// Can table be synced?
|
|
attrs.canSync = this._canTableSyncNow() ? true : false ;
|
|
|
|
// Come from external source?
|
|
attrs.fromExternalSource = this.model.get("from_external_source");
|
|
|
|
// Render
|
|
this.$el
|
|
.html(this.template(attrs))
|
|
.attr('class', '')
|
|
.addClass(attrs.state + ' ' + this.className);
|
|
|
|
// Tipsy?
|
|
this.$(".sync_now_disabled").tipsy({
|
|
gravity: 's',
|
|
fade: true,
|
|
title: function() {
|
|
return _.template(self._TEXTS.sync_now_disabled)({ gap: self._SYNC_GAP })
|
|
}
|
|
});
|
|
|
|
return this;
|
|
},
|
|
|
|
_bindEvents: function() {
|
|
this.model.bind('change:state', this._onStateChange, this);
|
|
},
|
|
|
|
_unbindEvents: function() {
|
|
this.model.unbind('change:state', this._onStateChange, this)
|
|
},
|
|
|
|
// Helpers
|
|
|
|
_canTableSyncNow: function() {
|
|
var ran_at = new Date(this.model.get('ran_at'));
|
|
var now = new Date();
|
|
var state = this.model.get('state');
|
|
var gap = this._SYNC_GAP*60*1000; // Importer needs some time to perform the next sync,
|
|
// set 15 min as default.
|
|
|
|
// If table is syncing... false!
|
|
if (state === "syncing") {
|
|
return false
|
|
}
|
|
|
|
if (( now.getTime() - ran_at.getTime() ) > gap) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
},
|
|
|
|
_isSyncing: function() {
|
|
return this.model.get('state') === "syncing";
|
|
},
|
|
|
|
|
|
// UI bind events //
|
|
|
|
_onClickSyncNow: function(e) {
|
|
if (e) this.killEvent(e);
|
|
|
|
if (this._canTableSyncNow()) {
|
|
// Set syncing state
|
|
this.model.set('state', 'syncing');
|
|
// Show dialog
|
|
this._showSyncNow();
|
|
// Enqueue synchronization
|
|
this.model.syncNow(this._startSync);
|
|
}
|
|
},
|
|
|
|
_onClickOptions: function(e) {
|
|
if (e) this.killEvent(e);
|
|
var dialog = new cdb.editor.SyncView({
|
|
clean_on_hide: true,
|
|
enter_to_confirm: true,
|
|
table: this.table
|
|
});
|
|
dialog.appendToBody();
|
|
},
|
|
|
|
|
|
_startSync: function() {
|
|
// Render again
|
|
this.render();
|
|
// Bind events
|
|
this._bindEvents();
|
|
// We MUST wait before start polling
|
|
var self = this;
|
|
_.delay(function() {
|
|
self.model.pollCheck();
|
|
}, (this._POLLING_GAP * 1000)); // polling gap * miliseconds
|
|
},
|
|
|
|
_finishSync: function() {
|
|
this._unbindEvents();
|
|
this.model.destroyCheck();
|
|
this._hideSyncNow();
|
|
|
|
// Reload table and map data
|
|
this.dataLayer.invalidate();
|
|
this.table.data().refresh();
|
|
},
|
|
|
|
_onStateChange: function() {
|
|
this._finishSync();
|
|
|
|
// Success state could be wrong if any error_code
|
|
// or error_message appears in the model
|
|
if (this.model.get('state') === "success" &&
|
|
(this.model.get('error_code') || this.model.get('error_message'))
|
|
) {
|
|
this.model.set('state', 'failure');
|
|
}
|
|
|
|
this.render();
|
|
},
|
|
|
|
|
|
// Show or hide sync now modal //
|
|
|
|
_showSyncNow: function(e) {
|
|
if (e) this.killEvent(e);
|
|
|
|
var modal = cdb.editor.ViewFactory.createDialogByTemplate('common/templates/loading', {
|
|
title: 'Your dataset is being synced…',
|
|
quote: "This action will take some time. In the meantime the UI is disabled, but APIs will work as usual."
|
|
}, { sticky: true }).render();
|
|
this.sync_now = modal;
|
|
modal.appendToBody();
|
|
},
|
|
|
|
_hideSyncNow: function() {
|
|
if (this.sync_now) {
|
|
this.sync_now.hide();
|
|
}
|
|
},
|
|
|
|
|
|
_destroyTipsy: function() {
|
|
// Remove tipsy
|
|
if (this.$('.sync_now_disabled').data('tipsy')) {
|
|
this.$('.sync_now_disabled')
|
|
.unbind('mouseenter mouseleave')
|
|
.data('tipsy').remove();
|
|
}
|
|
},
|
|
|
|
clean: function() {
|
|
this._destroyTipsy();
|
|
cdb.core.View.prototype.clean.call(this);
|
|
}
|
|
|
|
})
|