Simple Productivity/Interruption Tracker

Post your working scripts, libraries and tools for AHK v1.1 and older
User avatar
AlleyArtwork
Posts: 44
Joined: 09 Jun 2015, 21:08

Simple Productivity/Interruption Tracker

13 Sep 2018, 08:30

Hi All,
At work I began to need to track how often my team (or myself) was being interrupted, especially for un-ticketed or non-Jira task duties..
  • Who was being interrupted (the me or my team part)
  • Who interrupted us
  • How much time did it take
  • What was the method of interruption
  • what the interruption involved.
With my whole team contributing, we were able to find out who the most common interrupters were, what issues they were having, their favorite means of causing disruption, how much additional untracked time was being used up, and who on our team was being harassed the most.
This allowed us to better guide people to follow process, or review/create KB material if needed to help deter interruptions.

Since one option is to open a Read Only report in a CSV file, you can safely play around with the report in excel, pivot data, graph charts etc to help visualize metrics if needed, without corrupting the data file. (Read only as in, changes to the report do not write to the database file, but you can still do whatever you want to the CSV file.)
Image
As with all things, i'm sure someone here can look at this and make it even better (especially the GUI which I am sure is laughable), but we've discovered that the data provided by tracking productivity interruptions has helped us identify offenders and schedule process training or other automations to help minimize or eliminate future interruptions from frequent offenders, or help with making cases about project interruptions due to other priorities (say a severity incident, or impromptu emergency from someone you probably shouldn't say no to).

Quick Start Guide:
on first use:
1) click New Database
2) Create a TXT file in a location of your choosing, then select that file
3) you can now save input with the GUI.

Other notes:
- The LogonID field is freeform, so if you wanted to track against something other than people, you may (like a cross-team project name for example)
- The Minutes/duration is also freeform if you want a custom value.
- The "report" opens data in CSV. If you are using excel you can then Pivot table & Graph out any datapoint you would like.
- If you only use this for yourself, you can create a local or home-drive file
- if you want this accessible for a team, you can create a file on a team's network drive
- if you want this available through out an entire department/business, you can create a file on a network share available by all teams

Code: Select all

;---------------------------------------------------------------
; Rudimentary Tracker.  CTRL + WinKey + T
; While the LogonID field was built in mind with AD User IDs, it is Free Form so you can track against a person or a project if desired.
;---------------------------------------------------------------

;-----------------
; Set Hotkey to desired hotkey
^#t::

;-----------------
; Check for INI settings file which houses the DB path and dropdown menu settings
; If no existing settings, create some basic settings.
IfNotExist, %A_MyDocuments%\distracktersettings.ini
{
	defaultdb = Please Connect to or Create a Database
	timedurdropdown = 5||10|15|20|25|30|35|40|45|50|55|60
	interruptname = Phone|Walk-up|Email|IM / Skype|Slack / Teams
	IniWrite, %timedurdropdown%, %A_MyDocuments%\distracktersettings.ini, timeduration, Key
	IniWrite, %interruptname%, %A_MyDocuments%\distracktersettings.ini, categories, Key
	IniWrite, %defaultdb%, %A_MyDocuments%\distracktersettings.ini, DBpath, Key
}

