pimcore workflow management - disabling Save and publish - pimcore

In pimcore I tried implementing the workflow management for objects. Workflow is working fine. But, save and publish button are still appearing, how can I remove these features if workflow is enabled. 1. Disabling Save, publish, unpublish and delete to the user if workflow is enabled. 2. Removing same options (save, publish, unpublish and delete) on right clicking the object.

If you want to disable buttons you have to overwrite pimcore object.js(pimcore/static6/js/pimcore/object/object.js) and tree.js(pimcore/static6/js/pimcore/object/tree.js).
First create plugin. Then create object.js in static(Remember to add js paths to plugin.xml) and add code:
pimcore.registerNS("pimcore.object.object");
pimcore.object.object = Class.create(pimcore.object.object, {
getLayoutToolbar : function () {
if (!this.toolbar) {
var buttons = [];
this.toolbarButtons = {};
this.toolbarButtons.save = new Ext.SplitButton({
text: t('save'),
iconCls: "pimcore_icon_save",
scale: "medium",
handler: this.save.bind(this, "unpublish"),
menu:[{
text: t('save_close'),
iconCls: "pimcore_icon_save",
handler: this.unpublishClose.bind(this)
}]
});
this.toolbarButtons.publish = new Ext.SplitButton({
text: t('save_and_publish'),
iconCls: "pimcore_icon_publish",
scale: "medium",
handler: this.publish.bind(this),
menu: [{
text: t('save_pubish_close'),
iconCls: "pimcore_icon_save",
handler: this.publishClose.bind(this)
},
{
text: t('save_only_new_version'),
iconCls: "pimcore_icon_save",
handler: this.save.bind(this, "version")
},
{
text: t('save_only_scheduled_tasks'),
iconCls: "pimcore_icon_save",
handler: this.save.bind(this, "scheduler","scheduler")
}
]
});
this.toolbarButtons.unpublish = new Ext.Button({
text: t('unpublish'),
iconCls: "pimcore_icon_unpublish",
scale: "medium",
handler: this.unpublish.bind(this)
});
this.toolbarButtons.remove = new Ext.Button({
tooltip: t("delete"),
iconCls: "pimcore_icon_delete",
scale: "medium",
handler: this.remove.bind(this)
});
this.toolbarButtons.rename = new Ext.Button({
tooltip: t('rename'),
iconCls: "pimcore_icon_key pimcore_icon_overlay_go",
scale: "medium",
handler: function () {
var options = {
elementType: "object",
elementSubType: this.data.general.o_type,
id: this.id,
default: this.data.general.o_key
};
pimcore.elementservice.editElementKey(options);
}.bind(this)
});
//This code is for save&publish buttons
if (this.isAllowed("save")) {
buttons.push(this.toolbarButtons.save);
}
if (this.isAllowed("publish")) {
buttons.push(this.toolbarButtons.publish);
}
if (this.isAllowed("unpublish") && !this.data.general.o_locked) {
buttons.push(this.toolbarButtons.unpublish);
}
buttons.push("-");
if(this.isAllowed("delete") && !this.data.general.o_locked) {
buttons.push(this.toolbarButtons.remove);
}
if(this.isAllowed("rename") && !this.data.general.o_locked) {
buttons.push(this.toolbarButtons.rename);
}
var reloadConfig = {
xtype: "splitbutton",
tooltip: t('reload'),
iconCls: "pimcore_icon_reload",
scale: "medium",
handler: this.reload.bind(this, this.data.currentLayoutId)
};
if (this.data["validLayouts"] && this.data.validLayouts.length > 1) {
var menu = [];
for (var i = 0; i < this.data.validLayouts.length; i++) {
var menuLabel = ts(this.data.validLayouts[i].name);
if (Number(this.data.currentLayoutId) == this.data.validLayouts[i].id) {
menuLabel = "<b>" + menuLabel + "</b>";
}
menu.push({
text: menuLabel,
iconCls: "pimcore_icon_reload",
handler: this.reload.bind(this, this.data.validLayouts[i].id)
});
}
reloadConfig.menu = menu;
}
buttons.push(reloadConfig);
if (pimcore.elementservice.showLocateInTreeButton("object")) {
if (this.data.general.o_type != "variant" || this.data.general.showVariants) {
buttons.push({
tooltip: t('show_in_tree'),
iconCls: "pimcore_icon_show_in_tree",
scale: "medium",
handler: this.selectInTree.bind(this, this.data.general.o_type)
});
}
}
buttons.push({
tooltip: t("show_metainfo"),
iconCls: "pimcore_icon_info",
scale: "medium",
handler: this.showMetaInfo.bind(this)
});
buttons.push("-");
buttons.push({
xtype: 'tbtext',
text: t("id") + " " + this.data.general.o_id,
scale: "medium"
});
buttons.push("-");
buttons.push({
xtype: 'tbtext',
text: ts(this.data.general.o_className),
scale: "medium"
});
// version notification
this.newerVersionNotification = new Ext.Toolbar.TextItem({
xtype: 'tbtext',
text: ' <img src="/pimcore/static6/img/flat-color-icons/medium_priority.svg" style="height: 16px;" align="absbottom" /> '
+ t("this_is_a_newer_not_published_version"),
scale: "medium",
hidden: true
});
buttons.push(this.newerVersionNotification);
//workflow management
pimcore.elementservice.integrateWorkflowManagement('object', this.id, this, buttons);
// check for newer version than the published
if (this.data.versions.length > 0) {
if (this.data.general.o_modificationDate < this.data.versions[0].date) {
this.newerVersionNotification.show();
}
}
this.toolbar = new Ext.Toolbar({
id: "object_toolbar_" + this.id,
region: "north",
border: false,
cls: "main-toolbar",
items: buttons,
overflowHandler: 'scroller'
});
this.toolbar.on("afterrender", function () {
window.setTimeout(function () {
if (!this.data.general.o_published) {
this.toolbarButtons.unpublish.hide();
} else if (this.isAllowed("publish")) {
this.toolbarButtons.save.hide();
}
}.bind(this), 500);
}.bind(this));
}
return this.toolbar;
}
});
You have to do the same with tree.js:
pimcore.object.tree = Class.create({
onTreeNodeContextmenu: function (tree, record, item, index, e, eOpts ) {
e.stopEvent();
tree.select();
var menu = new Ext.menu.Menu();
var perspectiveCfg = this.perspectiveCfg;
var object_types = pimcore.globalmanager.get("object_types_store_create");
var objectMenu = {
objects: [],
importer: [],
ref: this
};
var groups = {
importer: {},
objects: {}
};
var tmpMenuEntry;
var tmpMenuEntryImport;
var $this = this;
object_types.each(function (classRecord) {
if ($this.config.allowedClasses && !in_array(classRecord.get("id"), $this.config.allowedClasses)) {
return;
}
tmpMenuEntry = {
text: classRecord.get("translatedText"),
iconCls: "pimcore_icon_object pimcore_icon_overlay_add",
handler: $this.addObject.bind($this, classRecord.get("id"), classRecord.get("text"), tree, record)
};
// add special icon
if (classRecord.get("icon") != "/pimcore/static6/img/flat-color-icons/timeline.svg") {
tmpMenuEntry.icon = classRecord.get("icon");
tmpMenuEntry.iconCls = "";
}
tmpMenuEntryImport = {
text: classRecord.get("translatedText"),
iconCls: "pimcore_icon_object pimcore_icon_overlay_add",
handler: $this.importObjects.bind($this, classRecord.get("id"), classRecord.get("text"), tree, record)
};
// add special icon
if (classRecord.get("icon") != "/pimcore/static6/img/flat-color-icons/timeline.svg") {
tmpMenuEntryImport.icon = classRecord.get("icon");
tmpMenuEntryImport.iconCls = "";
}
// check if the class is within a group
if(classRecord.get("group")) {
if(!groups["objects"][classRecord.get("group")]) {
groups["objects"][classRecord.get("group")] = {
text: classRecord.get("group"),
iconCls: "pimcore_icon_folder",
hideOnClick: false,
menu: {
items: []
}
};
groups["importer"][classRecord.get("group")] = {
text: classRecord.get("group"),
iconCls: "pimcore_icon_folder",
hideOnClick: false,
menu: {
items: []
}
};
objectMenu["objects"].push(groups["objects"][classRecord.get("group")]);
objectMenu["importer"].push(groups["importer"][classRecord.get("group")]);
}
groups["objects"][classRecord.get("group")]["menu"]["items"].push(tmpMenuEntry);
groups["importer"][classRecord.get("group")]["menu"]["items"].push(tmpMenuEntryImport);
} else {
objectMenu["objects"].push(tmpMenuEntry);
objectMenu["importer"].push(tmpMenuEntryImport);
}
});
var isVariant = record.data.type == "variant";
if (record.data.permissions.create) {
if (!isVariant) {
if (perspectiveCfg.inTreeContextMenu("object.add")) {
menu.add(new Ext.menu.Item({
text: t('add_object'),
iconCls: "pimcore_icon_object pimcore_icon_overlay_add",
hideOnClick: false,
menu: objectMenu.objects
}));
}
}
if (record.data.allowVariants && perspectiveCfg.inTreeContextMenu("object.add")) {
menu.add(new Ext.menu.Item({
text: t("add_variant"),
iconCls: "pimcore_icon_variant",
handler: this.createVariant.bind(this, tree, record)
}));
}
if (!isVariant) {
if (perspectiveCfg.inTreeContextMenu("object.addFolder")) {
menu.add(new Ext.menu.Item({
text: t('add_folder'),
iconCls: "pimcore_icon_folder pimcore_icon_overlay_add",
handler: this.addFolder.bind(this, tree, record)
}));
}
if (perspectiveCfg.inTreeContextMenu("object.importCsv")) {
menu.add({
text: t('import_csv'),
hideOnClick: false,
iconCls: "pimcore_icon_object pimcore_icon_overlay_upload",
menu: objectMenu.importer
});
}
menu.add("-");
//paste
var pasteMenu = [];
if (perspectiveCfg.inTreeContextMenu("object.paste")) {
if (pimcore.cachedObjectId && record.data.permissions.create) {
pasteMenu.push({
text: t("paste_recursive_as_childs"),
iconCls: "pimcore_icon_paste",
handler: this.pasteInfo.bind(this, tree, record, "recursive")
});
pasteMenu.push({
text: t("paste_recursive_updating_references"),
iconCls: "pimcore_icon_paste",
handler: this.pasteInfo.bind(this, tree, record, "recursive-update-references")
});
pasteMenu.push({
text: t("paste_as_child"),
iconCls: "pimcore_icon_paste",
handler: this.pasteInfo.bind(this, tree, record, "child")
});
if (record.data.type != "folder") {
pasteMenu.push({
text: t("paste_contents"),
iconCls: "pimcore_icon_paste",
handler: this.pasteInfo.bind(this, tree, record, "replace")
});
}
}
}
if (!isVariant) {
if (pimcore.cutObject && record.data.permissions.create) {
pasteMenu.push({
text: t("paste_cut_element"),
iconCls: "pimcore_icon_paste",
handler: function () {
this.pasteCutObject(pimcore.cutObject,
pimcore.cutObjectParentNode, record, this.tree);
pimcore.cutObjectParentNode = null;
pimcore.cutObject = null;
}.bind(this)
});
}
if (pasteMenu.length > 0) {
menu.add(new Ext.menu.Item({
text: t('paste'),
iconCls: "pimcore_icon_paste",
hideOnClick: false,
menu: pasteMenu
}));
}
}
}
}
if (!isVariant) {
if (record.data.id != 1 && record.data.permissions.view && perspectiveCfg.inTreeContextMenu("object.copy")) {
menu.add(new Ext.menu.Item({
text: t('copy'),
iconCls: "pimcore_icon_copy",
handler: this.copy.bind(this, tree, record)
}));
}
//cut
if (record.data.id != 1 && !record.data.locked && record.data.permissions.rename && perspectiveCfg.inTreeContextMenu("object.cut")) {
menu.add(new Ext.menu.Item({
text: t('cut'),
iconCls: "pimcore_icon_cut",
handler: this.cut.bind(this, tree, record)
}));
}
}
//publish
if (record.data.type != "folder" && !record.data.locked) {
if (record.data.published && record.data.permissions.unpublish && perspectiveCfg.inTreeContextMenu("object.unpublish")) {
menu.add(new Ext.menu.Item({
text: t('unpublish'),
iconCls: "pimcore_icon_unpublish",
handler: this.publishObject.bind(this, tree, record, 'unpublish')
}));
} else if (!record.data.published && record.data.permissions.publish && perspectiveCfg.inTreeContextMenu("object.publish")) {
menu.add(new Ext.menu.Item({
text: t('publish'),
iconCls: "pimcore_icon_publish",
handler: this.publishObject.bind(this, tree, record, 'publish')
}));
}
}
if (record.data.permissions["delete"] && record.data.id != 1 && !record.data.locked && perspectiveCfg.inTreeContextMenu("object.delete")) {
menu.add(new Ext.menu.Item({
text: t('delete'),
iconCls: "pimcore_icon_delete",
handler: this.remove.bind(this, tree, record)
}));
}
if (record.data.permissions.rename && record.data.id != 1 && !record.data.locked && perspectiveCfg.inTreeContextMenu("object.rename")) {
menu.add(new Ext.menu.Item({
text: t('rename'),
iconCls: "pimcore_icon_key pimcore_icon_overlay_go",
handler: this.editObjectKey.bind(this, tree, record)
}));
}
// advanced menu
var advancedMenuItems = [];
var user = pimcore.globalmanager.get("user");
if (record.data.permissions.create && perspectiveCfg.inTreeContextMenu("object.searchAndMove")) {
advancedMenuItems.push({
text: t('search_and_move'),
iconCls: "pimcore_icon_search pimcore_icon_overlay_go",
handler: this.searchAndMove.bind(this, tree, record)
});
}
if (record.data.id != 1 && user.admin) {
var lockMenu = [];
if (record.data.lockOwner && perspectiveCfg.inTreeContextMenu("object.unlock")) { // add unlock
lockMenu.push({
text: t('unlock'),
iconCls: "pimcore_icon_lock pimcore_icon_overlay_delete",
handler: function () {
pimcore.elementservice.lockElement({
elementType: "object",
id: record.data.id,
mode: "null"
});
}.bind(this)
});
} else {
if (perspectiveCfg.inTreeContextMenu("object.lock")) {
lockMenu.push({
text: t('lock'),
iconCls: "pimcore_icon_lock pimcore_icon_overlay_add",
handler: function () {
pimcore.elementservice.lockElement({
elementType: "object",
id: record.data.id,
mode: "self"
});
}.bind(this)
});
}
if (perspectiveCfg.inTreeContextMenu("object.lockAndPropagate")) {
lockMenu.push({
text: t('lock_and_propagate_to_childs'),
iconCls: "pimcore_icon_lock pimcore_icon_overlay_go",
handler: function () {
pimcore.elementservice.lockElement({
elementType: "object",
id: record.data.id,
mode: "propagate"
});
}.bind(this)
});
}
}
if(record.data.locked) {
// add unlock and propagate to children functionality
if (perspectiveCfg.inTreeContextMenu("object.unlockAndPropagate")) {
lockMenu.push({
text: t('unlock_and_propagate_to_children'),
iconCls: "pimcore_icon_lock pimcore_icon_overlay_delete",
handler: function () {
pimcore.elementservice.unlockElement({
elementType: "object",
id: record.data.id
});
}.bind(this)
});
}
}
if (lockMenu.length > 0) {
advancedMenuItems.push({
text: t('lock'),
iconCls: "pimcore_icon_lock",
hideOnClick: false,
menu: lockMenu
});
}
}
menu.add("-");
if(advancedMenuItems.length) {
menu.add({
text: t('advanced'),
iconCls: "pimcore_icon_more",
hideOnClick: false,
menu: advancedMenuItems
});
}
if (perspectiveCfg.inTreeContextMenu("object.reload")) {
menu.add({
text: t('refresh'),
iconCls: "pimcore_icon_reload",
handler: this.reloadNode.bind(this, tree, record)
});
}
pimcore.helpers.hideRedundantSeparators(menu);
pimcore.plugin.broker.fireEvent("prepareObjectTreeContextMenu", menu, this, record);
menu.showAt(e.pageX+1, e.pageY+1);
},
});

