app
Wiki Notify for Google Chat
Public Made by Adomby adom
Turn wiki.adom.inc notification emails into a live Google Chat board. One card, one row per issue - newest first, OPEN/CLOSED status, origination date, actor, and a View link - continuously updated in your own Chat space via your own webhook. Emails are swept out of your inbox (trash, archive, or label). Closed items linger until 6am the next day, then drop off. Delegates all auth to adom-google; the only secret is your webhook URL, kept in your private config.
← Commit history
Publish 1.7.0
4 files changed
+52−14
bin/__pycache__/wiki-notify-gchatcpython-312.pyc⋯ 1 unchanged line ⋯
bin/wiki-notify-gchat+50−12@@ -49,7 +49,26 @@ DEFAULT_CONFIG = { "fullName": "", } -OPEN_COLOR, CLOSED_COLOR = "#22c55e", "#94a3b8"+OPEN_COLOR, CLOSED_COLOR = "#22c55e", "#64abff" # CLOSED = Adom blue (text-safe --blue)+# 3-state triage (needs YOU to act vs WAITING on another member vs CLOSED).+# Most board items live on pages someone else owns - only their owner can close+# them - so a flat "open" count reads as "nothing ever closes". Splitting it+# shows what is actually yours to move.+NEEDS_COLOR, WAITING_COLOR = "#8c6bf7", "#00b8b1" # Adom purple = your move, Adom teal = waiting+++def triage(it):+ """closed | needs_you | waiting. 'needs_you' = your page (you're the+ maintainer who closes it) OR someone @mentioned you (they want your call).+ Otherwise it's on another member's page and the ball is in their court."""+ if it.get("status") != "open":+ return "closed"+ if it.get("ownsPage") or it.get("lastEvent") == "mention":+ return "needs_you"+ return "waiting"+++TRIAGE_RANK = {"needs_you": 0, "waiting": 1, "closed": 2} def emit(line):@@ -502,9 +521,11 @@ EVENT_LABEL = {"opened": "opened", "comment": "new comment", "mention": "mention def render_card(items, cfg): tz = tzinfo_of(cfg)- rows = sorted(items.values(), key=lambda it: -it["lastAt"])- n_open = sum(1 for it in rows if it["status"] == "open")- n_closed = len(rows) - n_open+ # NEEDS YOU floats to the top, then WAITING, then CLOSED; newest-first within each.+ rows = sorted(items.values(), key=lambda it: (TRIAGE_RANK[triage(it)], -it["lastAt"]))+ n_needs = sum(1 for it in rows if triage(it) == "needs_you")+ n_wait = sum(1 for it in rows if triage(it) == "waiting")+ n_closed = sum(1 for it in rows if triage(it) == "closed") max_rows = int(cfg.get("maxRows", 40)) shown, overflow = rows[:max_rows], max(0, len(rows) - max_rows) style = cfg.get("style", "table")@@ -516,7 +537,9 @@ def render_card(items, cfg): widgets.append({"textParagraph": {"text": f"<i>+{overflow} older item(s) not shown</i>"}}) if not shown: widgets = [{"textParagraph": {"text": "No wiki notifications. Inbox clean."}}]- subtitle = f"{n_open} open · {n_closed} closed · updated {datetime.now(tz).strftime('%b %-d %H:%M')}"+ subtitle = (f'<font color="{NEEDS_COLOR}">{n_needs} need you</font> · '+ f'<font color="{WAITING_COLOR}">{n_wait} waiting</font> · {n_closed} closed'+ f' · updated {datetime.now(tz).strftime("%b %-d %H:%M")}') return {"cardsV2": [{"cardId": "wiki-notify-board", "card": { "header": {"title": cfg.get("boardTitle", "Wiki Notifications"), "subtitle": subtitle}, "sections": [{"widgets": widgets}],@@ -539,9 +562,15 @@ def render_table_widgets(shown, tz, me="You"): for i, it in enumerate(shown): if i: widgets.append({"divider": {}})- is_open = it["status"] == "open"- status = (f'<font color="{OPEN_COLOR}"><b>OPEN</b></font>' if is_open- else f'<font color="{CLOSED_COLOR}"><b>CLOSED</b></font>')+ t = triage(it)+ if t == "needs_you":+ status = f'<font color="{NEEDS_COLOR}"><b>NEEDS YOU</b></font>'+ elif t == "waiting":+ # name who the ball is on: the page owner (who can close it), else last actor+ on = it.get("pageAuthor") or it.get("actor") or "another member"+ status = f'<font color="{WAITING_COLOR}"><b>WAITING</b></font> · {html_mod.escape(str(on), quote=False)}'+ else:+ status = f'<font color="{CLOSED_COLOR}"><b>CLOSED</b></font>' item = it["page"] + (f" #{it['num']}" if it["num"] else "") title = it["title"][:110] + ("…" if len(it["title"]) > 110 else "") title = html_mod.escape(title, quote=False)@@ -606,9 +635,12 @@ def render_table_widgets(shown, tz, me="You"): def render_block_widgets(shown, tz): widgets = [] for it in shown:- is_open = it["status"] == "open"- status_html = (f'<font color="{OPEN_COLOR}"><b>OPEN</b></font>' if is_open- else f'<font color="{CLOSED_COLOR}"><b>CLOSED</b></font>')+ t = triage(it)+ status_html = {+ "needs_you": f'<font color="{NEEDS_COLOR}"><b>NEEDS YOU</b></font>',+ "waiting": f'<font color="{WAITING_COLOR}"><b>WAITING</b></font>',+ "closed": f'<font color="{CLOSED_COLOR}"><b>CLOSED</b></font>',+ }[t] num = f" #{it['num']}" if it["num"] else "" top = f"{it['page']}{num} · opened {fmt_date(it['openedAt'], tz)}" + ( f" · by {it['actor']}" if it["actor"] else "")@@ -626,8 +658,14 @@ def render_block_widgets(shown, tz): return widgets +# Bump when the RENDER changes (not the data) so the board re-pushes once with+# the new look; without this, items_hash is data-only and a render change never+# reaches the card. Kept out of the hash's per-minute churn (no timestamp here).+RENDER_VERSION = "triage-3state-v2-adomcolors"++ def items_hash(items):- key = json.dumps(items, sort_keys=True)+ key = RENDER_VERSION + "\n" + json.dumps(items, sort_keys=True) return hashlib.sha256(key.encode()).hexdigest()
package.json+1−1@@ -2,7 +2,7 @@ "slug": "wiki-notify-gchat", "title": "Wiki Notify for Google Chat", "type": "app",- "version": "1.6.9",+ "version": "1.7.0", "description": "Turn wiki.adom.inc notification emails into a live Google Chat board. One card, one row per issue - newest first, OPEN/CLOSED status, origination date, actor, and a View link - continuously updated in your own Chat space via your own webhook. Emails are swept out of your inbox (trash, archive, or label). Closed items linger until 6am the next day, then drop off. Delegates all auth to adom-google; the only secret is your webhook URL, kept in your private config.", "tags": [ "cli",
page.json+1−1@@ -2,7 +2,7 @@ "slug": "wiki-notify-gchat", "title": "Wiki Notify for Google Chat", "type": "app",- "version": "1.6.9",+ "version": "1.7.0", "description": "Turn wiki.adom.inc notification emails into a live Google Chat board. One card, one row per issue - newest first, OPEN/CLOSED status, origination date, actor, and a View link - continuously updated in your own Chat space via your own webhook. Emails are swept out of your inbox (trash, archive, or label). Closed items linger until 6am the next day, then drop off. Delegates all auth to adom-google; the only secret is your webhook URL, kept in your private config.", "tags": [ "cli",