;-----------------
; Check if Window is already open and activate it.
IfWinExist, DisTrackter
{
	WinActivate, DisTrackter
}
else,
{
;-----------------
; GUI

; Import settings from INI
	IniRead, timetrackerdb, %A_MyDocuments%\distracktersettings.ini, DBpath, Key
	IniRead, timedurdropdown, %A_MyDocuments%\distracktersettings.ini, timeduration, Key
	IniRead, interruptname, %A_MyDocuments%\distracktersettings.ini, categories, Key
	
	
; Button/Text for Instructions Connect Database and New Database
	Gui, 99:Add, Text, x12 y3 w110 r1 ginstructions cblue, Click for instructions
	Gui, 99:Add, text, x130 y3 w110 r1 gchangedb vchangedb cgray, [ Connect Database ]
	Gui, 99:Add, Text, x250 y3 w110 r1 gnewdb vnewdb cgray, `+[ ] New database
	
	
; ; ComboBox Group (To replace Radio Buttons and allow for custom Interruption Type)
	Gui, 99:Add, GroupBox, x5 y21 h44 w335 cpurple center, Interruption Type / Project Name / Ticket#
	Gui, 99:Add, ComboBox, x12 y37 w320 vdistruptiontype, %interruptname% 
	
; Text Fields
	Gui, 99:Add, Text, x5 y72 w40, LogonID:
	Gui, 99:Add, Edit, x50 y70 w75  voffender, 
	Gui, 99:Add, Text, x5 y100 w40, Desc:
	Gui, 99:Add, Edit, x50 y95 w290  vdetails, 
	Gui, 99:Add, Text, x128 y72 w40, Duration/Min:
	Gui, 99:add,ComboBox, x195 y70 w50 vtimespent, %timedurdropdown% 
	
; Buttons
	Gui, 99:Add, Button, x252 y70 w90 h20 gcheckname checkname, Check LogonID
	Gui, 99:Add, Button, x5 y130 w65 h20 greport vreport, View Report
	Gui, 99:Add, Button, x73 y130 h20 gdbopen vdbopent cgrey, Edit DB
	Gui, 99:Add, Button, x252 y120 w90 h30 Default gsubmit vsubmit, Submit
	Gui, 99:Add, Button, x160 y130 w90 h20 gcancel vcancel, Cancel/Close
	
	Gui, 99:Add, Text, x5 y155 w100 r1 cgray gabout, `? About
	Gui, 99:Add, Text, x290 y155 w100 r1 h15 cgray gsettings, < Settings >
	Gui, 99:Add, StatusBar,, DB:  %timetrackerdb%
	
	Gui, 99:Show, w350 h195, DisTrackter 
	return
	
;-----------------
; AD Query to check for names.
	checkname:
	gui, submit, nohide
	
	if offender =
	{
		MsgBox, You didn't enter any information!  Try Again!
		return
	}
	userdata = 
	loopnumber = 
	savefile = %a_mydocuments%\userdata.txt
	FileDelete, %savefile%
	
;*******GetADObjectArray Function********;
	GetADObjectArray(Query) {
		objConnection := ComObjCreate("ADODB.Connection")
		objConnection.Open("Provider=ADsDSOObject;")
		
		objCommand := ComObjCreate("ADODB.Command")
		objCommand.ActiveConnection := objConnection
		objCommand.Properties("Page Size") := 100000
		objCommand.CommandText := Query
		objRecordSet := objCommand.Execute
		
;Create and populate a generic object with the data.
		ADObjectArray := Object()
		while objRecordSet.EOF = 0
		{
			ADObject := Object()                
			for f in objRecordSet.fields
			{
				ADObject[f.name] := f.value
			}
			ADObjectArray[a_index] := ADObject
			try {
				objRecordSet.MoveNext
			}
			catch e {
				msgbox, No Dice.
				break
			}
		}
		objRecordSet.Close
		objConnection.Close
		query =
		return ADObjectArray   
	}   
;*******END - GetADObjectArray Function********;
	
;Build AD Query String   
	UserQuery = SELECT pwdlastset, title, description, mail, sAMAccountName, employeeID, displayName, name, cn, sn, homeDirectory, telephoneNumber FROM 'LDAP://dc=rgl,dc=net' where objectCategory='user' AND samaccountname='*%offender%*'
	
	Data := GetADObjectArray(UserQuery)
	
;Loop through Each record row returned from ADQuery
	for k,v in Data
	{
		thename := v["displayName"]
		thefullname := v["name"]
		themail := v["mail"]
		thephone := v["telephoneNumber"]
		thepdrive := v["homeDirectory"]
		thepwdls := v["pwdlastset"]
		thetitle := v["title"]
		thedesc := v["description"]
		thefirstname := v["cn"]
		thelastname := v["sn"]
		thesaman := v["sAMAccountName"]
		
		;~ loopnumber := (a_index - 1)
		loopnumber := a_index
		
		;~ MsgBox, Loop`#%loopnumber%`nquery: %offender%`nName: %thename%
		
		userdata = %userdata%RESULT %loopnumber%: %thesaman% | %thefullname% | %thetitle%`n
		
		if thesaman =
		{
			MsgBox, The user doesn't appear to exist.
			return
		}	
	}
	; Clear Variables
	thename:=themail:=thephone:=thepdrive:=thepwdls:=thetitle:=thedesc:=thefirstname:=thelastname:=thesaman:=adstatus:=theregion:=theoffice:=""
	
	if userdata !=
	{
		userdata = ***Please Choose a UserID below ***`n`n`n%userdata%
		FileAppend, %userdata%, %savefile%
		sleep, 200
		run, %savefile%
		sleep, 200
	}
	
	return
	return
	
;-----------------
; Submits data to the DB using the field information
	submit:
	gui, submit, nohide

; Check for empty Fields
	if timetrackerdb = %defaultdb%
	{
		MsgBox, Before you can save data you need to do one of the following:`n1) Change/Select an existing database, or... `n2) Create a new database TXT file.
		return
	}
	
	if distruptiontype = 
	{
		MsgBox, Choose an interruption type from the Drop Down`n(Such as Slack, IM, Walkup etc.)
		return
	}
	
	if details =
	{
		MsgBox, You didn't enter any information!  Try Again!
		return
	}

	; If Offender/Login ID field is left empty, adds your own username to this field. Maybe you had to do some KB documentation or something.
	if offender =
	{
		offender := A_UserName
	}
	
	
	StringReplace, offender, offender, `|,, all
	StringReplace, offender, offender, %A_Space%,, all
	StringReplace, details, details, `,, `;, all
	FileAppend, %A_MM%/%A_DD%/%A_YYYY%`,%A_Hour%:%A_Min%`,%a_username%`,%distruptiontype%`,%offender%`,%timespent%`,%details%`n, %timetrackerdb%