Related

getting 0x03 error when performing chart generation: please check your input data in Highchart

i am using highchart export server for generate chart in NodeJs
but when i am generating many charts it gives error like 0x03 error when performing chart generation: please check your input data
here is my code
exports.generateAllCharts = (chartData, callback) => {
highchartsExporter.initPool({
maxWorkers: 100,
initialWorkers: 40,
workLimit: 100,
queueSize: 40,
timeoutThreshold: 600000
});
var allPromises = [];
if(!chartData ||chartData.length === 0) {
return callback({
code: '4',
msg: 'Please send chartdata'
})
}
allPromises.push(exports.getStockChartImg(chartData[1]));
allPromises.push(exports.priceChartVsPeersImg(chartData[2]));
allPromises.push(exports.getPieChartImg(chartData[3]));
allPromises.push(exports.getPieChartImg(chartData[4]));
allPromises.push(exports.getPieChartImg(chartData[5]));
allPromises.push(exports.getPieChartImg(chartData[6]));
allPromises.push(exports.getPieChartImg(chartData[13]));
allPromises.push(exports.getPieChartImg(chartData[14]));
allPromises.push(exports.getPieChartImg(chartData[15]));
allPromises.push(exports.getPieChartImg(chartData[16]));
allPromises.push(exports.getPieChartImg(chartData[18]));
allPromises.push(exports.getPieChartImg(chartData[19]));
allPromises.push(exports.getPieChartImg(chartData[7]));
allPromises.push(exports.getPieChartImg(chartData[17]));
allPromises.push(exports.getPieChartImg(chartData[20]));
allPromises.push(exports.getPieChartImg(chartData[21]));
allPromises.push(exports.getPieChartImg(chartData[22]));
allPromises.push(exports.getPieChartImg(chartData[23]));
allPromises.push(exports.getPieChartImg(chartData[24]));
allPromises.push(exports.getPieChartImg(chartData[25]));
allPromises.push(exports.getPieChartImg(chartData[26]));
allPromises.push(exports.getPieChartImg(chartData[27]));
allPromises.push(exports.getPieChartImg(chartData[33]));
allPromises.push(exports.getPieChartImg(chartData[34]));
allPromises.push(exports.getGlobalOwnershipDistributionChartImg(chartData[35]));
allPromises.push(exports.getPieChartImg(chartData[36]));
allPromises.push(exports.getPieChartImg(chartData[37]));
allPromises.push(exports.getPieChartImg(chartData[38]));
allPromises.push(exports.getPieChartImg(chartData[39]));
allPromises.push(exports.getPieChartImg(chartData[40]));
allPromises.push(exports.getPieChartImg(chartData[41]));
allPromises.push(exports.getPieChartImg(chartData[42]));
allPromises.push(exports.getPieChartImg(chartData[43]));
Promise.all(allPromises)
.then(data => {
highchartsExporter.killPool();
return callback({
code: '0',
custImg: {
pc1: data[0].data,
pc2: data[1].data,
pc3: data[2].data,
pc4: data[3].data,
pc5: data[4].data,
pc6: data[5].data,
pc7: data[6].data,
pc8: data[7].data,
pc9: data[8].data,
pc10: data[9].data,
pc11: data[10].data,
pc12: data[11].data,
pc13: data[12].data,
pc14: data[13].data,
pc17: data[14].data,
pc18: data[15].data,
pc19: data[16].data,
pc20: data[17].data,
pc21: data[18].data,
pc22: data[19].data,
pc23: data[20].data,
pc24: data[21].data,
pc27: data[22].data,
pc28: data[23].data,
pc29: data[24].data,
pc30: data[25].data,
pc31: data[26].data,
pc32: data[27].data,
pc33: data[28].data,
pc34: data[29].data,
pc35: data[30].data,
pc36: data[31].data,
pc37: data[32].data,
}
})
})
.catch(err => callback({
code: '5',
msg: 'Error generating charts',
err,
}))
}
exports.getPieChartImg = (seriesData, xOrLength) => {
var chartOpts = {
colors: ['#7380D4', '#749FD4', '#74BFD4', '#74D4B6', '#99EBA8', '#FEE08B', '#FDAE61', '#F07346', '#E65433', '#C92D22'],
chart: {
plotBackgroundColor: null,
plotBorderWidth: null,
plotShadow: false,
renderTo: 'container',
style: {
fontSize: '20px',
background: '#fffdcc'
},
width:650,
},
credits: {
enabled: false
},
title: {
text: null,
},
tooltip: {
pointFormat: '{series.name}: {point.percentage:.1f}%'
},
legend: {
itemStyle: {
font: 'sans-serif',
fontWeight: 'bold',
fontSize: '13px'
},
useHTML: true,
layout: 'vertical',
align: 'right',
verticalAlign: 'middle',
labelFormatter: ()=> {
if (this.name[xOrLength] > 9) {
var words = this.name.split(/[\s]+/);
var numWordsPerLine = 1;
var str = [];
for (var word in words) {
if (parseInt(word) > 0 && parseInt(word) % numWordsPerLine == 0)
str.push('<br>');
str.push(words[word]);
}
var label = str.join(' ');
// Make legend text bold and red if most recent value is less than prior
if (this.name[1] > this.name[2]) {
return '<span style="font-weight:bold">' + label + '</span>';
} else {
return label;
}
} else {
return this.name;
}
}
},
plotOptions: {
pie: {
size: '85%',
allowPointSelect: true,
cursor: 'pointer',
showInLegend: true,
dataLabels: {
enabled: true,
allowOverlap: false,
distance: 10,
formatter: ()=> {
return undefined;
// if (parseFloat(this.percentage.toFixed(2)) > 0.35) {
// return '' + parseFloat(this.percentage).toFixed(2) + '%';
// }
},
padding: 5,
style: { fontFamily: '\'Lato\', sans-serif', /*lineHeight: '18px',*/ fontWeight: 'normal', fontSize: '18px' }
}
},
series: {
stacking: 'normal',
dataLabels: {
enabled: true,
color: '#6f6f6f',
style: { fontFamily: '\'Lato\', sans-serif', /*lineHeight: '18px',*/ fontWeight: 'normal', fontSize: '18px' },
format:'{point.percentage:.2f}'
},
pointWidth: 30,
cursor: 'pointer'
}
},
series: [{
name: "Value",
type: 'pie',
data: seriesData
}],
navigation: {
buttonOptions: {
enabled: false
}
},
};
var exportSettings = generateExportSettings(chartOpts, 'Stock');
return generateBase64Chart(exportSettings, 3)
}
function generateExportSettings(chartOpts, constr) {
return {
// b64: true,
instr: JSON.stringify(chartOpts),
noDownload: true,
constr,
globalOptions: {
colors: ['#7380D4', '#749FD4', '#74BFD4', '#74D4B6', '#99EBA8', '#FEE08B', '#FDAE61', '#F07346', '#E65433', '#C92D22'],
lang: {
thousandsSep: ','
}
},
scale: 2,
styledMode: false,
type: "image/png",
width: false,
};
}
function generateBase64Chart(exportSettings, number) {
return new Promise((resolve, reject) => {
//Perform an export
highchartsExporter.export(exportSettings, function (err, res) {
//The export result is now in res.
//If the output is not PDF or SVG, it will be base64 encoded (res.data).
//If the output is a PDF or SVG, it will contain a filename (res.filename).
if(err) {
Logger.error("IN ERROR: ", number);
Logger.error("ERROR: ", err);
return reject({
code: '1',
err,
msg: 'Error in stock chart',
exportSettings
})
}
return resolve({
code: '0',
msg: 'success',
data: 'data:image/png;base64,' + res.data,
})
//Kill the pool when we're done with it, and exit the application
// highchartsExporter.killPool();
// process.exit(1);
});
})
}
i am generating all charts at a time, so how can i solve this problem.
I have modified your code a little bit (and used the getPieChartImg as it is the only one available) and tried to export a big number of charts (35 in this case). I don't encounter the 0x03-error. Here is the modified code:
(test.js)
const exporter = require('./promise-based.js');
let numberOfCharts = 35;
let chartsData = [];
for (let i = 0; i < numberOfCharts; i++) {
chartsData.push([1, 2, 3, 4, 5]);
}
exporter.generateAllCharts(chartsData, results => {
if (results.code === '0') {
console.log('All charts exported!');
console.log(results);
} else {
console.log('Error #' + results.code + ': ' + results.msg);
if (results.err) {
console.log(results.err);
}
}
process.exit();
});
(promise-based.js)
const highchartsExporter = require('highcharts-export-server');
let promiseId = 0;
exports.generateAllCharts = (chartData, callback) => {
let allPromises = [];
let chartsLen = chartData.length;
highchartsExporter.logLevel(4);
highchartsExporter.initPool({
maxWorkers: 100,
initialWorkers: 50,
workLimit: 100,
queueSize: 50,
timeoutThreshold: 10000
});
if (!chartData || !chartsLen) {
highchartsExporter.killPool();
return callback({
code: '4',
msg: 'Please send chartdata'
});
}
for (let i = 0; i < chartsLen; i++) {
allPromises.push(
new Promise((resolve, reject) => {
exports.getPieChartImg(chartData[i], false, results => {
if (results.code !== '0') {
return reject(results);
}
return resolve(results);
});
})
);
}
Promise.all(allPromises)
.then(data => {
highchartsExporter.killPool();
let imagesObject = {
code: '0',
custImg: {}
};
data.forEach((image, index) => {
imagesObject.custImg['pc' + (index + 1)] = image.data;
imagesObject.custImg.promiseId = image.promiseId;
});
return callback(imagesObject);
})
.catch(err => callback({
code: '5',
msg: 'Error generating charts',
err
}));
};
exports.getPieChartImg = (seriesData, xOrLength, cb) => {
let chartOpts = {
colors: ['#7380D4', '#749FD4', '#74BFD4', '#74D4B6', '#99EBA8', '#FEE08B', '#FDAE61', '#F07346', '#E65433', '#C92D22'],
chart: {
plotBackgroundColor: null,
plotBorderWidth: null,
plotShadow: false,
renderTo: 'container',
style: {
fontSize: '20px',
background: '#fffdcc'
},
width: 650,
},
credits: {
enabled: false
},
title: {
text: null,
},
tooltip: {
pointFormat: '{series.name}: {point.percentage:.1f}%'
},
legend: {
itemStyle: {
font: 'sans-serif',
fontWeight: 'bold',
fontSize: '13px'
},
useHTML: true,
layout: 'vertical',
align: 'right',
verticalAlign: 'middle',
labelFormatter: () => {
if (this.name[xOrLength] > 9) {
let words = this.name.split(/[\s]+/);
let numWordsPerLine = 1;
let str = [];
for (let word in words) {
if (parseInt(word) > 0 && parseInt(word) % numWordsPerLine == 0)
str.push('<br>');
str.push(words[word]);
}
let label = str.join(' ');
// Make legend text bold and red if most recent value is less than prior
if (this.name[1] > this.name[2]) {
return '<span style="font-weight:bold">' + label + '</span>';
} else {
return label;
}
} else {
return this.name;
}
}
},
plotOptions: {
pie: {
size: '85%',
allowPointSelect: true,
cursor: 'pointer',
showInLegend: true,
dataLabels: {
enabled: true,
allowOverlap: false,
distance: 10,
formatter: () => {
return undefined;
// if (parseFloat(this.percentage.toFixed(2)) > 0.35) {
// return '' + parseFloat(this.percentage).toFixed(2) + '%';
// }
},
padding: 5,
style: {
fontFamily: '\'Lato\', sans-serif',
// lineHeight: '18px',
fontWeight: 'normal',
fontSize: '18px'
}
}
},
series: {
stacking: 'normal',
dataLabels: {
enabled: true,
color: '#6f6f6f',
style: {
fontFamily: '\'Lato\', sans-serif',
// lineHeight: '18px',
fontWeight: 'normal',
fontSize: '18px'
},
format: '{point.percentage:.2f}'
},
pointWidth: 30,
cursor: 'pointer'
}
},
series: [{
name: "Value",
type: 'pie',
data: seriesData
}],
navigation: {
buttonOptions: {
enabled: false
}
},
};
let exportSettings = generateExportSettings(chartOpts, 'Stock');
return generateBase64Chart(exportSettings, 3, cb);
};
function generateExportSettings(chartOpts, constr) {
return {
type: 'png',
constr,
b64: true,
// async: false,
noDownload: true,
scale: 2,
options: chartOpts,
globalOptions: {
colors: ['#7380D4', '#749FD4', '#74BFD4', '#74D4B6', '#99EBA8', '#FEE08B', '#FDAE61', '#F07346', '#E65433', '#C92D22'],
lang: {
thousandsSep: ','
}
}
};
}
function generateBase64Chart(exportSettings, number, cb) {
// Perform an export
highchartsExporter.export(exportSettings, function(err, res) {
// The export result is now in res.
// If the output is not PDF or SVG, it will be base64 encoded (res.data).
// If the output is a PDF or SVG, it will contain a filename (res.filename).
if (err) {
return cb({
code: '1',
msg: 'Error in stock chart',
err,
exportSettings
});
}
promiseId++;
return cb({
code: '0',
msg: 'Success',
promiseId: promiseId,
data: 'data:image/png;base64,' + res.data,
});
// Kill the pool when we're done with it, and exit the application
// highchartsExporter.killPool();
// process.exit(1);
});
}

