/*
* Copyright 2019 Anyware Services
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* This tool displays the global validation report for programs
* @private
*/
Ext.define('Ametys.plugins.odf.validation.GlobalValidationReportTool', {
extend: "Ametys.tool.Tool",
/**
* @private
* @property {Ext.LoadMask} _mask A mask bound to the grid to display information to the user
*/
/**
* @private
* @property {Ext.grid.Panel} _grid the grid panel of the tool
*/
/**
* @private
* @property {Ext.XTemplate} _hintTpl The template for the list of referenced contents
*/
_hintTpl : Ext.create('Ext.XTemplate', "{{i18n PLUGINS_ODF_UITOOL_GLOBAL_VALIDATION_HINT}}"),
statics: {
/**
* @property {Number}
* @readonly
* @static
* The number of records to display by 'page'
*/
PAGE_SIZE: 50,
/**
* @static
* Show the list of invalidated contents computed by the last report
* @param {String} contentId The content id
* @param {String} contentTitle The content title
*/
showInvalidatedContents: function(contentId, contentTitle)
{
Ametys.data.ServerComm.callMethod({
role: "org.ametys.odf.schedulable.GlobalValidationReport",
methodName: "getInvalidatedContents",
parameters: [contentId],
callback: {
handler: function (invalidatedContents) {
Ametys.odf.helper.Content.showInvalidatedContents({
id: contentId,
title: contentTitle,
invalidatedContents: invalidatedContents
}, null, null, null, "{{i18n PLUGINS_ODF_UITOOL_GLOBAL_VALIDATION_SHOW_INVALIDATED_CONTENTS_DIALOG_HINT1}}");
},
scope: this
},
errorMessage: "{{i18n PLUGINS_ODF_UITOOL_GLOBAL_VALIDATION_SHOW_INVALIDATED_ERROR}}"
});
}
},
getMBSelectionInteraction: function()
{
return Ametys.tool.Tool.MB_TYPE_ACTIVE;
},
constructor: function(config)
{
this.callParent(arguments);
Ametys.message.MessageBus.on(Ametys.message.Message.GLOBAL_VALIDATION_CHECK_STARTED, this._onCheckStart, this);
Ametys.message.MessageBus.on(Ametys.message.Message.GLOBAL_VALIDATION_CHECK_ENDED, this._onCheckEnd, this);
},
createPanel: function()
{
this._createGrid();
return this._grid;
},
sendCurrentSelection: function()
{
var selection = this._grid.getSelectionModel().getSelection();
var contentIds = Ext.Array.map(selection, function(record) {
return record.get('contentId');
});
Ext.create("Ametys.message.Message", {
type: Ametys.message.Message.SELECTION_CHANGED,
targets: {
id: Ametys.message.MessageTarget.CONTENT,
parameters: { ids: contentIds }
}
});
},
setParams: function(params)
{
this.callParent(arguments);
this._refreshData();
},
onClose: function()
{
this.callParent(arguments);
if (this._mask)
{
this._mask.hide();
delete this._mask;
}
},
/**
* @private
* Create the main grid that display the results.
*/
_createGrid: function()
{
this._store = this._createStore();
this._grid = Ext.create('Ext.grid.Panel', {
border: false,
scrollable: true,
stateful: true,
stateId: this.self.getName() + "$grid",
store: this._store,
selModel : {
mode: 'MULTI'
},
forceFit: true,
columns: [
{stateId: 'grid-title', header: "{{i18n PLUGINS_ODF_UITOOL_GLOBAL_VALIDATION_CONTENT_TITLE}}", width: 220, sortable: true, dataIndex: 'title', renderer: Ametys.plugins.cms.search.SearchGridHelper.renderTitle},
{stateId: 'grid-code', header: "{{i18n PLUGINS_ODF_UITOOL_GLOBAL_VALIDATION_CONTENT_CODE}}", width: 120, sortable: true, dataIndex: 'code'},
{stateId: 'grid-catalog', header: "{{i18n PLUGINS_ODF_UITOOL_GLOBAL_VALIDATION_CONTENT_CATALOG}}", width: 150, sortable: true, dataIndex: 'catalog'},
{stateId: 'grid-invalidatedContentsCount', header: "{{i18n PLUGINS_ODF_UITOOL_GLOBAL_VALIDATION_INVALIDATED_CONTENTS_COUNT}}", width: 100, sortable: true, dataIndex: 'invalidatedContentsCount', xtype: 'numbercolumn', format: '0', renderer: this._renderResultCount},
{stateId: 'grid-contributor', header: "{{i18n PLUGINS_ODF_UITOOL_GLOBAL_VALIDATION_CONTENT_CONTRIBUTOR}}", width: 140, sortable: true, dataIndex: 'contributor'},
{stateId: 'grid-lastModified', header: "{{i18n PLUGINS_ODF_UITOOL_GLOBAL_VALIDATION_CONTENT_LASTMODIFIED}}", width: 120, sortable: true, dataIndex: 'lastModified', renderer: Ext.util.Format.dateRenderer(Ext.Date.patterns.FriendlyDateTime)}
],
dockedItems: this._getDockedItems(),
listeners: {
selectionchange: {fn: this._onSelectionChange, scope: this},
itemdblclick: {fn: this._onItemDblClick, scope: this}
}
});
},
/**
* @private
* Create the store that the grid should use as its data source.
* @return {Ext.data.Store} The created store
*/
_createStore: function ()
{
return Ext.create('Ext.data.Store', {
autoLoad: false,
model: 'Ametys.plugins.odf.validation.GlobalValidationReportTool.ProgramEntry',
proxy: {
type: 'ametys',
plugin: 'odf',
url: 'global-validation/programs.xml',
reader: {
type: 'xml',
keepRawData: true,
rootProperty: 'programs',
record: 'program',
totalProperty: 'total'
}
},
pageSize: Ametys.plugins.odf.validation.GlobalValidationReportTool.PAGE_SIZE,
sortOnLoad: true,
sorters: [{property: 'title', direction:'ASC'}],
listeners: {
load: {fn: this._onLoad, scope: this}
}
});
},
/**
* @private
* Returns the docked items configuration
* @return {Object/Object[]} the items to dock
*/
_getDockedItems: function()
{
return [{
dock: 'top',
xtype: 'component',
itemId: 'hint',
hidden: true,
ui: 'tool-hintmessage',
html: "{{i18n PLUGINS_ODF_UITOOL_GLOBAL_VALIDATION_NO_REPORT}}"
},
{
// paging bottom bar
xtype: 'pagingtoolbar',
dock: 'bottom',
store: this._store,
displayInfo: true,
displayMsg: "{{i18n PLUGINS_ODF_UITOOL_GLOBAL_VALIDATION_RESULT_1}}{0}{{i18n PLUGINS_ODF_UITOOL_GLOBAL_VALIDATION_RESULT_2}}{1}{{i18n PLUGINS_ODF_UITOOL_GLOBAL_VALIDATION_RESULT_3}}{2}",
emptyMsg: "{{i18n PLUGINS_ODF_UITOOL_GLOBAL_VALIDATION_NO_RESULT}}"
}]
},
/**
* Fires a event of selection on message bus, from the selected contents in the grid.
* @param {Ext.selection.Model} model The selection model
* @param {Ext.data.Model[]} selected The selected records
* @private
*/
_onSelectionChange: function(model, selected)
{
this.sendCurrentSelection();
},
/**
* Open the corresponding content
* @param {Ext.view.View} view The view
* @param {Ext.data.Model} record The record that belongs to the item
* @param {HTMLElement} item the item's element
* @private
*/
_onItemDblClick: function(view, record, item)
{
var params = {
id: record.get('contentId'),
mode: 'view'
}
Ametys.tool.ToolsManager.openTool('uitool-content', params);
},
/**
* Fill the grid with the contents
* @private
*/
_refreshData: function()
{
this._grid.getView().unmask();
this._grid.getStore().loadPage(1);
},
/**
* Called whenever the store load data
* @param {Ext.data.Store} store the store
* @param {Ext.data.Model[]} records An array of records
* @param {Boolean} success True if the operation was successful.
* @private
*/
_onLoad: function(store, records, success)
{
if (!success)
{
Ametys.Msg.alert(
"{{i18n PLUGINS_ODF_UITOOL_GLOBAL_VALIDATION_ERROR_TITLE}}",
"{{i18n PLUGINS_ODF_UITOOL_GLOBAL_VALIDATION_ERROR_MSG}}"
);
return;
}
var hintPanel = this._grid.getDockedItems('[itemId="hint"]')[0];
var xmlRawData = store.getProxy().reader.rawData;
if (xmlRawData.nodeName == 'file-not-found')
{
this._grid.getView().mask("{{i18n PLUGINS_ODF_UITOOL_GLOBAL_VALIDATION_NO_REPORT}}", 'ametys-mask-unloading');
hintPanel.setVisible(false);
}
else
{
if (records.length == 0)
{
this._grid.getView().mask("{{i18n PLUGINS_ODF_UITOOL_GLOBAL_VALIDATION_NO_RESULT}}", 'ametys-mask-unloading');
}
var date = Ext.util.Format.date(xmlRawData.getAttribute("date"), Ext.Date.patterns.FriendlyDateTime);
var hintMsg = this._hintTpl.apply({date: date, count: this._store.getTotalCount()});
hintPanel.update(hintMsg);
hintPanel.setVisible(true);
}
},
/**
* Bus message listener for message of type : Ametys.message.Message.GLOBAL_VALIDATION_CHECK_STARTED
* Displays an informative message and recursively verify if the global validation
* check process is still running on the server.
* @param {Ametys.message.Message} message the bus message
* @private
*/
_onCheckStart: function(message)
{
this._grid.getView().unmask();
this._grid.getView().mask("{{i18n PLUGINS_ODF_UITOOL_GLOBAL_VALIDATION_WAIT_MESSAGE}}");
Ext.Function.defer(this._checkEngine, 1000, this);
},
/**
* Bus message listener for message of type : Ametys.message.Message.GLOBAL_VALIDATION_CHECK_ENDED
* Refresh the grid data.
* @param {Ametys.message.Message} message the bus message
* @private
*/
_onCheckEnd: function(message)
{
this._grid.getView().unmask();
this._refreshData();
},
/**
* Verify if the global validation check process is still running on the server.
* @private
*/
_checkEngine: function()
{
Ametys.data.ServerComm.callMethod({
role: "org.ametys.odf.schedulable.GlobalValidationReport",
methodName: "isRunning",
parameters: [],
callback: {
handler: this._checkEngineCb,
scope: this,
arguments: []
},
errorMessage: "{{i18n PLUGINS_ODF_UITOOL_GLOBAL_VALIDATION_CHECK_ENGINE_ERROR}}"
});
},
/**
* #_checkEngine callback function.
* Fire the Ametys.message.Message.GLOBAL_VALIDATION_CHECK_ENDED when the server process has ended.
* @param {Boolean} running the server's response. True if check engine is running
* @private
*/
_checkEngineCb: function(running)
{
if (running == null)
{
// Stop to recursively checks if the process is still running.
this._onCheckEnd();
return;
}
if (!running)
{
// Send a message on the bus to tell everyone that the server process has ended.
Ext.create("Ametys.message.Message", { type: Ametys.message.Message.GLOBAL_VALIDATION_CHECK_ENDED });
return;
}
Ext.defer(this._checkEngine, 1000, this);
},
/**
* Function to render the number of invalidated contents in the grid.
* @param {Object} value The data value
* @param {Object} metaData A collection of metadata about the current cell
* @param {Ext.data.Model} record The record
*/
_renderResultCount: function(value, metaData, record)
{
var escapedTitle = record.get('title').replace(/"/g, '"').replace(/'/g, "'");
return `<a href='javascript:(function(){Ametys.plugins.odf.validation.GlobalValidationReportTool.showInvalidatedContents("${record.get('contentId')}", "${escapedTitle}")})()'>${value}</a>`;
}
});
Ext.define('Ametys.plugins.odf.validation.GlobalValidationReportTool.ProgramEntry', {
extend: 'Ext.data.Model',
schema: 'default',
fields: [
{name: 'contentId', mapping: '@id'},
{name: 'title', mapping: '@title', type: 'string'},
{name: 'iconSmall', mapping: '@iconSmall'},
{name: 'iconGlyph', mapping: '@iconGlyph'},
{name: 'invalidatedContentsCount', mapping: '@invalidated-contents-count'},
{name: 'catalog', mapping: 'catalog'},
{name: 'code', mapping: 'code'},
{name: 'lastModified', mapping: 'lastModified'},
{name: 'contributor', mapping: 'contributor/sortablename'}
]
});