;~ gosub, 99GuiClose
	GuiControl,, offender, 
	GuiControl,, details, 
	GuiControl,, Submit, Data Entered!
	sleep, 1000
	GuiControl,, Submit, Submit
	return
	
;-----------------
; Change Database file
	changedb:
	gui, submit, nohide
	MsgBox, Locate the Database file you wish to Connect to.
	FileSelectFile, dbfilepath, ,,Choose your Team's Database file, *.txt
	if errorlevel
		return
	
	IniWrite, %dbfilepath%, %A_MyDocuments%\distracktersettings.ini, DBpath, Key
	IniRead, timetrackerdb, %A_MyDocuments%\distracktersettings.ini, DBpath, Key
	
	SB_SetText("DB:  "  timetrackerdb)
	
	return
	
;-----------------
; Create new DB
	newdb:
	gui, submit, nohide
	MsgBox, Create a new TXT file for your database in a location of your choosing.
	FileSelectFile, dbfilepath, ,,Choose your Team's Database file, *.txt
	if errorlevel
		return

	FileAppend, DATE`,TIME`,LOGGED_BY`,TYPE`,WHO`,TimeSpent`,DETAILS`n, %dbfilepath%
		
	IniWrite, %dbfilepath%, %A_MyDocuments%\distracktersettings.ini, DBpath, Key
	IniRead, timetrackerdb, %A_MyDocuments%\distracktersettings.ini, DBpath, Key
	
	SB_SetText("DB:  "  timetrackerdb)
	return
	
;-----------------
; INSTRUCTIONS Message Box
	instructions:
	MsgBox, ** FIRST TIME USE:  Be sure to Connect Database to your team's Tracker Database.`nOptionally you can create a new database for your team or for private use.`n`n--Standard Use--`n1) Choose an interruption type.`n2) Enter user's Logon name.`n3) Enter a Description (include ticket if required)`n4) Choose a duration in munutes of the interruption (dropdown or enter custom).`n5) Click Submit!`n`n--Other Notes--`n- Your Login (as interruptee) is automatically saved to the Database and time-stamped with each entry.`n- If LoginID (interrupter) is left empty it defaults to yourself.`n- VIEW REPORT is read only. If you need to make a correction`, please use the Edit DB button.`n- You can use Check Username to confirm user's actual logon. This is to keep data entry consistent so that a user isn't being entered in multiple ways. (joe.smith, jsmith etc.)
	return
	