Setting a react state in callback does not work as expected

I am making barcode reading app. I use Quaggajs and Reactjs.
Quaggajs has a function Quagga.onDetected(callback), the callback has one parameter result. The result is containing the detected barcode. I am having a react state (const [count, setCount] = useState(0);) in which I am counting the detected barcodes. The problem is that when I use setCount(count + 1) in the callback the count variable is allways it's initial value (0) so every time onDetect the setCount is setting the new value to be 1.
Here is an example of the functional react component I use(I think that there is no problem getting the count and setCount from the props of ):
const Body = ({setCount, count, ...rest }) => {
const start = () => {
Quagga.init({
inputStream: {
name: "Live",
type: "LiveStream",
constraints: {
facingMode: "environment",
},
area: {
top: "30%",
bottom: "30%"
}
},
locate: false,
frequency: 50,
decoder: {
readers: [
// "code_128_reader",
"ean_reader",
// "ean_8_reader",
// "code_39_reader",
// "code_39_vin_reader",
// "codabar_reader",
// "upc_reader",
// "upc_e_reader",
// "i2of5_reader"
],
debug: {
showCanvas: true,
showPatches: true,
showFoundPatches: true,
showSkeleton: true,
showLabels: true,
showPatchLabels: true,
showRemainingPatchLabels: true,
boxFromPatches: {
showTransformed: true,
showTransformedBox: true,
showBB: true
}
}
},
}, function (err) {
if (err) {
console.log(err);
return
}
console.log("Initialization finished. Ready to start");
Quagga.start();
});
Quagga.onProcessed(function (result) {
var drawingCtx = Quagga.canvas.ctx.overlay,
drawingCanvas = Quagga.canvas.dom.overlay;
if (result) {
if (result.boxes) {
drawingCtx.clearRect(0, 0, parseInt(drawingCanvas.getAttribute("width")), parseInt(drawingCanvas.getAttribute("height")));
result.boxes.filter(function (box) {
return box !== result.box;
}).forEach(function (box) {
Quagga.ImageDebug.drawPath(box, { x: 0, y: 1 }, drawingCtx, { color: "green", lineWidth: 2 });
});
}
if (result.box) {
Quagga.ImageDebug.drawPath(result.box, { x: 0, y: 1 }, drawingCtx, { color: "#00F", lineWidth: 2 });
}
if (result.codeResult && result.codeResult.code) {
Quagga.ImageDebug.drawPath(result.line, { x: 'x', y: 'y' }, drawingCtx, { color: 'red', lineWidth: 3 });
}
}
});
Quagga.onDetected((result) => {
if (result && result.codeResult && result.codeResult.startInfo && result.codeResult.startInfo.error < 0.03) {
console.log("Sould change")
setCount(count + 1);
}
});
}
const stop = () => { Quagga.stop(); }
useEffect(() => {
start();
console.log("CHANGE BODY");
return () => {
stop();
}
}, [])
return (
<Grid container justify="center">
<div id="interactive" className="viewport" style={{ position: 'unset', width: '100vw', height: "100vh" }}>
<video src=""></video>
<canvas class="drawingBuffer"></canvas>
</div>
</Grid>
)
}

