GoFiler features a number of collaboration tools for use in streamlining a filer or agent’s workflow. These include notifications, control functions, and account control. One of the more commonly used and powerful of these features is task tracking. Task tracking allows you to assign particular tasks to individual users and monitor their progress on those tasks. It also allows users to view the status of the tasks assigned to them and to other people. This is extremely helpful when dividing a complex project amongst different workers.
GoFiler allows you to create and store tasks in three different places: at an enterprise level, at a user level, and at a project level. Enterprise tasks are stored in a network drive. They are able to be seen by anyone who has their Enterprise tasks folder pointed to the same location. This allows global, overarching tasks to be stored in a common area. User tasks are maintained in a user’s local %appdata%. These tasks are generally applicable in situations where task progress doesn’t need to be tracked on a global scale. Finally, project tasks are stored inside of a GoFiler project file (.gfp) and are typically specific to that particular project. They are available to whomever currently has that file open.
Tasks can have a number of different types of information stored in them: subject (name), status, assignee, percent complete, priority, category, owner (creator), action block (these functions are disabled until the task is complete), additional information, and timeline information (date created, finished, due, etc). I’ll talk more about how to access this information in just a bit. As an introduction to how to use tasks in Legato, I’ve created a small function that hooks into opening a project to display any tasks attached to that project with their status. This allows users to see the overall status of how work on a filing is progressing whenever they open the project.
This week I’m splitting up our script just as a reminder that you don’t always need to have the function that performs the hook setup in the same file as the function being hooked into the menu item. You can make a general purpose script file that hooks multiple scripts into the application. In this case, we just have one:
int rc;
rc = MenuSetHook("PSEUDO_OPENED_PROJECT", GetScriptFolder() + "\\listTasks.ls", "run");
if (rc == ERROR_NONE) {
MessageBox("Successfully hooked");
}
else {
MessageBox("Failed to hook with return code: %8x", rc);
}
Check previous blog posts for information on enumerating GoFiler menu function IDs and how to hook functions onto a menu item. On the run action of the open project menu action, I am going to hook in our function, located in “listTasks.ls” in the script folder. Below are the contents of the listTask,ls file:
int run(int f_id, string mode) {
handle edit_window;
handle iv_window;
dword file_type;
string tasksloc[];
string taskprop[];
int i;
int taskscount;
if (mode != "postprocess") {
return ERROR_NONE;
}
edit_window = GetEditWindowHandle();
file_type = GetEditWindowType(edit_window);
if (file_type == 0) {
MessageBox("Failed to read opened file");
}
if ((file_type & EDX_TYPE_ID_MASK) != EDX_TYPE_EDGAR_VIEW) {
MessageBox("Not a project: %0x", file_type);
return ERROR_NONE;
}
tasksloc = GetTaskIDs(CM_LOCATION_PROJECT);
taskscount = GetTaskCount(CM_LOCATION_PROJECT);
if (taskscount > 0) {
log_window = LogCreate("Project Tasks");
AddMessage(log_window, "Number of Tasks: %d", taskscount);
LogIndent(log_window);
for (i = 0; i < taskscount; i++) {
taskprop = GetTaskProperties(tasksloc[i]);
AddMessage(log_window, "Task Name: %s", taskprop["Subject"]);
LogIndent(log_window);
AddMessage(log_window, "Status: %s", taskprop["Status"]);
LogOutdent(log_window);
}
LogOutdent(log_window);
LogDisplay(log_window);
return ERROR_NONE;
}
}
int main() {
// make sure the function is set up.
setup();
return ERROR_NONE;
}
I’m going to specify some local variables I’ll need, including a few window handles, a couple of string arrays to hold the tasks, and some counting variables. I begin by immediately checking the mode of the call to the run function, and if it’s not “postprocess”, I immediately exit. After that, I’ll try to get a handle to the edit window:
edit_window = GetEditWindowHandle();
file_type = GetEditWindowType(edit_window);
if (file_type == 0) {
MessageBox("Failed to read opened file");
}
if ((file_type & EDX_TYPE_ID_MASK) != EDX_TYPE_EDGAR_VIEW) {
MessageBox("Not a project: %0x", file_type);
return ERROR_NONE;
}
I need to be sure we have a GoFiler project file open before proceeding, so I use the GetEditWindowHandle and GetEditWindowType SDK functions to get access to the window itself. Using the bitwise & operator, I check the file_type variable against EDX_TYPE_EDGAR_VIEW to ensure the user has opened an EDGAR project. If not, the script alerts the user with a message box and exits.
Once I’m sure we have the right type of window handle and project open, I can start to enumerate the tasks associated with that project.
tasksloc = GetTaskIDs(CM_LOCATION_PROJECT);
taskscount = GetTaskCount(CM_LOCATION_PROJECT);
The GetTaskIDs SDK function will retrieve the list of task IDs as strings and return an array of them. You can specify which location you want to query. In this case, I tell it to look at the project level with the CM_LOCATION_PROJECT value, but there are other options listed in the Legato SDK. Similarly, the GetTaskCount function retrieves the number of tasks available at that particular location.
if (taskscount > 0) {
log_window = LogCreate("Project Tasks");
AddMessage(log_window, "Number of Tasks: %d", taskscount);
LogIndent(log_window);
for (i = 0; i < taskscount; i++) {
taskprop = GetTaskProperties(tasksloc[i]);
AddMessage(log_window, "Task Name: %s", taskprop["Subject"]);
LogIndent(log_window);
AddMessage(log_window, "Status: %s", taskprop["Status"]);
LogOutdent(log_window);
}
LogOutdent(log_window);
LogDisplay(log_window);
}
If the taskcount is greater than zero, I’ll make a log to show the tasks to the user. I’ll do that through the LogCreate SDK function. This will create a separate log entitled “Project Tasks” for the user and return a handle I can use to reference my log for subsequent use. I’ll add a message about the total number of tasks and use the LogIndent function to begin printing my next line below my message and indented. Next I’ll use a for loop to iterate through the tasks.
The GetTaskProperties function does most of my work here. It retrieves an string array of properties associated with the numeric task ID. I hand this function one task ID at a time, and with the returned array of properties for each task, I fill the log. The GetTaskProperties function returns an array with specified key names, so that makes it easier to reference which information I’d like to include. For more information on the task property key names, see the Legato SDK. In this case, I’m going to print the “Subject” field and the “Status” field. Of course, you can print more information as necessary. The LogIndent and LogOutdent functions help me format my information to make it more easily readable.
When the loop is complete, I simply use the LogDisplay function to display the task log.
Number of Tasks: 2
Task Name: Prepare HTML
Status: Not Started
Task Name: Send Proof to Client
Status: Waiting
So this is a quick and easy way to display tasks automatically to users when they open a project with project-level tasks associated with it. You can modify this script to enumerate the tasks in other locations, such as an enterprise level collaboration store. In subsequent posts, I’ll talk more about how to add, delete, and manage tasks to make your project management and workflow even more efficient.
Joshua Kwiatkowski is a developer at Novaworks, primarily working on Novaworks’ cloud-based solution, GoFiler Online. He is a graduate of the Rochester Institute of Technology with a Bachelor of Science degree in Game Design and Development. He has been with the company since 2013. |
Additional Resources
Novaworks’ Legato Resources
Legato Script Developers LinkedIn Group
Primer: An Introduction to Legato