/*
* Copyright 2022 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 a global consistency report for contents which consistency
* issues.
* @private
*/
Ext.define('Ametys.plugins.cms.content.tool.GlobalContentConsistencyTool', {
extend: "Ametys.plugins.cms.search.AbstractFacetedSearchTool",
statics: {
renderContentType: function(value, _metaData, _record, _rowIndex, _colIndex, _store, _view, _dataIndex)
{
if (Ext.isEmpty(value) || Ext.Object.isEmpty(value))
{
return '';
}
var values = Ext.Array.from(value);
var html = '';
for (var i=0; i < values.length; i++)
{
var cTypeValue = values[i];
var label = cTypeValue.label;
var smallIcon = cTypeValue.smallIcon;
var iconGlyph = cTypeValue.iconGlyph;
var iconDecorator = cTypeValue.iconDecorator;
if (!Ext.isEmpty(html))
{
html += '<br/>';
}
if (iconGlyph)
{
html += `<span class="a-grid-glyph ${iconGlyph} ${iconDecorator ? " " + iconDecorator : ""}"></span>${label}`
}
// use small icon as fallback
else
{
html += `<img src="${Ametys.CONTEXT_PATH + smallIcon}" class="a-grid-icon"/>${label}`;
}
}
return html;
}
},
constructor: function()
{
this.callParent(arguments);
Ametys.message.MessageBus.on(Ametys.message.Message.TASK_ENDED, this._onTaskEnded, this);
},
_onTaskEnded: function(message)
{
var taskTarget = message.getTarget(Ametys.message.MessageTarget.TASK);
if (taskTarget != null && taskTarget.getParameters().schedulable == "org.ametys.web.content.consistency.CheckContentConsistencySchedulable");
{
this.showOutOfDate();
}
},
getMBSelectionInteraction: function()
{
return Ametys.tool.Tool.MB_TYPE_ACTIVE;
},
// Open contistency tool at the opening
onOpen: function ()
{
this.callParent (arguments);
// Try to open the check consistency tool if available
if (Ametys.tool.ToolsManager.getFactory('uitool-consistency'))
{
Ametys.tool.ToolsManager.openTool ('uitool-consistency');
}
},
/**
* @protected
* Get the config to be used to create the store.
* @return {Object} The config object
*/
_getStoreCfg: function()
{
return {
remoteSort: true,
sortOnLoad: true,
listeners: {
'beforeload': {fn: this._onBeforeLoad, scope: this},
'load': {fn: this._onLoad, scope: this}
}
};
},
_getResultGridCfg: function(store)
{
var cfg = this.callParent (arguments);
return Ext.Object.merge(cfg, {
listeners: {
'itemdblclick': {fn: function (view, record, item, index, e) { this.openContent(record); }, scope: this}
}
})
},
openContent: function(record)
{
Ametys.tool.ToolsManager.openTool('uitool-content', {'id' : record.get('contentId')});
},
/**
* Function called before loading the store
* @param {Ext.data.Store} store The store
* @param {Ext.data.operation.Operation} operation The object that will be passed to the Proxy to load the store
* @protected
*/
_onBeforeLoad: function(_store, operation)
{
if (this.grid && !this._updatingModel && (!(this.form instanceof Ametys.form.ConfigurableFormPanel) || this.form.isFormReady()))
{
this.grid.getView().unmask();
if (!this.form.isValid())
{
this._stopSearch();
return false;
}
operation.setParams( Ext.apply(operation.getParams() || {}, {
model: this._modelId,
values: this.form.getJsonValues()
}));
// Facet handling
this.facetValues = this._faceting ? this.getFacetValues() : {};
operation.setParams(Ext.apply(operation.getParams(), {
facetValues: this.facetValues,
}));
this._facets = null;
}
else
{
// avoid use less requests at startup (applyState...)
return false;
}
},
_onLoad: function (store, _records, _successful, operation)
{
if (operation.aborted)
{
// Load has been canceled. Do nothing.
return;
}
// Hack to process groups locally even if remoteSort is enabled.
store.getData().setAutoGroup(true);
// Load facet store
if (this.facetPanel.isVisible() && this._facets)
{
if (!this._faceting)
{
// TODO Create a brand new memory proxy with the data and set it, instead of just changing the 'data' property?
this.facetPanel.getStore().getProxy().setData(this._facets);
this.facetPanel.getStore().load();
this.facetPanel.getRootNode().expand();
}
else
{
this._updateFacetPanel(this._facets);
}
}
this._setGridDisabled(false);
},
/**
* @protected
* Implement this method with your own logic for retrieving information about search criteria and columns.
* It should call {@link #_configureSearchTool}, either directly, or as a callback function after a server call, so as to finish the process of drawing and configure the search tool.
* @param {Boolean} force True to force the update of the model and columns even if not needed
*/
_retrieveCriteriaAndColumns: function(force)
{
Ametys.data.ServerComm.callMethod({
role: "org.ametys.cms.content.consistency.ContentConsistencySearcher",
methodName: "getModel",
callback: {
handler: this._getSearchModelCb,
scope: this,
},
errorMessage: {
msg: "{{i18n plugin.cms:UITOOL_SEARCH_ERROR}}",
category: Ext.getClassName(this)
}
});
},
_getSearchModelCb: function(result)
{
this._configureSearchTool({"fieldsetForDisplay" : {elements : result['criteria'], role: "fieldset"}}, result, {});
},
/**
* @protected
* Get the config to be used to create the reader for the store.
* @return {Object} The config object
*/
_getReaderCfg: function()
{
return {
type: 'json',
rootProperty: 'consistencyResults',
transform: {
fn: this._transformSearchData,
scope: this
}
};
},
/**
* Transform search data before loading it. Used to extract facet results.
* @param data {Object} The original data object.
* @return {Object} The transformed data object.
* @private
*/
_transformSearchData: function(data)
{
this._facets = data.facets;
// Return the data untouched.
return data;
},
/**
* @protected
* Listener when the selection has changed in result grid.
* @param {Ext.selection.Model} sm the selection model
* @param { Ext.data.Model[]} selected the selected record
*/
_onSelectionChanged: function(sm, selected)
{
this.sendCurrentSelection(selected);
},
sendCurrentSelection: function(selection)
{
if (selection == null)
{
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 }
}
});
},
/**
* Get the JS parameters for export
* @return {Object} the parameters
*/
getSearchParametersForExport: function ()
{
var params = {}
params.values = this.form.getJsonValues();
params.columns = this._getExportColumns();
params.sort = this.getEncodedSortersForExport() || undefined;
params.model = this._modelId;
params.facetValues = this.getFacetValues();
return params;
},
/**
* Get the array of current active sorters.
* @return {String} The list of sorters. Entry of the list are object with keys 'property' and 'direction' (optionnal)
*/
getCurrentSorters: function()
{
var sorters = [];
this.store.getSorters().each (function (sorter) {
sorters.push({property: sorter.getProperty(), direction: sorter.getDirection()})
});
return sorters;
},
/**
* Get the JSON encoded array of sorters.
* @return {String} A JSON String representing the list of sorters. Entry of the list are object with keys 'property' and 'direction' (optionnal)
*/
getEncodedSortersForExport: function()
{
return Ext.encode(this.getCurrentSorters() || []);
},
/**
* Get the list of columns to export
* @return {String[]} The id of columns in a Array
*/
_getExportColumns: function()
{
var columns = [];
Ext.Array.forEach(this.grid.getColumns(), function (column) {
if (column.dataIndex && column.isVisible())
{
columns.push(column.dataIndex);
}
});
return columns;
}
});