How do I populate a User Story's Revision History in a grid

I found an answer related to Revision History "Querying for User Story revisions in Rally"
I am having trouble determining how to populate a grid with it.
Can I use the model and populate a story that the gird references?
Here is a working example, using other examples.
I had to populate an array with revision history info and add it to a story.
Then the story populated the grid.
// Also referenced
// https://stackoverflow.com/questions/22334745/does-rally-data-custom-store-have-magic-uniqueness
//
Ext.define('CustomApp',
{
extend: 'Rally.app.App',
componentCls: 'app',
launch: function()
{
var panel = Ext.create('Ext.panel.Panel',
{
layout: 'hbox',
itemId: 'parentPanel',
componentCls: 'panel',
items: [
{
xtype: 'panel',
title: 'Artifacts updated in the last two days',
width: 600,
itemId: 'childPanel1'
},
{
xtype: 'panel',
title: 'Last Revision',
width: 600,
itemId: 'childPanel2'
}]
});
this.add(panel);
var artifacts = Ext.create('Rally.data.wsapi.artifact.Store',
{
models: ['UserStory','Defect', 'TestCase'],
fetch: ['Owner', 'FormattedID','Name','ScheduleState','RevisionHistory','Revisions','Description','CreationDate','User'],
autoLoad: true,
listeners:
{
load: this._onDataLoaded,
scope: this
}
});
},
_onDataLoaded: function(store, data)
{
this._customRecords = [];
_.each(data, function(artifact, index)
{
this._customRecords.push(
{
_ref: artifact.get('_ref'),
FormattedID: artifact.get('FormattedID'),
Name: artifact.get('Name'),
RevisionID: Rally.util.Ref.getOidFromRef(artifact.get('RevisionHistory')),
RevisionNumber: 'not loaded'
});
}, this);
this._createGrid(store,data);
},
_createGrid: function(store,data)
{
var that = this;
var g = Ext.create('Rally.ui.grid.Grid',
{
itemId: 'g',
store: store,
enableEditing: false,
showRowActionsColumn: false,
columnCfgs:
[{text: 'Formatted ID', dataIndex: 'FormattedID'},
{text: 'Name', dataIndex: 'Name'},
{text: 'ScheduleState', dataIndex: 'ScheduleState'},
{text: 'Last Revision',
renderer: function (v, m, r)
{
var id = Ext.id();
Ext.defer(function ()
{
Ext.widget('button',
{
renderTo: id,
text: 'see',
width: 50,
handler: function ()
{
that._getRevisionHistory(data, r.data);
}
});
}, 50);
return Ext.String.format('<div id="{0}"></div>', id);
}
}], height: 400,
});
this.down('#childPanel1').add(g);
},
_getRevisionHistory: function(artifactList, artifact)
{
this._artifact = artifact;
this._revisionModel = Rally.data.ModelFactory.getModel(
{
type: 'RevisionHistory',
scope: this,
success: this._onModelCreated
});
},
_onModelCreated: function(model)
{
model.load(Rally.util.Ref.getOidFromRef(this._artifact.RevisionHistory._ref),
{
scope: this,
success: this._onModelLoaded
});
},
_onModelLoaded: function(record, operation)
{
var list = [];
record.getCollection('Revisions').load(
{
fetch: true,
scope: this,
callback: function(revisions, operation, success)
{
_.each(revisions, function(artifact, index)
{
var creationdate;
if (Rally.environment.useSystemTimezone || Rally.environment.useWorkspaceTimeZone)
{
creationdate = Rally.util.DateTime.formatDate(artifact.data.CreationDate, true);
}
else
{
creationdate = Rally.util.DateTime.formatWithDefaultDateTime(artifact.data.CreationDate);
}
var nodedata =
{
rev_num: artifact.data.RevisionNumber,
descript: artifact.data.Description,
author: artifact.data.User._refObjectName,
creationdate: creationdate
};
if(nodedata.descript.indexOf('SCHEDULE STATE') > -1)
{
list.push(nodedata);
}
else
{
if(nodedata.descript .indexOf('PLAN ESTIMATE') > -1)
{
list.push(nodedata);
}
}
}, this);
var myStore = Ext.create("Rally.data.custom.Store",
{
autoLoad: true,
data : list,
});
var revGrid = Ext.create('Rally.ui.grid.Grid',
{
itemId: 'revGrid ',
store: myStore,
enableEditing: false,
showRowActionsColumn: false,
height: 400,
columnCfgs:
[
{text: 'Rev #', dataIndex: 'rev_num'},
{text: 'Description', dataIndex: 'descript'},
{text: 'Author', dataIndex: 'author'},
{text: 'Change Date', dataIndex: 'creationdate'}
]
});
this.down('#childPanel2').add(revGrid);
}
});
},
});