;-----------------
; Runs a read only report on tracked data by reading the DB and putting it into a separate CSV file for viewing, pivoting, graphing in Excel
	report:
	IfWinExist, timetracker.csv
	{
		WinActivate, timetracker.csv
	}
	else,
	{
		FileDelete, %A_MyDocuments%\timetracker.csv
		FileRead, timetrackerdata, %timetrackerdb%
		FileAppend, %timetrackerdata%, %A_MyDocuments%\timetracker.csv
		run, %A_MyDocuments%\timetracker.csv
	}	
	return
	
;-----------------
; Opens the "Database" text file if corrections need to be made.	
	dbopen:
	run, %timetrackerdb%
	return
	
	about:
	MsgBox, Created by Alley Artwork`nUsing AutoHotkey v1.1.30.00
	return
	
	settings:
	MsgBox, If you change any settings`nCLOSE AND RE-LAUNCH the application.`n`nValues are separated by Pipe:`nValue1|Value2|Value3
	run, %A_MyDocuments%\distracktersettings.ini
	return
	
;-----------------
; Close GUI by cancel button
	Cancel:
	Gui Destroy
	ExitApp
	return
	
;-----------------
; Close GUI by Windows "X" button
	99GuiClose:
	Gui Destroy
	ExitApp
	return
	
	return
}
return
Updates: 5/4/19
  • I removed the radio button menu and replaced with a dropdown. This means you can have a much larger variety of things to track and not take up additional space.
  • Added utilization of INI file to save settings.
    • This way if others that don't use AHK but want to use the tracker, you can compile it and they can still customize the settings, or simply customize without editing the script directly.
    • INI settings store Interruption type list, time increments, and database file location
    • INI file can be launched directly from the GUI. (Requires relaunching the tracker after saving new settings to load them)
  • Fixed a couple minor bugs such as save without entering an interruption type, not properly exiting app when clicking X etc.
Last edited by AlleyArtwork on 04 May 2019, 11:44, edited 10 times in total.
burque505
Posts: 1747
Joined: 22 Jan 2017, 19:37

Re: Simple Productivity/Interruption Tracker

14 Sep 2018, 14:25

@AlleyArt, that is very nice.
Regards,
burque505
User avatar
AlleyArtwork
Posts: 44
Joined: 09 Jun 2015, 21:08

Re: Simple Productivity/Interruption Tracker

16 Sep 2018, 16:17

Thanks guys, I hope you enjoy it or find the idea useful or can also put it to use as is.
If you can improve on it, or find a better way to do it please feel free to share.
I learned today, in the Discord chat, that i'm pretty much still quite the noob; and when helping someone, my 50 lines of code and multiple loops to accomplish something, was turned into a much cleaner 30 lines of code. Always learning and being humbled by people better than myself haha.
User avatar
AlleyArtwork
Posts: 44
Joined: 09 Jun 2015, 21:08

Re: Simple Productivity/Interruption Tracker

04 May 2019, 11:11

Updates:
  • I removed the radio button menu and replaced with a dropdown. This means you can have a much larger variety of things to track and not take up additional space.
  • Added utilization of INI file to save settings.
    • This way if others that don't use AHK but want to use the tracker, you can compile it and they can still customize the settings, or simply customize without editing the script directly.
    • INI settings store Interruption type list, time increments, and database file location
    • INI file can be launched directly from the GUI. (Requires relaunching the tracker after saving new settings to load them)
  • Fixed a couple minor bugs such as save without entering an interruption type, not properly exiting app when clicking X etc.

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: gwarble and 45 guests