/*
* Copyright 2025 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.
*/
/**
* MCCC to select skills weights on the whole program at once
* @private
*/
Ext.define('Ametys.plugins.odf.pilotage.tool.MicroSkillsWeightTreeGridPanel', {
extend: 'Ametys.plugins.odf.pilotage.tool.MicroSkillsTreeGridPanel',
statics: {
_microSkillWeightRenderer: function(value, metadata, record, rowIndex, cellIndex, store, view)
{
let headerCt = this.getHeaderContainer();
let column = headerCt.getHeaderAtIndex(cellIndex);
if (!(record.data['notEditableData'] === true)
&& !(record.data['notEditableDataIndex'] && Ext.Array.contains(record.data['notEditableDataIndex'], column.dataIndex))
&& !(record.data[column.dataIndex + '_external_status'] == 'external')
&& (record.get("mccSession1") || record.get("mccSession2")))
{
metadata.tdCls += ' editable';
}
let educationalPath = record.getPath("contentId", ";").substring(1);
if (!value)
{
if ((record.get("contenttypesIds") || []).includes("org.ametys.plugins.odf.Content.course"))
{
function getSession(session)
{
if (!session) return "";
let s = "<div class='session' data-ametys-note='" + session + "/0/0'></div>";
s += "<div>";
let m = 0;
for (let evaluations of Object.keys(session.data))
{
let d = session.data[evaluations];
if (d.common || d.path == educationalPath)
{
s += "<div class='epreuve' data-ametys-note='" + session + "/" + m + "/0'></div>"
s += "<div>";
for (let n = 0; n < d.notes.length; n++)
{
// let note = d.notes[n];
s += "<div class='note' data-ametys-note='" + session + "/" + m + "/" + n + "'></div>"
}
s += "</div>";
m++;
}
}
s += "</div>";
if (m == 0)
{
return "";
}
else
{
return s;
}
}
if (record.get("mccSession1") || record.get("mccSession2"))
{
return "<div class='value'><div class='course'></div>"
+ getSession(record.get("mccSession1"))
+ getSession(record.get("mccSession2"))
+ "</div>"
}
else
{
return "";
}
}
else
{
return "";
}
}
let s = "";
s += "<div class='value'>"
s += "<div class='course'></div>"; // space for the ELP name
s += "<div>"
for (let session of Object.keys(value))
{
let ss = "";
ss += "<div class='session' data-ametys-note='" + session + "/0/0'></div>"; // space for the session name
ss += "<div>"
let m = 0;
for (let evalNum of Object.keys(value[session].data))
{
let d = value[session].data[evalNum];
if (d.common || d.path == educationalPath)
{
ss += "<div class='evaluation' data-ametys-note='" + session + "/" + m + "/0'></div>"; // space for the evaluation name
ss += "<div>"
let n = 0;
for (let note of d.notes)
{
ss += "<div class='note' data-ametys-note='" + session + "/" + m + "/" + n + "' data-qtip=''>"; // The empty data qtip is here to avoid the auto-qtip, that is wrongly present because of the css hack to have the cell overlaping the parent padding
let ssValue = d.common ? note[educationalPath] : note[""];
if (ssValue) {
ss += ssValue + "%";
}
else {
ss += "-";
}
ss += "</div>";
n++;
}
ss += "</div>";
m++;
}
}
ss += "</div>"
if (m > 0)
{
s += ss;
}
}
s += "</div>"
s += "</div>"
return s;
}
},
constructor: function(config)
{
config.cls = Ext.Array.from(config.cls);
config.cls.push('microskillsweighttreegrid');
this.callParent(arguments);
var me = this;
var view = this.view.lockedView || this.view;
view.cellTpl.html = view.cellTpl.html.replace('</div></td>',
'<tpl if="values.column.getItemId().startsWith(\'tree\') && this.isCourse(values.record) && this.hasSession(values.record)">' // startsWith(\'tree\') to apply to the main column only
+ '{% out.push(this.getSessionData(values.record)) %}'
+ '</tpl>'
+ '</div></td>');
view.cellTpl.hasSession = function(record) {
return record.get("mccSession1") || record.get("mccSession2");
};
view.cellTpl.getSessionData = function(record) {
let educationalPath = record.getPath("contentId", ";").substring(1);
function computePadding(record) {
return record != null ? 20 + computePadding(record.parentNode) : 40; // First level is 20 + 20 for the missing image
}
function getSession(session)
{
if (!session) return "";
let s = "<div class='session'>" + session.label + "</div>";
s += "<div data-qtip=''>";
let i = 1;
for (let evaluations of Object.keys(session.data))
{
let d = session.data[evaluations];
if (d.common || d.path == educationalPath)
{
s += "<div class='epreuve'>{{i18n PLUGINS_ODF_PILOTAGE_RIGHTS_MICROSKILLSWEIGHT_TREE_EPREUVE}} " + i++ + (d.label ? " - " + d.label : "") + "</div>"
s += "<div data-qtip=''>";
for (let n = 0; n < d.notes.length; n++)
{
let note = d.notes[n];
s += "<div class='note'>{{i18n PLUGINS_ODF_PILOTAGE_RIGHTS_MICROSKILLSWEIGHT_TREE_NOTES}} " + (n+1)
+ ((d.notes.length > 1 || note.ponderation != 100) ? " (" + note.ponderation + "%)" : "")
+ (note.label ? " - " + note.label : "") + "</div>"
}
s += "</div>";
}
}
s += "</div>";
if (i == 1)
{
return "";
}
else
{
return s;
}
}
return "<div class='tree' data-qtip='' style='padding-left: " + computePadding(record) + "px;'>"
+ getSession(record.get("mccSession1"))
+ getSession(record.get("mccSession2"))
+ "</div>"
}
view.cellTpl.isCourse = function(record) {
return (record.get("contenttypesIds") || []).includes("org.ametys.plugins.odf.Content.course");
};
},
_toMicroSkillsColumns: function(microSkills)
{
let json = [];
let i = 0;
for (let [key, microSkill] of Object.entries(microSkills))
{
let cfg = {
text: microSkill.title,
headerId: microSkill.id, // FIXME workaround for https://issues.ametys.org/browse/CMS-9008 (see https://www.sencha.com/forum/showthread.php?469623-ExtJS-6-5-3-Grid-reconfigure-methods-generates-a-warning&p=1317295#post1317295)
stateId: microSkill.id,
dataIndex: microSkill.id,
align: 'center',
sortable: false,
tooltip: microSkill.title,
hidden: microSkill.archived,
lockable: false,
editable: true,
renderer: Ametys.plugins.odf.pilotage.tool.MicroSkillsWeightTreeGridPanel._microSkillWeightRenderer,
editor: 'edition.notes'
};
json[i++] = cfg;
}
return json;
},
// Override to get available actions from server call
_beforeEditContentCB: function(content, record)
{
if (content == null)
{
Ametys.cms.content.EditContentsView.prototype._beforeEditContentCB.apply(this, [content, record]); }
else
{
if (content.getAvailableActions().indexOf(this.workflowEditActionId) != -1)
{
Ametys.cms.content.EditContentsView.prototype._beforeEditContentCB.apply(this, [content, record]);
}
else
{
// Test if edit workflow action id is available for current path
Ametys.data.ServerComm.callMethod({
role: this.getInitialConfig('serverRole'),
methodName: "canEditRepeaterWithPath",
parameters: [
content.getId(),
record.getPath("contentId", ";").substring(1).split(';')
],
callback: {
handler: this._canEditRepeaterWithPathCB,
scope: this,
arguments: {
content: content,
record: record
}
},
errorMessage: true,
waitMessage: false
});
}
}
},
_canEditRepeaterWithPathCB: function (available, args)
{
// Add edit workflow action id to available actions
let availableActions = args.content.getAvailableActions();
if (available)
{
availableActions.push(this.workflowEditActionId);
}
args.content._availableActions = availableActions;
Ametys.cms.content.EditContentsView.prototype._beforeEditContentCB.apply(this, [args.content, args.record]);
},
});