Highchart y axis need 2 category each having 3 sub category

I am using high chart version v4.0.4, i have worked bar chart like mentioned below i need output with there bar for every year details given below
I am working on below high chart code
var data_first_vd = 0;
var data_second_vd = 0;
var glb_data_ary = [];
var dynamicval1 = 5.85572581;
var dynamicval2 = 0.16091656;
if((dynamicval1>1) || (dynamicval2>1)){
var data_tit = 'Value';
var data_val = '${value}';
var prdelvalaxis = 1000000;
}else{
prdelvalaxis = 1000;
data_tit = "Value";
data_val = "${value}";
}
data_first_vd=5.86;
data_second_vd =0.16;
var data_first_ud =1397.128;
var data_second_ud = 28.145;
data_first_ud_lbl = '1.40M';
data_second_ud_lbl = '28K';
data_first_vd_lbl = '5.86M';
data_second_vd_lbl = '161K';
data_first_vd_lbl_xaxis = '$5.86M';
data_second_vd_lbl_xaxis = '$161K';
var ud1 = 1397;
var ud2 = 28;
var vd1 = 6;
var vd2 = 0;
$('#id').highcharts({
credits: { enabled: false },
chart: {
type: 'bar',
height: 200,
marginLeft: 120,
marginBottom:50,
marginTop: 47,
marginRight:30,
plotBorderWidth: 0,
},
title: {
text: null
},
xAxis: {
drawHorizontalBorders: false,
labels: {
groupedOptions: [{
rotation: 270,
}],
rotation: 0,
align:'center',
x: -30,
y: 5,
formatter: function () {
if (curYear === this.value) {
return '<span style="color:#6C9CCC;">' + this.value + '</span>';
}
else if (prevYear === this.value) {
return '<span style="color: #ED7D31;">' + this.value + '</span>';
}
else if ('VALUE' === this.value) {
return '<span style="color:#942EE1;">' + this.value + '</span>';
}
else{
return '<span style="color: #E124D2;">' + this.value + '</span>';
}
},
useHTML:true
},
categories: [{
name: "UNITS",
categories: [2017, 2016]
},{
name: "VALUE",
categories: [2017, 2016]
}
],
},
yAxis: [{ // Primary yAxis
labels: {
format: data_val,
formatter: function () {
if(this.value!=0){
return '$'+valueConverter_crt(this.value*prdelvalaxis);
}else{
return this.value;
}
},
style: {
color: '#942EE1'
}
},
title: {
text: "<span style='font-size: 12px;'>"+data_tit+"</span>",
style: {
color: '#942EE1'
},
useHTML:true
}
}, { // Secondary yAxis
title: {
text: "<span style='font-size: 12px;'>Units</span>",
style: {
color: '#E124D2'
},
useHTML:true
},
labels: {
format: '{value}',
formatter: function () {
if(this.value!=0){
return cal_pro_del_xaxis(this.value);
}else{
return this.value;
}
},
style: {
color: '#E124D2'
}
},
opposite: true
}],
tooltip: { enabled: false },
exporting: { enabled: false },
legend: { enabled: false },
plotOptions: {
series: {
dataLabels: {
inside: true,
align: 'left',
enabled: true,
formatter: function () {
return this.point.name;
},
color: '#000000',
},
stacking: false,
pointWidth: 15,
groupPadding: 0.5
},
},
series: [{
yAxis: 1,
data: [{y:1397.128,name:data_first_ud_lbl,color:'#6C9CCC'},{y:28.145,name:data_second_ud_lbl,color:'#ED7D31'}],
}, {
data: [null,null,{y:5.86,name:data_first_vd_lbl_xaxis,color:'#6C9CCC'},{y:0.16,name:data_second_vd_lbl_xaxis,color:'#ED7D31'}],
}]
});
I need out put like below chart This chart i draw in paint.
Here 3 bar added in every year
Please help me to achieve this

