/*
* Copyright 2024 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.
*/
/**
* Class defining the pilotage dashboard tool
*/
Ext.define('Ametys.plugins.odf.pilotage.tool.PilotageDashboardTool', {
extend: "Ametys.tool.Tool",
/**
* @property {String} _catalog
* @private
*/
/**
* @property {String} _orgUnit
* @private
*/
/**
* @property {Boolean} _isRulesEnabled
* @private
*/
statics: {
/**
* @static
* Open the program search tool
* @param {String} catalog The catalog
* @param {String[]} orgUnit The orgUnit
* @param {String} pilotageStatus The pilotage status
*/
openProgramSearchTool: function(catalog, orgUnit, pilotageStatus)
{
var params = {
startSearchAtOpening: true,
values: {
"reference-orgUnit-eq": orgUnit && orgUnit.trim() != "" ? [orgUnit] : [],
"reference-catalog-eq": catalog,
"reference-mccPilotageStatus-eq": pilotageStatus
},
"id": "search-ui.program-pilotage"
};
Ametys.tool.ToolsManager.openTool('uitool-odf-education', params);
},
/**
* @static
* Open the container search tool
* @param {String} catalog The catalog
* @param {String} yearId The year id
* @param {String[]} orgUnit The orgUnit
* @param {String} thematicId The thematic id
* @param {String} mccStatus The MCC status
* @param {String} invalidData true to get invalid data
*/
openContainerSearchTool: function(catalog, yearId, orgUnit, thematicId, mccStatus, invalidData)
{
var values = {
"reference-parentOrgunits-eq": orgUnit && orgUnit.trim() != "" ? [orgUnit] : [],
"reference-catalog-eq": catalog,
"reference-overridenThematics-eq": thematicId,
"reference-nature-eq": yearId,
"reference-mccWorkflowStatus-eq": mccStatus && mccStatus.trim() != "" ? [mccStatus] : []
}
if (invalidData)
{
values["reference-invalidData-eq"] = true
}
var params = {
startSearchAtOpening: true,
values: values,
"id": "search-ui.container-pilotage"
};
Ametys.tool.ToolsManager.openTool('uitool-odf-container-search', params);
},
},
createPanel: function()
{
this._panel = Ext.create('Ext.Panel', {
cls: 'pilotage-dashboard-tool',
dockedItems: this._getTopPanel(),
scrollable: true,
items: [
{
xtype: 'container',
layout: {
type: 'hbox',
align: 'stretch'
},
items: [
this._getPilotageMCCWorkflowStatsPanel(),
{
xtype: 'tbspacer',
flex: 0.01
},
this._getPilotageWorkflowStatsPanel()
]
},
this._getPilotageRulesStatsPanel()
]
});
return this._panel;
},
/**
* @private
* Get the top panel for filters
* @return {Ext.Panel} the top panel
*/
_getTopPanel: function ()
{
let store = Ext.create('Ext.data.Store', {
autoLoad: true,
proxy: {
type: 'ametys',
role: 'org.ametys.plugins.odfpilotage.dashboard.PilotageDashboardHelper',
methodName: 'getOrgUnits',
reader: {
type: 'json',
rootProperty: 'orgUnits'
}
},
listeners: {
load: {
fn: function(store, values)
{
if (values.length > 0)
{
this._panel.down("#orgUnits").setValue(values[0].id)
}
},
scope: this
}
},
fields: [
{name: 'id', mapping: 'id'},
{name: 'label', mapping: 'label'}
],
sorters: [
{property: 'label', direction:'ASC'}
]
});
return Ext.create({
dock: 'top',
xtype: 'container',
layout: {
type: 'hbox',
},
cls: 'top',
items: [
Ametys.odf.catalog.CatalogDAO.createComboBox({
name: 'catalog',
labelWidth: 60,
fieldLabel: "{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_DASHBOARD_FILTER_CATALOG_LABEL}}",
itemId: 'catalog',
allowBlank: false,
cls: 'ametys catalogs',
listeners: {
change: {
fn: function(select) {
this._catalog = select.value;
this.refresh();
},
scope: this
}
}
}),
Ext.create('Ext.form.field.ComboBox', {
cls: 'ametys orgunits',
labelWidth: 74,
forceSelection: true,
editable: false,
triggerAction: 'all',
width: 450,
queryMode: 'local',
fieldLabel: "{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_DASHBOARD_FILTER_ORGUNITS_LABEL}}",
name: 'orgUnits',
itemId: 'orgUnits',
store: store,
listeners: {
change: {
fn: function(select) {
this._orgUnit = select.getValue();
this.refresh();
},
scope: this
}
},
valueField: 'id',
displayField: 'label',
})
]
});
},
/**
* @private
* Get the rules stats panel
* @return {Ext.Panel} the rules stats panel
*/
_getPilotageRulesStatsPanel: function()
{
this._rulesStatsStore = Ext.create('Ext.data.Store', {
proxy: {
type: 'ametys',
role: 'org.ametys.plugins.odfpilotage.dashboard.PilotageDashboardHelper',
methodName: 'getRulesStats',
methodArguments: ['catalog', 'orgUnit'],
reader: {
type: 'json'
}
},
fields: [
{name: 'thematic', convert: Ext.bind(Ametys.plugins.cms.search.SearchGridHelper.convertContent, null, ['thematic'], true)},
{name: 'thematicTitle'},
{name: 'regime'},
{name: 'nbSessions'},
{name: 'pourcent'},
{name: 'number'},
{name: 'total'},
{name: 'hasRight'}
],
listeners: {
beforeload: {fn: this._onPilotageStatsStoreBeforeLoad, scope: this}
}
});
this._rulesStatsGrid = Ext.create('Ext.grid.Panel',{
title : "{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_DASHBOARD_RULES_STATS_PANEL_TITLE}}",
cls: 'rules-stats-panel',
scrollable: true,
maxHeight: 280,
minHeight: 280,
hidden: true,
store : this._rulesStatsStore,
columns: [
{header: "{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_DASHBOARD_RULES_STATS_PANEL_THEMATIC_COLUMN_LABEL}}", menuDisabled : true, sortable: false, flex: 1, renderer: Ext.bind(this._renderThematic, this), dataIndex: 'thematic'},
{header: "{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_DASHBOARD_RULES_STATS_PANEL_REGIMES_COLUMN_LABEL}}", menuDisabled : true, sortable: false, flex: 1, dataIndex: 'regime', renderer: Ext.bind(this._renderRegime, this)},
{header: "{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_DASHBOARD_RULES_STATS_PANEL_NUMBER_OF_SESSIONS_COLUMN_LABEL}}", menuDisabled : true, sortable: false, flex: 1, dataIndex: 'nbSessions', renderer: Ext.bind(this._renderNbSessions, this)},
{header: "{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_DASHBOARD_RULES_STATS_PANEL_NUMBER_COLUMN_LABEL}}", menuDisabled : true, sortable: false, width: 300, dataIndex: 'number', renderer: Ext.bind(this._renderNbContainers, this)},
]
});
return this._rulesStatsGrid;
},
/**
* @private
* Get the pilotage workflow stats panel
* @return {Ext.Panel} the pilotage workflow stats panel
*/
_getPilotageWorkflowStatsPanel: function ()
{
this._pilotageWorkflowStatsStore = Ext.create('Ext.data.Store', {
proxy: {
type: 'ametys',
role: 'org.ametys.plugins.odfpilotage.dashboard.PilotageDashboardHelper',
methodName: 'getPilotageWorkflowStats',
methodArguments: ['catalog', 'orgUnit'],
reader: {
type: 'json'
}
},
fields: [
{name: 'label'},
{name: 'number'},
{name: 'pourcent'},
{name: 'status'},
{name: 'total'},
{name: 'type'},
{name: 'attributName'}
],
groupField: 'type',
listeners: {
beforeload: {fn: this._onPilotageStatsStoreBeforeLoad, scope: this}
}
});
this._pilotageWorkflowStatsGrid = Ext.create('Ext.grid.Panel',{
title : "{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_DASHBOARD_WORKFLOW_STATS_PANEL_TITLE}}",
flex: 1,
minHeight: 280,
store : this._pilotageWorkflowStatsStore,
columns: [
{header: "{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_DASHBOARD_WORKFLOW_STATS_PANEL_LABEL_COLUMN_LABEL}}", menuDisabled : true, sortable: false, flex: 1, dataIndex: 'label', renderer: Ext.bind(this._renderProgramLabel, this)},
{header: "{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_DASHBOARD_WORKFLOW_STATS_PANEL_NUMBER_COLUMN_LABEL}}", menuDisabled : true, sortable: false, width: 300, dataIndex: 'number', renderer: Ext.bind(this._renderNbPrograms, this)}
],
// Grouping by type
features: [
{
ftype: 'grouping',
enableGroupingMenu: false,
groupHeaderTpl: [
'{name:this.typeLabel}',
{
typeLabel: function() {
return "{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_DASHBOARD_WORKFLOW_STATS_PANEL_GROUP_PROGRAM}}";
}
}
]
}
]
});
return this._pilotageWorkflowStatsGrid;
},
/**
* @private
* Get the pilotage MCC workflow stats panel
* @return {Ext.Panel} the pilotage MCC workflow stats panel
*/
_getPilotageMCCWorkflowStatsPanel: function ()
{
this._pilotageMCCWorkflowStatsStore = Ext.create('Ext.data.Store', {
proxy: {
type: 'ametys',
role: 'org.ametys.plugins.odfpilotage.dashboard.PilotageDashboardHelper',
methodName: 'getPilotageMCCWorkflowStats',
methodArguments: ['catalog', 'orgUnit'],
reader: {
type: 'json'
}
},
fields: [
{name: 'label'},
{name: 'number'},
{name: 'pourcent'},
{name: 'status'},
{name: 'total'},
{name: 'type'},
{name: 'attributName'}
],
groupField: 'type',
listeners: {
beforeload: {fn: this._onPilotageStatsStoreBeforeLoad, scope: this}
}
});
this._pilotageMCCWorkflowStatsGrid = Ext.create('Ext.grid.Panel',{
title : "{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_DASHBOARD_MCC_WORKFLOW_STATS_PANEL_TITLE}}",
flex: 1,
minHeight: 280,
store : this._pilotageMCCWorkflowStatsStore,
columns: [
{header: "{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_DASHBOARD_MCC_WORKFLOW_STATS_PANEL_LABEL_COLUMN_LABEL}}", menuDisabled : true, sortable: false, flex: 1, dataIndex: 'label', renderer: Ext.bind(this._renderContainerLabel, this)},
{header: "{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_DASHBOARD_MCC_WORKFLOW_STATS_PANEL_NUMBER_COLUMN_LABEL}}", menuDisabled : true, sortable: false, width: 300, dataIndex: 'number', renderer: Ext.bind(this._renderNbContainers, this)}
],
// Grouping by type
features: [
{
ftype: 'grouping',
enableGroupingMenu: false,
groupHeaderTpl: [
'{name:this.typeLabel}',
{
typeLabel: function(name) {
switch (name) {
case "program":
return "{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_DASHBOARD_MCC_WORKFLOW_STATS_PANEL_GROUP_PROGRAM}}";
case "container":
default:
return "{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_DASHBOARD_MCC_WORKFLOW_STATS_PANEL_GROUP_CONTAINER}}";
}
}
}
]
}
]
});
return this._pilotageMCCWorkflowStatsGrid;
},
/**
* Function to render a thematic content value
* @param {Object} value The data value
* @param {Object} metaData A collection of metadata about the current cell
* @param {Ext.data.Model} record The record
* @param {Number} rowIndex The index of the current row
* @param {Number} colIndex The index of the current column
* @param {Ext.data.Store} store The store
* @param {Ext.view.View} view The current view
*/
_renderThematic: function (value, metaData, record, rowIndex, colIndex, store, view)
{
return record.data.hasRight
? Ametys.plugins.cms.search.SearchGridHelper.renderContent(value, metaData, record, rowIndex, colIndex, store, view, 'thematic')
: record.data.thematicTitle;
},
/**
* @private
* Render the pilotage number of programs
* @param {Object} value The data value
* @param {Object} metaData A collection of metadata about the current cell
* @param {Ext.data.Model} record The record
* @return {String} the render
*/
_renderNbPrograms: function(value, metaData, record)
{
let number = record.data.number;
let tooltip = number > 1
? Ext.String.format("{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_DASHBOARD_WORKFLOW_STATS_NB_PROGRAM_SEVERAL_TOOLTIP}}", record.data.number, record.data.total)
: Ext.String.format("{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_DASHBOARD_WORKFLOW_STATS_NB_PROGRAM_ONE_TOOLTIP}}", record.data.number, record.data.total);
return "<a title=\"" + tooltip + "\" href='javascript:void(0)' onclick='Ametys.plugins.odf.pilotage.tool.PilotageDashboardTool.openProgramSearchTool(\"" + this._catalog + "\", \"" + this._orgUnit + "\", \"" + record.data.status + "\")'>" + value + "</a> (" + record.data.pourcent + " %)";
},
/**
* @private
* Render the pilotage number of containers
* @param {Object} value The data value
* @param {Object} metaData A collection of metadata about the current cell
* @param {Ext.data.Model} record The record
* @return {String} the render
*/
_renderNbContainers: function(value, metaData, record)
{
let number = record.data.number;
let tooltip = number > 1
? Ext.String.format("{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_DASHBOARD_RULES_STATS_NB_CONTAINER_SEVERAL_TOOLTIP}}", record.data.number, record.data.total)
: Ext.String.format("{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_DASHBOARD_RULES_STATS_NB_CONTAINER_ONE_TOOLTIP}}", record.data.number, record.data.total);
return record.data.thematic
? "<a title=\"" + tooltip + "\" href='javascript:void(0)' onclick='Ametys.plugins.odf.pilotage.tool.PilotageDashboardTool.openContainerSearchTool(\"" + this._catalog + "\", \"" + this._yearId + "\", \"" + this._orgUnit + "\", \"" + record.data.thematic + "\")'>" + value + "</a> (" + record.data.pourcent + " %)"
: record.data.attributName == 'invalidData'
? "<a title=\"" + tooltip + "\" href='javascript:void(0)' onclick='Ametys.plugins.odf.pilotage.tool.PilotageDashboardTool.openContainerSearchTool(\"" + this._catalog + "\", \"" + this._yearId + "\", \"" + this._orgUnit + "\", null, \"" + record.data.status + "\", true)'>" + value + "</a> (" + record.data.pourcent + " %)"
: "<a title=\"" + tooltip + "\" href='javascript:void(0)' onclick='Ametys.plugins.odf.pilotage.tool.PilotageDashboardTool.openContainerSearchTool(\"" + this._catalog + "\", \"" + this._yearId + "\", \"" + this._orgUnit + "\", null, \"" + record.data.status + "\", false)'>" + value + "</a> (" + record.data.pourcent + " %)";
},
/**
* @private
* Render the label for container workflow status
* @param {Object} value The data value
* @param {Object} metaData A collection of metadata about the current cell
* @param {Ext.data.Model} record The record
* @return {String} the render
*/
_renderContainerLabel: function(value, metaData, record)
{
let invalidDataTooltip = Ext.String.format("{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_DASHBOARD_WORKFLOW_STATS_CONTAINERS_INVALID_DATA_TOOLTIP}}");
let noValidationTooltip = Ext.String.format("{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_DASHBOARD_WORKFLOW_STATS_CONTAINERS_NO_VALIDATION_TOOLTIP}}");
return record.data.attributName == 'invalidData'
? "<span title=\"" + invalidDataTooltip + "\">" + value + "<span>"
: record.data.status == "NONE"
? "<span title=\"" + noValidationTooltip + "\">" + value + "<span>"
: value;
},
/**
* @private
* Render the label for program workflow status
* @param {Object} value The data value
* @param {Object} metaData A collection of metadata about the current cell
* @param {Ext.data.Model} record The record
* @return {String} the render
*/
_renderProgramLabel: function(value, metaData, record)
{
let noValidationTooltip = Ext.String.format("{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_DASHBOARD_WORKFLOW_STATS_PROGRAMS_NO_VALIDATION_TOOLTIP}}");
return record.data.status == "NONE"
? "<span title=\"" + noValidationTooltip + "\">" + value + "<span>"
: value;
},
/**
* @private
* Render the regime
* @param {Object} value The data value
* @param {Object} metaData A collection of metadata about the current cell
* @param {Ext.data.Model} record The record
* @return {String} the renderer of regime
*/
_renderRegime: function(value, grid, record)
{
if (value)
{
return value;
}
return "{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_DASHBOARD_RULES_STATS_ALL_REGIME}}";
},
/**
* @private
* Render the number of sessions
* @param {Object} value The data value
* @param {Object} metaData A collection of metadata about the current cell
* @param {Ext.data.Model} record The record
* @return {String} the renderer of the number of sessions
*/
_renderNbSessions: function(value, grid, record)
{
if (value)
{
return value;
}
return "{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_DASHBOARD_RULES_STATS_ALL_NB_SESSION}}";
},
/**
* Set the filter parameters before loading the store.
* @param {Ext.data.Store} store The store.
* @param {Ext.data.operation.Operation} operation The Ext.data.Operation object that will be passed to the Proxy to load the Store.
* @private
*/
_onPilotageStatsStoreBeforeLoad: function(store, operation)
{
var params = operation.getParams() || {};
operation.setParams(Ext.apply(params, {
catalog: this._catalog,
orgUnit: this._orgUnit
}));
},
refresh: function()
{
this.callParent(arguments);
if (this._isRulesEnabled === undefined || this._yearId === undefined)
{
Ametys.data.ServerComm.callMethod({
role: "org.ametys.plugins.odfpilotage.dashboard.PilotageDashboardHelper",
methodName: "getDashboardInfo",
parameters: [],
callback: {
handler: this._getDashboardInfoCB,
scope: this
},
waitMessage: {
target: this.getContentPanel()
}
});
}
else
{
this._refreshCB(this._isRulesEnabled);
}
},
/**
* Get dashboard information callback
* @param {Object} results the results
* @private
*/
_getDashboardInfoCB: function(results)
{
if (results.error)
{
Ametys.Msg.show({
title: "{{i18n PLUGINS_ODF_PILOTAGE_DASHBOARD_NO_YEAR_ERROR}}",
msg: "{{i18n PLUGINS_ODF_PILOTAGE_DASHBOARD_NO_YEAR_MSG}}",
buttons: Ext.Msg.OK,
icon: Ext.Msg.ERROR
});
}
else
{
this._isRulesEnabled = results.isRulesEnabled;
this._yearId = results.yearId;
this._refreshCB(this._isRulesEnabled);
}
},
/**
* Refresh callback
* @param {Boolean} isRulesEnabled true is rules are enabled
* @private
*/
_refreshCB: function(isRulesEnabled)
{
if (this._catalog)
{
this._reloadStores(isRulesEnabled);
}
else
{
Ametys.odf.catalog.CatalogDAO.getDefaultCatalogName(
[],
function(catalogName) {
this._panel.down("#catalog").setValue(catalogName);
},
{ scope: this }
);
}
},
/**
* Reload all the store
* @param {Boolean} isRulesEnabled true is rules are enabled
* @private
*/
_reloadStores: function(isRulesEnabled)
{
if (isRulesEnabled)
{
this._rulesStatsGrid.show();
this._rulesStatsStore.load({
callback: Ext.bind(function() {
if (this._rulesStatsStore.getCount() > 0)
{
this._rulesStatsGrid.getView().unmask();
}
else
{
this._rulesStatsGrid.getView().mask("{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_DASHBOARD_RULES_STATS_PANEL_NO_RESULT}}", 'ametys-mask-unloading');
}
}, this)
});
}
this._pilotageWorkflowStatsStore.load();
this._pilotageMCCWorkflowStatsStore.load();
},
getMBSelectionInteraction: function()
{
return Ametys.tool.Tool.MB_TYPE_NOSELECTION;
},
});