I’m exploring ways to implement a custom widget or alternative solution in Grist that tracks modifications in certain columns. Specifically, my goal is to have a mechanism where, when any of a set of columns is modified, a dedicated “UpdateTracker” column is automatically updated with the name of the column that changed.
For example, consider a table with these columns:
Name
UserName
Date
Email
Phone
Currently, the only solution I’ve found is to create an associated tracking column for each of these fields, so that each time one is updated, its corresponding tracker is updated with the column name (e.g., “Name” when the Name column is modified). However, this approach quickly multiplies the number of columns and clutters the table schema.
My question is:
Is it possible to create a custom widget—or use another mechanism (maybe leveraging Grist’s internal trigger system such as _grist_Triggers)—that can monitor these changes and update a single tracking column (or otherwise log the change) without needing to create separate tracking columns for each field?
I would appreciate any insights, sample code, or references to documentation that could help implement a more elegant solution.
AFAIK you could just create a dependency on the _grist_Tables_column meta table. For example, this formula: _grist_Tables_column.lookupRecords(tableId="Test") gets updated as it should when you create a column on the ‘Test’ table.
For now I use the following formula which is triggered upon modification of the Last Modified automatic column. It joins multiple columns content in one single log.
import datetime
log=" ".join(f'[{w}]' for w in [$A, $B, $C])
ticket=Change_Identification.lookupOne(User=user.Name).Change_Identifier
current_time = NOW().strftime("%Y-%m-%d %H:%M:%S")
new_entry = f"{ticket}: ({user.Name}) {current_time} - {log}"
return (value + "\n" + new_entry) if value else new_entry
You’ll see I use a Change_Identification table to justify changes through a change ticket. My dream would be to make it mandatory before allowing any change with an auto-delete of the ticket identifier upon user logout…
However, for change tracking I think a better alternative would be to use the grist internal history but this is not possible for now.
I am sharing here a revised version for my needs, which only logs the changes from the same user if they are more than 60 min apart. It avoids cluttering the log with a user actively editing a record:
import datetime
current_time = datetime.datetime.now()
current_time_str = current_time.strftime("%Y-%m-%d %H:%M:%S")
new_entry = f"{user.Email} - {current_time_str}"
# Try to extract the last line from the existing field
last_line = value.strip().split("\n")[-1]
try:
last_name, last_time_str = last_line.rsplit(" - ", 1)
last_time = datetime.datetime.strptime(last_time_str, "%Y-%m-%d %H:%M:%S")
time_diff = (current_time - last_time).total_seconds() / 60 # in minutes
# If same user and less than 60 minutes: do not add anything
if last_name == user.Email and time_diff < 60:
return value # return the existing value unchanged
except Exception:
pass # If parsing fails, ignore and continue normally
# If the cell is empty, simply add the first entry
if not value:
return new_entry
# If everything is fine: append the new entry
return value + "\n" + new_entry
Disclaimer: the code is AI-generated and shared after some testing that showed it works as intended!