jQuery JTable Problems to find selected rows in ChildTable

I have some problems finding my selected rows in a nested JQuery JTable via a Toolbar Click.
This is my nested table which works fine:
$(document).ready(function () {
$('#TableContainer').jtable({
title: 'MyList',
sorting: true,
defaultSorting: 'list_id desc',
actions: {
listAction: 'lists_list_action.php?action=list',
updateAction: 'lists_list_action.php?action=update',
},
fields: {
list_id: { title: 'Nr.', key: true, list: true, width: '10px', listClass: 'psg_list_center' },
//CHILD TABLE "Abos"
abos: {
title: 'Abos',
width: '5%',
sorting: false,
edit: false,
create: false,
display: function (ListData) {
//Create an image that will be used to open child table
var $img = $('<img src="../../images/list_metro.png" title="manage Listabos" />');
//Open child table when user clicks the image
$img.click(function () {
$('#TableContainer').jtable('openChildTable',
$img.closest('tr'), //Parent row
{
title: 'List: ' + ListData.record.list_name,
selecting: true, //Enable selecting
multiselect: true, //Allow multiple selecting
selectingCheckboxes: true, //Show checkboxes on first column
selectOnRowClick: false, //Enable this to only select using checkboxes
actions: {
listAction: 'lists_list_action.php?action=AbosList&ListId=' + ListData.record.list_id,
deleteAction: 'lists_list_action.php?action=AbosDelete&ListId=' + ListData.record.list_id,
},
fields: {
list_id: { type: 'hidden', defaultValue: ListData.record.list_id },
person_id: { key: true, create: false, edit: false, list: false },
person_name: { title: 'Name', width: '40%' },
created_name: { title: 'created from', create: false, edit: false },
created_on: { title: 'created on', create: false, edit: false },
updated_name: { title: 'updated from', create: false, edit: false },
updated_on: { title: 'updated on', create: false, edit: false },
},
toolbar: {
items: [{
//icon: '/images/trash.png',
text: 'remove selected Abos',
click: function () {
// here i need to something like this:
alert('list_id=' + record.list_id + ', person_id=' + record.person_id);
delete_abo(record.list_id, record.person_id);
}
}]
},
}, function (data) { //opened handler
data.childTable.jtable('load');
});
});
//Return image to show on the person row
return $img;
}
},
list_name: { title: 'List Name' },
list_description: { title: 'Description', type: 'textarea' },
list_active: { title: 'activ', options: { 1: 'Yes', 0: 'No' } },
list_allow_subscribe: { title: 'Subscribe erlaubt', options: { 1: 'Yes', 0: 'No' } },
list_allow_unsubscribe: { title: 'Unsubscribe erlaubt', options: { 1: 'Yes', 0: 'No' } },
},
});
$('#TableContainer').jtable('load');
});
Can anybody help me at the toolbar-click Section, finding the selected Rows of the Child-Table?
I tried to do something like this:
click: function (ListData) {
var $selectedRows = ListData.jtable('selectedRows');
or:
click: function () {
var $selectedRows = $('#TableContainer').jtable-child-table-container.jtable('selectedRows');
$('#TableContainer').jtable('delete', $selectedRows);
}
or:
click: function () {
var $selectedRows = $('#TableContainer').jtable-child-table-container.jtable('selectedRows');
if ($selectedRows.length > 0) {
$selectedRows.each(function () {
var record = $(this).data('record');
alert('list_id=' + record.list_id + ', person_id=' + record.person_id);
//delete_abo(record.list_id, record.person_id);
});
} else {
//No rows selected
alert('please select some rows first!');
}
}
because the last part worked fine in an "not nested" part of my program,
but I did not come to an resolution anyhow...
Thanks for help!
finaly found the solution!
The Key to get the selected Rows:
var $selectedRows = $('#TableContainer>.jtable-main-container>.jtable>tbody>.jtable-child-row .jtable-row-selected');
or the whole working function:
click: function () {
var $selectedRows = $('#TableContainer>.jtable-main-container>.jtable>tbody>.jtable-child-row .jtable-row-selected');
if ($selectedRows.length > 0) {
$selectedRows.each(function () {
var record = $(this).data('record');
alert('list_id=' + record.list_id + ', person_id=' + record.person_id);
//delete_abo(record.list_id, record.person_id);
});
} else {
//No rows selected
alert('please select some rows first!');
} }

Resources