How to trigger Assign to Analyst by Group

Mikkel_MadsenMikkel_Madsen Customer Adept IT Monkey ✭✭
edited November 6 in Analyst Portal
Hi
When you select a request in Team Request view (or Mywork/Active work) you can hit the Task button on the drawer task bar an select assign to analyst by group.

What I would like to do is making an icon in the assigned to column and trigger the same function when you click on that icon but I can't find out how trigger it.

Anyone who can help with this or guide me?

Best Answers

Answers

  • Mikkel_MadsenMikkel_Madsen Customer Adept IT Monkey ✭✭
    No one?
  • Mikkel_MadsenMikkel_Madsen Customer Adept IT Monkey ✭✭
    @Justin_Workman
    Can you help? :smile:

  • Mikkel_MadsenMikkel_Madsen Customer Adept IT Monkey ✭✭
    yes, I know about that one but if it's possible to trigger the Assign to Analyst task I will create an icon the same way as this add-on https://community.cireson.com/discussion/1919/custom-quick-assign-work-item-to-me-from-grid#latest 

  • Tom_HendricksTom_Hendricks Customer Super IT Monkey ✭✭✭✭✭
    There is an ugly way, and a better way.

    The ugly way is to trigger a click on the button itself:
    $('a[data-bind="localize: AssignToAnalystByGroup"]').trigger('click')
    A better way would be to find the "analystByGroup" function that is actually firing within the click event, and call it directly.  These functions typically live within the view when forms are involved, but I do not see the objects I am looking for since pageForm does not exist on these grid pages.
  • Justin_WorkmanJustin_Workman Cireson Support Ninja IT Monkey ✭✭✭✭
    The solution provided by @Tom_Hendricks would certainly work.  I think it would work pretty well personally.  I don't think it's ugly at all! :)
  • Ryan_LaneRyan_Lane Customer Advanced IT Monkey ✭✭✭
    edited November 22
    Another small update to my ongoing work in progress:
    • Updated the column template to only show the edit buttons for Incidents and Service Requests to match the enabled/disabled behavior of analystByGroup.
    • Updated gridTasksViewModel PendingTasks to operate as an ObservableArray with push/pop/remove functionality to account for additional column tasks in the future.
    • Binding to the analystByGroup task's view model change event vs. the grid's app events in order to better handle the order of events for grid selection and triggering the Assign To Analyst By Group window.
    New AssignedUser column template to handle non-Incidents/Service Requests:
    "template": "<span style=\"display: inherit; width: 100%\">#: AssignedUser #</span># if (session.user.Analyst && (!_.isUndefined(WorkItemType) && (WorkItemType==='System.WorkItem.Incident' || WorkItemType==='System.WorkItem.ServiceRequest'))) { #<ul class=\"ra-grid-task-menu\" style=\"display: inherit; list-style: none;\"><li onclick=\"app.events.publish('newGridTask','AssignToAnalystByGroup');\"><a class=\"ra-icon\" style=\"display: inherit;\"><i class=\"fa fa-pencil\"></i></a></li></ul># } #"


    New custom.js script:
    var gridTasksViewModel = new kendo.observable({
        pending: [],
        lib: {
            push: function push (taskName) {
                console.log("gridTasksViewModel push", {taskName: taskName});
                if (gridTasksViewModel.pending.indexOf(taskName) === -1) {
                    gridTasksViewModel.pending.push(taskName);
                }
            },
            remove: function remove (taskName) {
                console.log("gridTasksViewModel remove", {taskName: taskName});
                gridTasksViewModel.pending.remove(taskName);
            },
            process: function ProcessPendingTask (vm, taskName) {
                console.log("gridTasksViewModel process", {vm: vm, taskName: taskName});
                if (!_.isUndefined(gridTasksViewModel.tasks.get(taskName)) && gridTasksViewModel.pending.indexOf(taskName) !== -1) {
                    gridTasksViewModel.pending.remove(taskName);
                    gridTasksViewModel.tasks[taskName](vm);
                }
            }
        },
        tasks: {
            AssignToAnalystByGroup: function AssignToAnalystByGroup (vm) {
                console.log("gridTasksViewModel AssignToAnalystByGroup", {vm: vm});
                vm.analystByGroup();
            }
        }
    });
    
    app.events.subscribe("newGridTask", function (event, taskName) {
        console.log("grid:newGridTask event", {event: event, taskName: taskName});
        gridTasksViewModel.lib.push(taskName);
    });
    
    $('li[data-bind*="click: analystByGroup"]').get(0).kendoBindingTarget.source.bind("change", function (event) {
        var vm = _.isUndefined(event.sender.observable) ? event.sender : event.sender.source,
            taskName = "AssignToAnalystByGroup",
            isEnabled = vm.get("isEnabled");
        console.log("analystByGroup change", {event: event, field: event.field, taskName: taskName, vm: vm, isEnabled: isEnabled});
        switch (event.field) {
            case "isEnabled":
                // TBD Update edit buttons to show enabled/disabled status
                if (isEnabled) {
                    gridTasksViewModel.lib.process(vm, taskName);
                } else {
                    gridTasksViewModel.lib.remove(taskName);
                }
                break;
            case "currentSelection":
                if (isEnabled) {
                    gridTasksViewModel.lib.process(vm, taskName);
                } else {
                    var keepPendingTask = false,
                        selectedDataItems = vm.get("currentSelection"),
                        selectedTypes = _.pluck(selectedDataItems, "WorkItemType"),
                        singleSelectedType = _.reduce(selectedTypes, function (memo, currentVal) {
                            return (memo === currentVal) ? memo : false;
                        });
                    if (singleSelectedType && selectedDataItems.length > 0 && selectedDataItems.length <= 10) {
                        switch (singleSelectedType) {
                            case "System.WorkItem.ServiceRequest":
                            case "System.WorkItem.Incident":
                                keepPendingTask = true;
                                break;
                        }
                    }
                    if (!keepPendingTask) {
                        gridTasksViewModel.lib.remove(taskName);
                    }
                }
            break;
        }
    });
    TBD:
    • Enabled/Disabled styling for buttons.
    • Update column template to handle additional buttons.

    EDIT: Modified the custom.js script to account for edge cases of swapping back and forth between non-IR/SR selections and then immediately selecting a valid option as well as moving tasks functions into a small library under gridTasksViewModel.lib for a better interface.
  • Ryan_LaneRyan_Lane Customer Advanced IT Monkey ✭✭✭
    edited November 26
    Hello!
    Hope everyone had a great holiday weekend.  For this small update of my work in progress I've made a bit of a breakthrough in altering grid columns dynamically without removing existing bindings or functionality.  Here are some screenshots of multiple button types per field, conditional filtering and formatting based on field values:
    My Work:

    Team Work:

    I'm still working on the grid tasks framework but so far it has provided a wealth of potential benefits:
    • No need to modify Cireson's source files, create custom views or modify view definitions in ServiceManagement db.
    • Efficiently uses Kendo's templating system to handle refreshes, page navigation and grid changes without mutation observers, timers or excessive subscriptions to any event systems.
    • Easily expandable to handle multiple separate functions per field.  So far I am working on the following functionality: edit buttons, info/popup buttons, conditional formatting and access control to these custom features.
    On another note, I've moved away from allowing multiple selections at once when clicking on individual field buttons so clicking an edit button will select that single row and un-select all other rows.  This still leaves the option of selecting multiple items and then clicking Assign To Analyst By Group under Tasks.

    Please let me know if anyone has any thoughts or ideas as I'm working on this one.  Thanks!
  • Mikkel_MadsenMikkel_Madsen Customer Adept IT Monkey ✭✭
    Looks very promising :smiley:

  • Ryan_LaneRyan_Lane Customer Advanced IT Monkey ✭✭✭
    edited November 30
    Hello!
    It's me again with another update on my work in progress for the custom buttons/styles in grids portion of this thread.
    I have created app.custom.gridTasks (in a similar vein to app.custom.formTasks) to handle adding custom tasks to specific grids. Using each Kendo grid's own column template array to store our custom data and anonymous functions to return angular template strings we can have any grid populate and use our custom code however we would like to without destroying the grids and undoing existing bindings from Cireson, subscriptions or other scripts.
    app.custom.gridTasks:
    app.custom.gridTasks = {
        add: function add (gridData, field, type, name, template, callback) {
    		var that = this,
                // Look for provided column in grid by field name
                taskColumn = $.grep(gridData.columns, function (colValue, colIndex) {
    			return colValue.field === field;
    		});
    		
    		if (taskColumn.length > 0) {
    			taskColumn = taskColumn[0];
    			if (_.isUndefined(taskColumn["style"])) {
    				// Add default blank style template function to column template
    				taskColumn["style"] = function defaultStyle (data) { return ""; };
    			}
    			
    			if (_.isUndefined(taskColumn["tasks"])) {
    				// Add empty tasks array to column template
    				taskColumn["tasks"] = [];
    			}
    			
    			switch (type) {
    				case "style":
    					// Set style template function to provided template
    					taskColumn["style"] = template
    					break
    				case "task":
    					var existingTask = that.get(gridData, field, name);
    					if (existingTask) {
    						// Merge new task with existing one in the column template
    						$.extend(existingTask, {
    							name : name,
    							template: template,
    							callback: callback
    						});
    					} else {
    						// Add new task to the column template
    						taskColumn["tasks"].push({
    							name : name,
    							template: template,
    							callback: callback
    						});
    					}
    					break;
    			}
    		} else {
    			console.log("gridTasks:add", "Warning! Unable to find field '" + field + "'.");
    		}
    	},
    	get: function get (gridData, field, name) {
    		// Look for provided column in grid by field name
    		var taskColumn = $.grep(gridData.columns, function (colValue, colIndex) {
    			return colValue.field === field;
    		});
    		
    		if (taskColumn.length > 0) {
    			taskColumn = taskColumn[0];
    			if (_.isUndefined(name)) {
    				// Return all tasks for the provided field				
    				return taskColumn["tasks"];
    			} else {
    				// Look for the specific task named in the provided field
    				var gridTask = $.grep(taskColumn["tasks"], function (taskValue, taskIndex) {
    					return taskValue.name === name;
    				});
    				
    				if (gridTask.length > 0) {
    					// Return the specific task in the provided field
    					return gridTask[0];
    				} else {
    					console.log("gridTasks:get", "Warning! Unable to find task '" + name + "' in field '" + field + "'.");
    					return null;
    				}
    			}
    		} else {
    			console.log("gridTasks:get", "Warning! Unable to find field '" + field + "'.");
    			return null;
    		}
    	},
    	callback: function callback (itemEle) { // item is the task element clicked 
    		var that = this,
                item = $(itemEle),
    			gridData = item.closest("div[data-role='grid']").data("kendoGrid"),
    			itemData = item.data(),
    			itemRowEle = item.closest("tr").get(0),
    			dataItem = gridData.dataItem(itemRowEle);
    			
    		console.log("gridTasks:callback", {
    			gridData: gridData,
    			itemRowEle: itemRowEle,
    			dataItem: dataItem,
    			itemData: itemData
    		});
    		
    		var existingTask = that.get(gridData, itemData.field, itemData.role);
    		if (existingTask) {
    			existingTask.callback(dataItem);
    		} else {
    			console.log("gridTasks:callback", "Unable to find task for callback.");
    		}
    	},
    	updateGrid: function (gridData) {
    		console.log("gridTasks:updateGrid", "Updating grid column templates");
    		var that = this,
                bUpdateGridTemplate = false;
    		
    		$.each(gridData.columns, function (colIndex, column) {
    			if (!_.isUndefined(column["style"])) {
    				column.template = that.build.cell(column);
    				bUpdateGridTemplate = true;
    			}
    		});
    		
    		if (bUpdateGridTemplate) {
    			// Update grid row templates if custom tasks/styles are added 
    			gridData.rowTemplate = gridData._tmpl(gridData.options.rowTemplate, gridData.columns);
    			gridData.altRowTemplate = gridData._tmpl(gridData.options.rowTemplate, gridData.columns);
    
    			// Refresh grid to show column template changes
    			gridData.refresh();
    		}
    	},
    	build: {
    		cell: function cell (column) {
    			var template = " \
    				<div class=\"ra-grid-task-container\" style=\"" + column.style(column) + "\"> \
    					<ul class=\"ra-grid-task-menu\">";
    						$.each(column["tasks"], function (taskIndex, task) {
    							template += task.template(column);
    						});
    						template += " \
    					</ul> \
    					<span class=\"ra-grid-task-content\"> \
    						#: " + column.field + " # \
    					</span> \
    				</div>";
    			return template;
    		},
    		listItem: function listItem (field, role, icon) {
    			icon = icon || 'fa-pencil';
    			
    			var template = " \
    				<li class=\"ra-grid-task-item\" data-role=\"" + role + "\" data-field=\"" + field + "\" onclick=\"app.custom.gridTasks.callback(this);\"> \
    					<a class=\"ra-icon ra-grid-task-icon\"> \
    						<i class=\"fa " + icon + "\"></i> \
    					</a> \
    				</li>";
    			return template;
    		}
    	}
    };
    

    Adding a grid style to Priority with different colors depending on value:
    var gridData = $("div[data-role='grid']").data("kendoGrid");
    app.custom.gridTasks.add(gridData, "Priority", "style", "", function (column) {
        // Custom Priority Style Template
        var template = " \
            # if (!_.isUndefined(Priority)) { \
                switch (Priority) { \
                    case \"4\": \
                        # # \
                        break; \
                    case \"3\": \
                        # background-color:rgba(0, 255, 0, 0.25); # \
                        break; \
                    case \"2\": \
                    case \"Medium\": \
                        # background-color:rgba(255, 255, 0, 0.25); # \
                        break; \
                    case \"1\": \
                    case \"High\": \
                        # background-color:rgba(255, 0, 0, 0.25); # \
                        break; \
                } \
            } #";
        return template;
    });


    Adding two grid tasks to AssignedUser with unique callbacks and filters:
    var gridData = $("div[data-role='grid']").data("kendoGrid");
    app.custom.gridTasks.add(gridData, "AssignedUser", "task", "GetUserInfo", function (column) {
        // Custom GetUserInfo Task Template
        var template = " \
            # if (!_.isUndefined(WorkItemType) && (WorkItemType==='System.WorkItem.Incident' || WorkItemType==='System.WorkItem.ServiceRequest')) { \
                if ( !_.isUndefined(AssignedUser) && AssignedUser !== \"\") { # \
                    " + app.custom.gridTasks.build.listItem("AssignedUser", "GetUserInfo", "fa-info-circle") + " \
                # } \
            } #";
        return template;
    }, function (dataItem) {
        console.log("GetUserInfo Callback", dataItem);
        return "";
    });
    
    app.custom.gridTasks.add(gridData, "AssignedUser", "task", "AssignToAnalystByGroup", function (column) {
        // Custom AssignToAnalystByGroup Task Template        
        var template = " \
            # if (!_.isUndefined(WorkItemType) && (WorkItemType==='System.WorkItem.Incident' || WorkItemType==='System.WorkItem.ServiceRequest')) { # \
                " + app.custom.gridTasks.build.listItem("AssignedUser", "AssignToAnalystByGroup", "fa-pencil") + " \
            # } #";
        return template;
    }, function (dataItem) {
        console.log("AssignToAnalystByGroup Callback", dataItem);
        return "";
    });
    


    Some custom CSS for our new grid task elements:
    .ra-grid-task-container {
    	display: block;
    	width: 100%;
    	height: 100%;
    	margin:-5px -6px -4px;
    	padding: 5px 6px 4px 6px;
    }
    
    .ra-grid-task-menu {
    	display: inherit;
    	list-style: none;
    	float:right;
    	text-align:right;
    	margin:-5px -6px -4px;
    	padding: 5px 0px 0px 6px;
    }
    
    .ra-grid-task-item {
    	display: inline-block;
    	margin: 0px 6px 4px 0px;
    }
    
    .ra-grid-task-icon {
    	display: inherit;
    }
    
    .ra-grid-task-content {
    	display: inline;
    	width: 100%;
    }

    And finally updating the grid to show our changes:
    var gridData = $("div[data-role='grid']").data("kendoGrid");
    app.custom.gridTasks.updateGrid(gridData);
    TBD:
    - Combining this new grid task functionality with my previous trigger script for Assign To Analyst By Group.
    - Adding the option of using a html file to define Kendo external templates.
    - Still potentially adding enable/disable functionality to buttons rather than just not rendering them.

    Please let me know if anyone has any thoughts or ideas as I'm working on this one.  Thanks!
  • Mikkel_MadsenMikkel_Madsen Customer Adept IT Monkey ✭✭
    Wow... I'm looking forward to get time to try some  of it out :smiley:

  • Ryan_LaneRyan_Lane Customer Advanced IT Monkey ✭✭✭
    edited December 4
    Hello!
    Hope you had a good weekend.  I have added quite a bit more polish on this (attached).
    - Custom task templates now support tasks and links.
    - Callbacks can now dynamically stop click propagation to the built-in click functionality.
    - Added to custom.css for better highlighting of tasks in the grid title and regular cell sections and removed the built-in right-arrow in Team Work/Active Work views.
    - Fully functional Assign To Analyst By Group and custom Title links for same page and new tab. (below)
    custom.js:
    app.custom.gridTasks = {
        add: function add (gridData, field, type, name, template, callback) {
            var that = this,
                // Look for provided column in grid by field name
                taskColumn = $.grep(gridData.columns, function (colValue, colIndex) {
                    return colValue.field === field;
                })[0];
    
            if (!_.isUndefined(taskColumn)) {
                if (_.isUndefined(taskColumn["style"])) {
                    // Add default blank style template function to column template
                    taskColumn["style"] = function defaultStyle (data) { return ""; };
                }
    
                if (_.isUndefined(taskColumn["tasks"])) {
                    // Add empty tasks array to column template
                    taskColumn["tasks"] = [];
                }
    
                switch (type) {
                    case "style":
                        // Set style template function to provided template
                        taskColumn["style"] = template
                        break
                    case "task":
                        var existingTask = that.get(gridData, field, name);
                        if (existingTask) {
                            // Merge new task with existing one in the column template
                            $.extend(existingTask, {
                                name : name,
                                template: template,
                                callback: callback
                            });
                        } else {
                            // Add new task to the column template
                            taskColumn["tasks"].push({
                                name : name,
                                template: template,
                                callback: callback
                            });
                        }
                        break;
                }
            } else {
                console.log("gridTasks:add", "Warning! Unable to find field '" + field + "'.");
            }
        },
        get: function get (gridData, field, name) {
            // Look for provided column in grid by field name
            var taskColumn = $.grep(gridData.columns, function (colValue, colIndex) {
                return colValue.field === field;
            })[0];
    
            if (!_.isUndefined(taskColumn)) {
                if (_.isUndefined(name)) {
                    // Return all tasks for the provided field
                    return taskColumn["tasks"];
                } else {
                    // Look for the specific task named in the provided field
                    var gridTask = $.grep(taskColumn["tasks"], function (taskValue, taskIndex) {
                        return taskValue.name === name;
                    })[0];
    
                    if (!_.isUndefined(gridTask)) {
                        // Return the specific task in the provided field
                        return gridTask;
                    } else {
                        console.log("gridTasks:get", "Warning! Unable to find task '" + name + "' in field '" + field + "'.");
                        return null;
                    }
                }
            } else {
                console.log("gridTasks:get", "Warning! Unable to find field '" + field + "'.");
                return null;
            }
        },
        callback: function callback (itemEle, bClickPropagation) { // item is the task element clicked, bClickPropagation determines if click event should propagate
            var that = this,
                item = $(itemEle),
                gridData = item.closest("div[data-role='grid']").data("kendoGrid"),
                itemData = item.data(),
                itemRowEle = item.closest("tr").get(0),
                dataItem = gridData.dataItem(itemRowEle),
                data = {
                    gridData: gridData,
                    itemRowEle: itemRowEle,
                    dataItem: dataItem,
                    itemData: itemData
                }
    
            console.log("gridTasks:callback", data);
    
            var existingTask = that.get(gridData, itemData.field, itemData.task);
            if (existingTask) {
                // Stop click propagation for jQuery click events if requested
                if (!bClickPropagation) {
                    event.stopPropagation();
                }
                existingTask.callback(data);
            } else {
                console.log("gridTasks:callback", "Unable to find task for callback.");
            }
        },
        updateGrid: function (gridData) {
            var that = this,
                bUpdateGridTemplate = false;
    
            $.each(gridData.columns, function (colIndex, column) {
                if (!_.isUndefined(column["style"])) {
                    column.template = that.template.cell(column);
                    bUpdateGridTemplate = true;
                }
            });
    
            if (bUpdateGridTemplate) {
                // Update grid row templates if custom tasks/styles are added
                gridData.rowTemplate = gridData._tmpl(gridData.options.rowTemplate, gridData.columns);
                gridData.altRowTemplate = gridData._tmpl(gridData.options.rowTemplate, gridData.columns);
    
                // Refresh grid to show column template changes
                gridData.refresh();
            }
        },
        template: {
            cell: function cell (column) {
                var template = " \
                    <div class=\"ra-grid-task-container\" style=\"" + column.style(column) + "\"> \
                        <ul class=\"ra-grid-task-menu\">";
                            $.each(column["tasks"], function (taskIndex, task) {
                                template += task.template(column, task);
                            });
                            template += " \
                        </ul> \
                        <span class=\"ra-grid-task-content\"> \
                            #: " + column.field + " # \
                        </span> \
                    </div>";
                return template;
            },
            listItem : {
                task: function task (field, task, options) {
                    var properties = {
                        field: field,
                        task: task,
                        icon: "fa-pencil",
                        bClickPropagation: true
                    };
    
                    $.extend(properties, options);
    
                    var template = " \
                        <li class=\"ra-grid-task-item\" data-task=\"" + properties.task + "\" data-field=\"" + properties.field + "\" onclick=\"app.custom.gridTasks.callback(this, " + properties.bClickPropagation + ");\"> \
                            <a class=\"ra-icon ra-grid-task-icon\"> \
                                <i class=\"fa " + properties.icon + "\"></i> \
                            </a> \
                        </li>";
                    return template;
                },
                link: function link (field, task, options) {
                    var properties = {
                        field: field,
                        task: task,
                        icon: "fa-external-link",
                        bClickPropagation: false,
                        className: "",
                        href: "/",
                        target: "_blank"
                    }
    
                    $.extend(properties, options);
    
                    var template = " \
                        <li class=\"ra-grid-task-item " + properties.className + "\" data-task=\"" + properties.task + "\" data-field=\"" + field + "\" onclick=\"app.custom.gridTasks.callback(this, " + properties.bClickPropagation + ");\"> \
                            <a class=\"ra-icon ra-grid-task-icon\" href=\"" + properties.href + "\" target=\"" + properties.target + "\" > \
                                <i class=\"fa " + properties.icon + "\"></i> \
                            </a> \
                        </li>";
                    return template;
                }
            }
        }
    };
    custom.css:
    /*
        Custom Grid Tasks
    */
    
    .k-grid tr:hover td.grid-highlight-column-last a:after,
    .k-grid tr:hover td.grid-highlight-column-title a:after,
    .k-grid .k-state-selected td.grid-highlight-column-last a:after,
    .k-grid .k-state-selected td.grid-highlight-column-title a:after {
        content: none;
    }
    
    .k-grid .ra-grid-task-container {
        display: block;
        width: 100%;
        height: 100%;
        margin:-5px -6px -4px;
        padding: 5px 6px 4px 6px;
    }
    
    .k-grid .grid-highlight-column .ra-grid-task-menu,
    .k-grid .grid-highlight-column-title .ra-grid-task-menu,
    .k-grid .grid-highlight-column-last .ra-grid-task-menu {
        margin-right: -20px;
        visibility: hidden;
    }
    
    .k-grid tr:hover .ra-grid-task-menu,
    .k-grid .k-state-selected .ra-grid-task-menu {
        visibility: visible;
    }
    
    .k-grid .k-state-selected td.grid-highlight-column .ra-grid-task-menu i,
    .k-grid .k-state-selected td.grid-highlight-column-title .ra-grid-task-menu i,
    .k-grid .k-state-selected td.grid-highlight-column-last .ra-grid-task-menu i,
    .grid-highlight-column .ra-grid-task-container i,
    .grid-highlight-column-title .ra-grid-task-container i,
    .grid-highlight-column-last .ra-grid-task-container i {
        color: #a3b8c2;
    }
    
    .k-grid .k-state-selected td.grid-highlight-column .ra-grid-task-menu i:hover,
    .k-grid .k-state-selected td.grid-highlight-column-title .ra-grid-task-menu i:hover,
    .k-grid .k-state-selected td.grid-highlight-column-last .ra-grid-task-menu i:hover,
    .k-grid .k-state-selected .ra-grid-task-container i:hover,
    .grid-highlight-column .ra-grid-task-container i:hover,
    .grid-highlight-column-title .ra-grid-task-container i:hover,
    .grid-highlight-column-last .ra-grid-task-container i:hover,
    .k-grid tr:hover .ra-grid-task-menu .ra-highlight-default-icon i {
        color: #fff;
    }
    
    .grid-highlight-column ul.ra-grid-task-menu:hover li.ra-highlight-default-icon i,
    .grid-highlight-column-title ul.ra-grid-task-menu:hover li.ra-highlight-default-icon i,
    .grid-highlight-column-last ul.ra-grid-task-menu:hover li.ra-highlight-default-icon i {
        color: #a3b8c2;
    }
    
    .grid-highlight-column ul.ra-grid-task-menu:hover li.ra-highlight-default-icon i:hover,
    .grid-highlight-column-title ul.ra-grid-task-menu:hover li.ra-highlight-default-icon i:hover,
    .grid-highlight-column-last ul.ra-grid-task-menu:hover li.ra-highlight-default-icon i:hover {
        color: #fff;
    }
    
    .k-grid .ra-grid-task-menu {
        display: inherit;
        list-style: none;
        float:right;
        text-align:right;
        margin:-5px -6px -4px;
        padding: 5px 0px 0px 6px;
    }
    
    .k-grid .ra-grid-task-item {
        display: inline-block;
        margin: 0px 6px 4px 0px;
    }
    
    .k-grid .ra-grid-task-icon {
        display: inherit;
    }
    
    .k-grid .ra-grid-task-content {
        display: inline;
        width: 100%;
    }

    WIP In Action:
    The script below shows a fully functional customization with:
    - Internal/External Links in Title.
    - Quick edit buttons for Assign To Analyst By Group in Assigned User
    - Background color conditional formatting for Priority.

    // Adding a grid style to Priority with different depending on value:
    var gridData = $("div[data-role='grid']").data("kendoGrid");
    app.custom.gridTasks.add(gridData, "Priority", "style", "", function (column) {
        // Custom Priority Style Template
        var template = " \
            # if (!_.isUndefined(Priority)) { \
                switch (Priority) { \
                    case \"4\": \
                        # # \
                        break; \
                    case \"3\": \
                        # background-color:rgba(0, 255, 0, 0.25); # \
                        break; \
                    case \"2\": \
                    case \"Medium\": \
                        # background-color:rgba(255, 255, 0, 0.25); # \
                        break; \
                    case \"1\": \
                    case \"High\": \
                        # background-color:rgba(255, 0, 0, 0.25); # \
                        break; \
                } \
            } #";    
        return template;
    });
    
    if (session.user.Analyst) {
        // Adding custom internal and external links to the Title column
        app.custom.gridTasks.add(gridData, "Title", "task", "TitleLinks", function (column, task) {
            // Custom Title Links Task Template
            var template = " \
                # var url = app.gridUtils.getLinkUrl(data, \"***\"); \
                if (!_.isUndefined(WorkItemType) && (WorkItemType==='System.WorkItem.Incident' || WorkItemType==='System.WorkItem.ServiceRequest')) { #" +
                    app.custom.gridTasks.template.listItem.link(column.field, task.name, {
                        href: "#=url#"
                    }) +
                "# } else if ((!_.isUndefined(WorkItemType)&& WorkItemType.indexOf('Activity') != -1)) { \
                    var approvalUrl = app.gridUtils.getApprovalLinkUrl(data); # " +
                    app.custom.gridTasks.template.listItem.link(column.field, task.name, {
                        icon: "fa-check",
                        href: "#=approvalUrl#"
                    }) + " \
                # } # " +
                app.custom.gridTasks.template.listItem.link(column.field, task.name, {
                    icon: "fa-arrow-right",
                    bClickPropagation: true,
                    className: "ra-highlight-default-icon",
                    href: "#=url#",
                    target: ""
                });
            return template;
        }, function (data) {
            console.log("TitleLinks Callback", data);
        });
    
        // Adding grid task to trigger AssignToAnalystByGroup
        app.custom.gridTasks.add(gridData, "AssignedUser", "task", "AssignToAnalystByGroup", function (column, task) {
            // Custom AssignToAnalystByGroup Task Template
            var template = " \
                # if (!_.isUndefined(WorkItemType) && (WorkItemType==='System.WorkItem.Incident' || WorkItemType==='System.WorkItem.ServiceRequest')) { #" +
                    app.custom.gridTasks.template.listItem.task(column.field, task.name, {
                        icon: "fa-pencil",
                        bClickPropagation: false
                    }) + " \
                # } #";
            return template;
        }, function (data) {
            console.log("AssignToAnalystByGroup Callback", data);
            data.gridData.clearSelection();
            data.gridData.select(data.itemRowEle);
    
            var assignToAnalystByGroupButton = $('li[data-bind*="click: analystByGroup"]').first();
    
            assignToAnalystByGroupButton.click();
        });
    }
    
    // Updating the grid to show our changes:
    app.custom.gridTasks.updateGrid(gridData);
    TBD:
    - Adding the option of using html files to define Kendo external templates.
    - Potentially adding enable/disable functionality to buttons rather than just not rendering them. Leaning more on a no on this feature as I go.
    - Removing custom tasks and potentially resetting grid columns to out of the box.

    Please let me know if anyone has any thoughts or ideas as I'm working on this.  Thanks!
  • Justin_WorkmanJustin_Workman Cireson Support Ninja IT Monkey ✭✭✭✭
    @Ryan_Lane -  These customizations look awesome!  You're knocking it out of the park!  You might consider a github project for organization's sake(and potential contribution by others).
  • Brian_WiestBrian_Wiest Customer Super IT Monkey ✭✭✭✭✭
    Both the previous version and the latest I am getting an error "Uncaught TypeError: cannot read property "columns' of undefined."
    Testing on the latest portal release v8.10.0.x and v8.11.0.x
    Suggestions?
  • Ryan_LaneRyan_Lane Customer Advanced IT Monkey ✭✭✭
    edited December 4
    @Justin_Workman Good point! I've created CustomGridTasks on GitHub.
    @Brian_Wiest That's most likely due to the script triggering before the grid is ready to be modified. A quick subscription to the dynamicPageReady event and a new variable to track if our customization is done at app.custom.gridTasks.built should do it.  I have updated, renamed and pushed custom.js and custom.css to the github repo.

    Related new code from custom.js (updated with latest push):
    app.custom.gridTasks = {
        built: false,
    ...
    };
    
    app.events.subscribe("dynamicPageReady", function () {
        console.log("dynamicPageReady Event", "Triggered at " + performance.now());
        if (app.custom.gridTasks.built) {
            return;
        }
    
        var gridData = $("div[data-role='grid']").data("kendoGrid");
        if (!_.isUndefined(gridData)) {
    ...
            app.custom.gridTasks.built = true;
        }
    });
    

    Thanks for the feedback!

    EDIT: I've also added a quick check after the dynamicPageReady event to confirm the page actually has a grid to customize.  Updated custom.js has been pushed.
  • Brian_WiestBrian_Wiest Customer Super IT Monkey ✭✭✭✭✭
    That did the trick. Thanks
  • Ryan_LaneRyan_Lane Customer Advanced IT Monkey ✭✭✭
    @Brian_Wiest Thanks for testing!  I have updated CustomGridTasks to disable enumeration on the custom properties _tasks and _style so they are no longer passed to jQuery when additional Ajax queries are made.  This was mainly a problem after resizing a column but will fix any other potential queries as well.

  • Brian_WiestBrian_Wiest Customer Super IT Monkey ✭✭✭✭✭
    edited December 7
    I have rolled it out to production and analysts are liking the priority colors. Just have to work on the pencil icon as our color scheme has it yellow against a dark grey background for the bottom bar. So its yellow in the column and hard to see. Playing with options for a pencil 2 with different color. BTW excellent work. :)


  • Ryan_LaneRyan_Lane Customer Advanced IT Monkey ✭✭✭
    edited December 7
    Thanks @Brian_Wiest!
    If you'd like to target the non-title section icons you can use the following CSS:
    a.ra-grid-task-icon i {
        color: #FF0000;
    }
    
    a.ra-grid-task-icon i:hover {
        color: #00FF00;
    }
    This works with the other CustomGridTask CSS in order of complexity so we can keep the title section links replicating the out of the box behavior while targeting the new icons with new coloring.

    Example 1:
    1. Selected Row
    2. Unselected Row
    3. Hovered Row & Icon


    Example 2:
    1. Selected Row & Hovered Icon 
    2. Unselected Row
    3. Unselected Row

    If you'd also like to change the icon color behavior when selected and hovering let me know and I'll see about the CSS for that scenario.


    EDIT:  I have added the examples as commented out classes in custom.css.  Also, I have made some light changes to custom.js to minimize the amount of whitespace in the final cell templates so that jQuery isn't sending unnecessarily large numbers of empty characters to the server when columns are converted to params:


    Have a good weekend all!
Sign In or Register to comment.