← Commit history
README.md+9−13
@@ -9,18 +9,14 @@ wiki notification email ──poll──> per-item state ──render──> ONE         └──sweep──> trash / archive / label ``` -The board is a single card holding a **table** - a header row and one row per-issue with consistent columns:--```-STATUS | ITEM | TITLE | BY | OPENED | LAST | LINK-```--**status** (OPEN green / CLOSED gray), **page + issue #**, title, **actor**,-**origination date**, last activity, and a **View link at the end of the-row**. New activity bubbles to the top. (Chat cards have no native table-widget, so the table is rendered as consistent pipe-separated columns; set-`"style": "blocks"` for a chunkier per-item layout instead.) Open items stay on the board until resolved; when an item+The board is a single card holding a **table**: a colored STATUS rail column+(OPEN green / CLOSED gray) beside a content column, one divider-ruled row per+issue. Every row has the same shape - **page + issue #**, title, then+**actor**, **origination date**, last activity, and a **View link at the end+of the row**. New activity bubbles to the top. (Chat cards have no native+table widget and free-flowing pipe columns wrap unreadably at card width, so+the table is two aligned columns with controlled line breaks; set+`"style": "blocks"` for the chunkier per-item layout with View buttons.) Open items stay on the board until resolved; when an item is closed it shows CLOSED - so you get the satisfaction of seeing it done - then drops off at **6am the next day** to keep the board fresh. @@ -107,7 +103,7 @@ inbox. A failed board post never sweeps the email; it retries next pass. | `timezone` | container local | IANA zone for dates + the purge | | `maxRows` | `40` | card row cap | | `boardTitle` | `Wiki Notifications` | card header |-| `style` | `table` | `table` (pipe-column table) or `blocks` (per-item blocks with View buttons) |+| `style` | `table` | `table` (status rail + content column, divider-ruled rows) or `blocks` (per-item blocks with View buttons) |  ## Commands 
SKILL.md+4−2
@@ -41,8 +41,10 @@ wiki-notify-gchat install-cron    # keep the board live every 2 min - `timezone`: IANA zone (e.g. `America/New_York`) so the 6am closed-item   purge lands in the user's morning; container default is often UTC. - `purgeHour`, `maxRows`, `pollSeconds`, `boardTitle` as needed.-- `style`: `table` (default - pipe-column table with header row) or `blocks`-  (per-item blocks with View buttons). Chat cards have no native table widget.+- `style`: `table` (default - colored status rail + content column, one+  divider-ruled row per item) or `blocks` (per-item blocks with View buttons).+  Chat cards have no native table widget; avoid single-line pipe columns,+  they wrap unreadably at card width.  ## How the board updates (why you may see a delete) 
bin/__pycache__/wiki-notify-gchatcpython-312.pyc
⋯ 1 unchanged line ⋯
bin/wiki-notify-gchat+23−13
@@ -296,25 +296,35 @@ def render_card(items, cfg):   def render_table_widgets(shown, tz):-    """One text block: a pipe-separated table, header row + one line per item.-    Chat cards have no native table widget (columns caps at 2), so consistent-    pipe columns are the closest faithful table rendering."""+    """A table built from columns widgets: a narrow STATUS rail + a content+    column, one divider-ruled row per item. Each content cell is exactly two+    controlled lines (item + title, then meta ending in the View link) so+    nothing free-wraps into unreadable pipe soup. Chat cards have no native+    table widget; this is the closest readable equivalent."""     import html as html_mod-    cells = ["STATUS", "ITEM", "TITLE", "BY", "OPENED", "LAST", "LINK"]-    lines = ["<b>" + " | ".join(cells) + "</b>"]-    for it in shown:+    widgets = []+    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>')         item = it["page"] + (f" #{it['num']}" if it["num"] else "")-        title = it["title"][:48] + ("…" if len(it["title"]) > 48 else "")+        title = it["title"][:70] + ("…" if len(it["title"]) > 70 else "")         title = html_mod.escape(title, quote=False)-        by = it["actor"] or "-"-        opened = fmt_date(it["openedAt"], tz)-        last = f"{EVENT_LABEL.get(it['lastEvent'], it['lastEvent'])} {fmt_datetime(it['lastAt'], tz)}"-        link = f'<a href="{it["url"]}">View</a>' if it["url"] else "-"-        lines.append(" | ".join([status, item, title, by, opened, last, link]))-    return [{"textParagraph": {"text": "<br>".join(lines)}}]+        meta = [f"by {it['actor']}" if it["actor"] else None,+                f"opened {fmt_date(it['openedAt'], tz)}",+                f"last: {EVENT_LABEL.get(it['lastEvent'], it['lastEvent'])} {fmt_datetime(it['lastAt'], tz)}",+                f'<a href="{it["url"]}">View</a>' if it["url"] else None]+        content = (f"<b>{item}</b>  {title}<br>"+                   f'<font color="#8a94a6">{" · ".join(m for m in meta if m)}</font>')+        widgets.append({"columns": {"columnItems": [+            {"horizontalSizeStyle": "FILL_MINIMUM_SPACE", "verticalAlignment": "TOP",+             "widgets": [{"textParagraph": {"text": status}}]},+            {"horizontalSizeStyle": "FILL_AVAILABLE_SPACE", "verticalAlignment": "TOP",+             "widgets": [{"textParagraph": {"text": content}}]},+        ]}})+    return widgets   def render_block_widgets(shown, tz):
docs/board.png
⋯ 1 unchanged line ⋯
docs/hero.png
⋯ 1 unchanged line ⋯
package.json+1−1
@@ -2,7 +2,7 @@   "slug": "wiki-notify-gchat",   "title": "Wiki Notify for Google Chat",   "type": "app",-  "version": "1.1.0",+  "version": "1.1.1",   "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.1.0",+  "version": "1.1.1",   "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",