https://bulldo.gs
const sh = SpreadsheetApp.getActive().getActiveSheet();
sh.getDataRange().getValues().forEach((r, i) => {
if (r[2] > 1000) sh.getRange(i+1, 1, 1, r.length).setBackground("#fde68a");
});
One pass, every matching row flagged. #AppsScript
https://bulldo.gs/pack/auto-email-weekly-digest/?utm_source=bluesky&utm_medium=social&utm_campaign=operator_month_digest_v1
https://bulldo.gs/pack/auto-email-weekly-digest/?utm_source=bluesky&utm_medium=social&utm_campaign=operator_month_digest_v1
ScriptApp.newTrigger("daily").timeBased().atHour(9).everyDays(1).create();
So never derive "yesterday" from when the trigger ran. Filter on the timestamp in the row.
#AppsScript
ScriptApp.newTrigger("daily").timeBased().atHour(9).everyDays(1).create();
So never derive "yesterday" from when the trigger ran. Filter on the timestamp in the row.
#AppsScript
Google Apps Script, weekly trigger:
const ev = CalendarApp.getEvents(mon, sun);
if (!ev.length) return;
sh.getRange(2,1,ev.length,2).setValues(ev.map(e=>[e.getStartTime(),e.getTitle()]));
A quiet week is 0 rows, and setValues throws. #AppsScript
Google Apps Script, weekly trigger:
const ev = CalendarApp.getEvents(mon, sun);
if (!ev.length) return;
sh.getRange(2,1,ev.length,2).setValues(ev.map(e=>[e.getStartTime(),e.getTitle()]));
A quiet week is 0 rows, and setValues throws. #AppsScript
Google Apps Script, on a weekly trigger:
GmailApp.sendEmail(TO, subj, body, {attachments:[DriveApp.getFileById(ID).getAs(MimeType.PDF)]});
The file updates in place; the mail always sends the current version.
#Gmail
Google Apps Script, on a weekly trigger:
GmailApp.sendEmail(TO, subj, body, {attachments:[DriveApp.getFileById(ID).getAs(MimeType.PDF)]});
The file updates in place; the mail always sends the current version.
#Gmail
sheet.appendRow(row) is atomic — the one write that cannot lose that race.
If you must setValues(), take a LockService lock first. #AppsScript
sheet.appendRow(row) is atomic — the one write that cannot lose that race.
If you must setValues(), take a LockService lock first. #AppsScript
const ss = SpreadsheetApp.getActive();
ss.getSheetByName('Tracker').copyTo(ss).setName('Tracker ' + Utilities.formatDate(new Date(), ss.getSpreadsheetTimeZone(), 'yyyy-MM-dd'));
Weekly time trigger does the rest. #GoogleSheets
const ss = SpreadsheetApp.getActive();
ss.getSheetByName('Tracker').copyTo(ss).setName('Tracker ' + Utilities.formatDate(new Date(), ss.getSpreadsheetTimeZone(), 'yyyy-MM-dd'));
Weekly time trigger does the rest. #GoogleSheets
Google Apps Script, once:
const sh=SpreadsheetApp.getActiveSheet(), extra=sh.getMaxRows()-sh.getLastRow();
if(extra>0) sh.deleteRows(sh.getLastRow()+1, extra);
Gone in a blink. #GoogleSheets
Google Apps Script, once:
const sh=SpreadsheetApp.getActiveSheet(), extra=sh.getMaxRows()-sh.getLastRow();
if(extra>0) sh.deleteRows(sh.getLastRow()+1, extra);
Gone in a blink. #GoogleSheets
Need an edit-trigger that sends mail or hits an API? Make it an INSTALLABLE onEdit (Triggers → Add) — same function, full scopes. #AppsScript
Need an edit-trigger that sends mail or hits an API? Make it an INSTALLABLE onEdit (Triggers → Add) — same function, full scopes. #AppsScript
const rows = sheet.getDataRange().getValues().filter(r => r[0] >= weekAgo);
GmailApp.sendEmail(me, "new this week", rows.map(r => r.join(" | ")).join("\n"));
plus one Friday clock trigger. #GoogleSheets
const rows = sheet.getDataRange().getValues().filter(r => r[0] >= weekAgo);
GmailApp.sendEmail(me, "new this week", rows.map(r => r.join(" | ")).join("\n"));
plus one Friday clock trigger. #GoogleSheets
Google Apps Script, once:
GmailApp.search("label:invoices filename:pdf newer_than:7d")
.flatMap(t=>t.getMessages())
.forEach(m=>m.getAttachments()
.forEach(a=>folder.createFile(a)));
Trigger it, done. #AppsScript
Google Apps Script, once:
GmailApp.search("label:invoices filename:pdf newer_than:7d")
.flatMap(t=>t.getMessages())
.forEach(m=>m.getAttachments()
.forEach(a=>folder.createFile(a)));
Trigger it, done. #AppsScript
const sh = SpreadsheetApp.getActive().getActiveSheet();
sh.getDataRange().getValues().forEach((r, i) => {
if (r[2] > 1000) sh.getRange(i+1, 1, 1, r.length).setBackground("#fde68a");
});
One pass, every matching row flagged. #AppsScript
const sh = SpreadsheetApp.getActive().getActiveSheet();
sh.getDataRange().getValues().forEach((r, i) => {
if (r[2] > 1000) sh.getRange(i+1, 1, 1, r.length).setBackground("#fde68a");
});
One pass, every matching row flagged. #AppsScript
const files = DriveApp.getFolderById(ID).getFiles();
while (files.hasNext()) {
const f = files.next();
f.setName(f.getName().replace(/ /g, "_"));
}
Whole folder normalized in one run. #AppsScript
const files = DriveApp.getFolderById(ID).getFiles();
while (files.hasNext()) {
const f = files.next();
f.setName(f.getName().replace(/ /g, "_"));
}
Whole folder normalized in one run. #AppsScript
onEdit only fires on human typing — not API/form/import writes. Use an installable onChange trigger:
function onChange(e) {
if (e.changeType !== "INSERT_ROW") return;
UrlFetchApp.fetch(HOOK, {payload: "new row"});
}
Wire it under Triggers.
onEdit only fires on human typing — not API/form/import writes. Use an installable onChange trigger:
function onChange(e) {
if (e.changeType !== "INSERT_ROW") return;
UrlFetchApp.fetch(HOOK, {payload: "new row"});
}
Wire it under Triggers.
clearContent() actually removes it. Or filter blanks from getValues() before trusting the length.
#AppsScript
clearContent() actually removes it. Or filter blanks from getValues() before trusting the length.
#AppsScript
onEdit(e): if the edited cell is the Status column and e.value == 'Done', appendRow() it to Archive, then deleteRow() from the source.
~8 lines. Pinning down the spec sentence was harder than the code. #AppsScript #GoogleSheets
onEdit(e): if the edited cell is the Status column and e.value == 'Done', appendRow() it to Archive, then deleteRow() from the source.
~8 lines. Pinning down the spec sentence was harder than the code. #AppsScript #GoogleSheets
function archiveOld() {
GmailApp.search("older_than:1y -is:starred")
.forEach(t => t.moveToArchive());
}
One sentence in, four lines out. Put it on a daily trigger and the inbox count stops climbing. #AppsScript #Gmail
function archiveOld() {
GmailApp.search("older_than:1y -is:starred")
.forEach(t => t.moveToArchive());
}
One sentence in, four lines out. Put it on a daily trigger and the inbox count stops climbing. #AppsScript #Gmail