Skip to content

feat(connectors): per-actor two-way reaction sync (MS Teams, Google Chat) - #201

Merged
KrisBraun merged 2 commits into
mainfrom
feat/connector-reactions
Jun 14, 2026
Merged

feat(connectors): per-actor two-way reaction sync (MS Teams, Google Chat)#201
KrisBraun merged 2 commits into
mainfrom
feat/connector-reactions

Conversation

@KrisBraun

Copy link
Copy Markdown
Contributor

Summary

Outbound emoji-reaction write-back, migrated to the per-actoronNoteReactionChanged
hook so each reaction is attributed to the user who made it (the runtime dispatches the
callback on the reacting user's own connector instance via twist_instance_for_actor).

  • MS Teams (de1a09c): onNoteReactionChanged for DMs + channel messages/replies via
    Graph set/unset reaction. (Originally PR feat(ms-teams): two-way emoji reaction sync #200.)
  • Google Chat (82385bc): onNoteReactionChanged (create/delete reaction); reactions
    removed from onNoteUpdated, which now only syncs content edits. Unicode only — custom
    workspace emoji stay deferred, symmetric with sync-in, pending the custom-emoji image cache.

Inbound reaction sync already worked for both. No new OAuth scopes. No twister/SDK changes,
so no changeset (connector-only).

Supersedes #200, which GitHub auto-closed when its head branch feat/ms-teams-reactions
was renamed to feat/connector-reactions. Same MS Teams commit, now bundled with Google Chat.

The private connectors (LinkedIn, Instagram, WhatsApp) get the same migration in a separate
plotday/core PR.

Test plan

  • tsc --noEmit + pnpm build clean for google-chat and ms-teams
  • plot lint clean (google-chat)
  • Manual multi-account E2E: two users react in Plot; each reaction lands under the right account; removal clears only that user's reaction

KrisBraunand others added 2 commits June 14, 2026 14:35
Implement outbound reaction write-back (onNoteReactionChanged) for the
Microsoft Teams connector. Reactions a user adds or removes in Plot are
now pushed to Teams via Graph setReaction/unsetReaction, attributed to
the reacting user (the runtime dispatches the callback on that user's own
connector instance via twist_instance_for_actor, so getApi resolves to
their token).
- Channel messages and replies: replies are addressed through the
parent's replies/{id} collection, so a new GraphApi.channelReactionPath
helper switches setChannelReaction/unsetChannelReaction to the
reply-scoped endpoint when the note is a reply (note.key differs from
meta.messageId). Parents keep the top-level messages/{id} endpoint.
- DMs (chats): setChatReaction/unsetChatReaction on chats/{chatId}.
- Emoji is passed through as Unicode (Graph accepts it directly);
reactionCapabilities stays open-unicode with no custom emoji.
Inbound reaction sync was already wired via the message transforms. No
new OAuth scopes are required: ChannelMessage.Send (channels) and
Chat.ReadWrite / ChatMessage.Send (chats) are already granted.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…anged
Migrate outbound reactions off the connected-user onNoteUpdated reconcile to
the per-actor onNoteReactionChanged hook (Slack/MS-Teams pattern), so each
emoji is attributed to the user who reacted. onNoteUpdated keeps content-edit
sync only. Unicode only; custom workspace emoji remain deferred (symmetric
with sync-in), pending the custom-emoji image cache.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@KrisBraun
KrisBraun merged commit c39b767 into mainJun 14, 2026
1 check passed
@KrisBraun
KrisBraun deleted the feat/connector-reactions branch June 14, 2026 20:16
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@KrisBraun
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
feat(connectors): per-actor two-way reaction sync (MS Teams, Google Chat) by KrisBraun · Pull Request #201 · plotday/plot · GitHub
Skip to content

feat(connectors): per-actor two-way reaction sync (MS Teams, Google Chat) - #201

Merged
KrisBraun merged 2 commits into
mainfrom
feat/connector-reactions
Jun 14, 2026
Merged

feat(connectors): per-actor two-way reaction sync (MS Teams, Google Chat)#201
KrisBraun merged 2 commits into
mainfrom
feat/connector-reactions

Conversation

@KrisBraun

Copy link
Copy Markdown
Contributor

Summary

Outbound emoji-reaction write-back, migrated to the per-actoronNoteReactionChanged
hook so each reaction is attributed to the user who made it (the runtime dispatches the
callback on the reacting user's own connector instance via twist_instance_for_actor).

  • MS Teams (de1a09c): onNoteReactionChanged for DMs + channel messages/replies via
    Graph set/unset reaction. (Originally PR feat(ms-teams): two-way emoji reaction sync #200.)
  • Google Chat (82385bc): onNoteReactionChanged (create/delete reaction); reactions
    removed from onNoteUpdated, which now only syncs content edits. Unicode only — custom
    workspace emoji stay deferred, symmetric with sync-in, pending the custom-emoji image cache.

Inbound reaction sync already worked for both. No new OAuth scopes. No twister/SDK changes,
so no changeset (connector-only).

Supersedes #200, which GitHub auto-closed when its head branch feat/ms-teams-reactions
was renamed to feat/connector-reactions. Same MS Teams commit, now bundled with Google Chat.

The private connectors (LinkedIn, Instagram, WhatsApp) get the same migration in a separate
plotday/core PR.

Test plan

  • tsc --noEmit + pnpm build clean for google-chat and ms-teams
  • plot lint clean (google-chat)
  • Manual multi-account E2E: two users react in Plot; each reaction lands under the right account; removal clears only that user's reaction

KrisBraunand others added 2 commits June 14, 2026 14:35
Implement outbound reaction write-back (onNoteReactionChanged) for the
Microsoft Teams connector. Reactions a user adds or removes in Plot are
now pushed to Teams via Graph setReaction/unsetReaction, attributed to
the reacting user (the runtime dispatches the callback on that user's own
connector instance via twist_instance_for_actor, so getApi resolves to
their token).
- Channel messages and replies: replies are addressed through the
parent's replies/{id} collection, so a new GraphApi.channelReactionPath
helper switches setChannelReaction/unsetChannelReaction to the
reply-scoped endpoint when the note is a reply (note.key differs from
meta.messageId). Parents keep the top-level messages/{id} endpoint.
- DMs (chats): setChatReaction/unsetChatReaction on chats/{chatId}.
- Emoji is passed through as Unicode (Graph accepts it directly);
reactionCapabilities stays open-unicode with no custom emoji.
Inbound reaction sync was already wired via the message transforms. No
new OAuth scopes are required: ChannelMessage.Send (channels) and
Chat.ReadWrite / ChatMessage.Send (chats) are already granted.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…anged
Migrate outbound reactions off the connected-user onNoteUpdated reconcile to
the per-actor onNoteReactionChanged hook (Slack/MS-Teams pattern), so each
emoji is attributed to the user who reacted. onNoteUpdated keeps content-edit
sync only. Unicode only; custom workspace emoji remain deferred (symmetric
with sync-in), pending the custom-emoji image cache.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@KrisBraun
KrisBraun merged commit c39b767 into mainJun 14, 2026
1 check passed
@KrisBraun
KrisBraun deleted the feat/connector-reactions branch June 14, 2026 20:16
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@KrisBraun
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' feat(connectors): per-actor two-way reaction sync (MS Teams, Google Chat) by KrisBraun · Pull Request #201 · plotday/plot · GitHub
Skip to content

feat(connectors): per-actor two-way reaction sync (MS Teams, Google Chat) - #201

Merged
KrisBraun merged 2 commits into
mainfrom
feat/connector-reactions
Jun 14, 2026
Merged

feat(connectors): per-actor two-way reaction sync (MS Teams, Google Chat)#201
KrisBraun merged 2 commits into
mainfrom
feat/connector-reactions

Conversation

@KrisBraun

Copy link
Copy Markdown
Contributor

Summary

Outbound emoji-reaction write-back, migrated to the per-actoronNoteReactionChanged
hook so each reaction is attributed to the user who made it (the runtime dispatches the
callback on the reacting user's own connector instance via twist_instance_for_actor).

  • MS Teams (de1a09c): onNoteReactionChanged for DMs + channel messages/replies via
    Graph set/unset reaction. (Originally PR feat(ms-teams): two-way emoji reaction sync #200.)
  • Google Chat (82385bc): onNoteReactionChanged (create/delete reaction); reactions
    removed from onNoteUpdated, which now only syncs content edits. Unicode only — custom
    workspace emoji stay deferred, symmetric with sync-in, pending the custom-emoji image cache.

Inbound reaction sync already worked for both. No new OAuth scopes. No twister/SDK changes,
so no changeset (connector-only).

Supersedes #200, which GitHub auto-closed when its head branch feat/ms-teams-reactions
was renamed to feat/connector-reactions. Same MS Teams commit, now bundled with Google Chat.

The private connectors (LinkedIn, Instagram, WhatsApp) get the same migration in a separate
plotday/core PR.

Test plan

  • tsc --noEmit + pnpm build clean for google-chat and ms-teams
  • plot lint clean (google-chat)
  • Manual multi-account E2E: two users react in Plot; each reaction lands under the right account; removal clears only that user's reaction

KrisBraunand others added 2 commits June 14, 2026 14:35
Implement outbound reaction write-back (onNoteReactionChanged) for the
Microsoft Teams connector. Reactions a user adds or removes in Plot are
now pushed to Teams via Graph setReaction/unsetReaction, attributed to
the reacting user (the runtime dispatches the callback on that user's own
connector instance via twist_instance_for_actor, so getApi resolves to
their token).
- Channel messages and replies: replies are addressed through the
parent's replies/{id} collection, so a new GraphApi.channelReactionPath
helper switches setChannelReaction/unsetChannelReaction to the
reply-scoped endpoint when the note is a reply (note.key differs from
meta.messageId). Parents keep the top-level messages/{id} endpoint.
- DMs (chats): setChatReaction/unsetChatReaction on chats/{chatId}.
- Emoji is passed through as Unicode (Graph accepts it directly);
reactionCapabilities stays open-unicode with no custom emoji.
Inbound reaction sync was already wired via the message transforms. No
new OAuth scopes are required: ChannelMessage.Send (channels) and
Chat.ReadWrite / ChatMessage.Send (chats) are already granted.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…anged
Migrate outbound reactions off the connected-user onNoteUpdated reconcile to
the per-actor onNoteReactionChanged hook (Slack/MS-Teams pattern), so each
emoji is attributed to the user who reacted. onNoteUpdated keeps content-edit
sync only. Unicode only; custom workspace emoji remain deferred (symmetric
with sync-in), pending the custom-emoji image cache.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@KrisBraun
KrisBraun merged commit c39b767 into mainJun 14, 2026
1 check passed
@KrisBraun
KrisBraun deleted the feat/connector-reactions branch June 14, 2026 20:16
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@KrisBraun
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' feat(connectors): per-actor two-way reaction sync (MS Teams, Google Chat) by KrisBraun · Pull Request #201 · plotday/plot · GitHub
Skip to content

feat(connectors): per-actor two-way reaction sync (MS Teams, Google Chat) - #201

Merged
KrisBraun merged 2 commits into
mainfrom
feat/connector-reactions
Jun 14, 2026
Merged

feat(connectors): per-actor two-way reaction sync (MS Teams, Google Chat)#201
KrisBraun merged 2 commits into
mainfrom
feat/connector-reactions

Conversation

@KrisBraun

Copy link
Copy Markdown
Contributor

Summary

Outbound emoji-reaction write-back, migrated to the per-actoronNoteReactionChanged
hook so each reaction is attributed to the user who made it (the runtime dispatches the
callback on the reacting user's own connector instance via twist_instance_for_actor).

  • MS Teams (de1a09c): onNoteReactionChanged for DMs + channel messages/replies via
    Graph set/unset reaction. (Originally PR feat(ms-teams): two-way emoji reaction sync #200.)
  • Google Chat (82385bc): onNoteReactionChanged (create/delete reaction); reactions
    removed from onNoteUpdated, which now only syncs content edits. Unicode only — custom
    workspace emoji stay deferred, symmetric with sync-in, pending the custom-emoji image cache.

Inbound reaction sync already worked for both. No new OAuth scopes. No twister/SDK changes,
so no changeset (connector-only).

Supersedes #200, which GitHub auto-closed when its head branch feat/ms-teams-reactions
was renamed to feat/connector-reactions. Same MS Teams commit, now bundled with Google Chat.

The private connectors (LinkedIn, Instagram, WhatsApp) get the same migration in a separate
plotday/core PR.

Test plan

  • tsc --noEmit + pnpm build clean for google-chat and ms-teams
  • plot lint clean (google-chat)
  • Manual multi-account E2E: two users react in Plot; each reaction lands under the right account; removal clears only that user's reaction

KrisBraunand others added 2 commits June 14, 2026 14:35
Implement outbound reaction write-back (onNoteReactionChanged) for the
Microsoft Teams connector. Reactions a user adds or removes in Plot are
now pushed to Teams via Graph setReaction/unsetReaction, attributed to
the reacting user (the runtime dispatches the callback on that user's own
connector instance via twist_instance_for_actor, so getApi resolves to
their token).
- Channel messages and replies: replies are addressed through the
parent's replies/{id} collection, so a new GraphApi.channelReactionPath
helper switches setChannelReaction/unsetChannelReaction to the
reply-scoped endpoint when the note is a reply (note.key differs from
meta.messageId). Parents keep the top-level messages/{id} endpoint.
- DMs (chats): setChatReaction/unsetChatReaction on chats/{chatId}.
- Emoji is passed through as Unicode (Graph accepts it directly);
reactionCapabilities stays open-unicode with no custom emoji.
Inbound reaction sync was already wired via the message transforms. No
new OAuth scopes are required: ChannelMessage.Send (channels) and
Chat.ReadWrite / ChatMessage.Send (chats) are already granted.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…anged
Migrate outbound reactions off the connected-user onNoteUpdated reconcile to
the per-actor onNoteReactionChanged hook (Slack/MS-Teams pattern), so each
emoji is attributed to the user who reacted. onNoteUpdated keeps content-edit
sync only. Unicode only; custom workspace emoji remain deferred (symmetric
with sync-in), pending the custom-emoji image cache.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@KrisBraun
KrisBraun merged commit c39b767 into mainJun 14, 2026
1 check passed
@KrisBraun
KrisBraun deleted the feat/connector-reactions branch June 14, 2026 20:16
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@KrisBraun
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' feat(connectors): per-actor two-way reaction sync (MS Teams, Google Chat) by KrisBraun · Pull Request #201 · plotday/plot · GitHub
Skip to content

feat(connectors): per-actor two-way reaction sync (MS Teams, Google Chat) - #201

Merged
KrisBraun merged 2 commits into
mainfrom
feat/connector-reactions
Jun 14, 2026
Merged

feat(connectors): per-actor two-way reaction sync (MS Teams, Google Chat)#201
KrisBraun merged 2 commits into
mainfrom
feat/connector-reactions

Conversation

@KrisBraun

Copy link
Copy Markdown
Contributor

Summary

Outbound emoji-reaction write-back, migrated to the per-actoronNoteReactionChanged
hook so each reaction is attributed to the user who made it (the runtime dispatches the
callback on the reacting user's own connector instance via twist_instance_for_actor).

  • MS Teams (de1a09c): onNoteReactionChanged for DMs + channel messages/replies via
    Graph set/unset reaction. (Originally PR feat(ms-teams): two-way emoji reaction sync #200.)
  • Google Chat (82385bc): onNoteReactionChanged (create/delete reaction); reactions
    removed from onNoteUpdated, which now only syncs content edits. Unicode only — custom
    workspace emoji stay deferred, symmetric with sync-in, pending the custom-emoji image cache.

Inbound reaction sync already worked for both. No new OAuth scopes. No twister/SDK changes,
so no changeset (connector-only).

Supersedes #200, which GitHub auto-closed when its head branch feat/ms-teams-reactions
was renamed to feat/connector-reactions. Same MS Teams commit, now bundled with Google Chat.

The private connectors (LinkedIn, Instagram, WhatsApp) get the same migration in a separate
plotday/core PR.

Test plan

  • tsc --noEmit + pnpm build clean for google-chat and ms-teams
  • plot lint clean (google-chat)
  • Manual multi-account E2E: two users react in Plot; each reaction lands under the right account; removal clears only that user's reaction

KrisBraunand others added 2 commits June 14, 2026 14:35
Implement outbound reaction write-back (onNoteReactionChanged) for the
Microsoft Teams connector. Reactions a user adds or removes in Plot are
now pushed to Teams via Graph setReaction/unsetReaction, attributed to
the reacting user (the runtime dispatches the callback on that user's own
connector instance via twist_instance_for_actor, so getApi resolves to
their token).
- Channel messages and replies: replies are addressed through the
parent's replies/{id} collection, so a new GraphApi.channelReactionPath
helper switches setChannelReaction/unsetChannelReaction to the
reply-scoped endpoint when the note is a reply (note.key differs from
meta.messageId). Parents keep the top-level messages/{id} endpoint.
- DMs (chats): setChatReaction/unsetChatReaction on chats/{chatId}.
- Emoji is passed through as Unicode (Graph accepts it directly);
reactionCapabilities stays open-unicode with no custom emoji.
Inbound reaction sync was already wired via the message transforms. No
new OAuth scopes are required: ChannelMessage.Send (channels) and
Chat.ReadWrite / ChatMessage.Send (chats) are already granted.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…anged
Migrate outbound reactions off the connected-user onNoteUpdated reconcile to
the per-actor onNoteReactionChanged hook (Slack/MS-Teams pattern), so each
emoji is attributed to the user who reacted. onNoteUpdated keeps content-edit
sync only. Unicode only; custom workspace emoji remain deferred (symmetric
with sync-in), pending the custom-emoji image cache.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@KrisBraun
KrisBraun merged commit c39b767 into mainJun 14, 2026
1 check passed
@KrisBraun
KrisBraun deleted the feat/connector-reactions branch June 14, 2026 20:16
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@KrisBraun
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' feat(connectors): per-actor two-way reaction sync (MS Teams, Google Chat) by KrisBraun · Pull Request #201 · plotday/plot · GitHub
Skip to content

feat(connectors): per-actor two-way reaction sync (MS Teams, Google Chat) - #201

Merged
KrisBraun merged 2 commits into
mainfrom
feat/connector-reactions
Jun 14, 2026
Merged

feat(connectors): per-actor two-way reaction sync (MS Teams, Google Chat)#201
KrisBraun merged 2 commits into
mainfrom
feat/connector-reactions

Conversation

@KrisBraun

Copy link
Copy Markdown
Contributor

Summary

Outbound emoji-reaction write-back, migrated to the per-actoronNoteReactionChanged
hook so each reaction is attributed to the user who made it (the runtime dispatches the
callback on the reacting user's own connector instance via twist_instance_for_actor).

  • MS Teams (de1a09c): onNoteReactionChanged for DMs + channel messages/replies via
    Graph set/unset reaction. (Originally PR feat(ms-teams): two-way emoji reaction sync #200.)
  • Google Chat (82385bc): onNoteReactionChanged (create/delete reaction); reactions
    removed from onNoteUpdated, which now only syncs content edits. Unicode only — custom
    workspace emoji stay deferred, symmetric with sync-in, pending the custom-emoji image cache.

Inbound reaction sync already worked for both. No new OAuth scopes. No twister/SDK changes,
so no changeset (connector-only).

Supersedes #200, which GitHub auto-closed when its head branch feat/ms-teams-reactions
was renamed to feat/connector-reactions. Same MS Teams commit, now bundled with Google Chat.

The private connectors (LinkedIn, Instagram, WhatsApp) get the same migration in a separate
plotday/core PR.

Test plan

  • tsc --noEmit + pnpm build clean for google-chat and ms-teams
  • plot lint clean (google-chat)
  • Manual multi-account E2E: two users react in Plot; each reaction lands under the right account; removal clears only that user's reaction

KrisBraunand others added 2 commits June 14, 2026 14:35
Implement outbound reaction write-back (onNoteReactionChanged) for the
Microsoft Teams connector. Reactions a user adds or removes in Plot are
now pushed to Teams via Graph setReaction/unsetReaction, attributed to
the reacting user (the runtime dispatches the callback on that user's own
connector instance via twist_instance_for_actor, so getApi resolves to
their token).
- Channel messages and replies: replies are addressed through the
parent's replies/{id} collection, so a new GraphApi.channelReactionPath
helper switches setChannelReaction/unsetChannelReaction to the
reply-scoped endpoint when the note is a reply (note.key differs from
meta.messageId). Parents keep the top-level messages/{id} endpoint.
- DMs (chats): setChatReaction/unsetChatReaction on chats/{chatId}.
- Emoji is passed through as Unicode (Graph accepts it directly);
reactionCapabilities stays open-unicode with no custom emoji.
Inbound reaction sync was already wired via the message transforms. No
new OAuth scopes are required: ChannelMessage.Send (channels) and
Chat.ReadWrite / ChatMessage.Send (chats) are already granted.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…anged
Migrate outbound reactions off the connected-user onNoteUpdated reconcile to
the per-actor onNoteReactionChanged hook (Slack/MS-Teams pattern), so each
emoji is attributed to the user who reacted. onNoteUpdated keeps content-edit
sync only. Unicode only; custom workspace emoji remain deferred (symmetric
with sync-in), pending the custom-emoji image cache.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@KrisBraun
KrisBraun merged commit c39b767 into mainJun 14, 2026
1 check passed
@KrisBraun
KrisBraun deleted the feat/connector-reactions branch June 14, 2026 20:16
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@KrisBraun
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); })(); feat(connectors): per-actor two-way reaction sync (MS Teams, Google Chat) by KrisBraun · Pull Request #201 · plotday/plot · GitHub
Skip to content

feat(connectors): per-actor two-way reaction sync (MS Teams, Google Chat) - #201

Merged
KrisBraun merged 2 commits into
mainfrom
feat/connector-reactions
Jun 14, 2026
Merged

feat(connectors): per-actor two-way reaction sync (MS Teams, Google Chat)#201
KrisBraun merged 2 commits into
mainfrom
feat/connector-reactions

Conversation

@KrisBraun

Copy link
Copy Markdown
Contributor

Summary

Outbound emoji-reaction write-back, migrated to the per-actoronNoteReactionChanged
hook so each reaction is attributed to the user who made it (the runtime dispatches the
callback on the reacting user's own connector instance via twist_instance_for_actor).

  • MS Teams (de1a09c): onNoteReactionChanged for DMs + channel messages/replies via
    Graph set/unset reaction. (Originally PR feat(ms-teams): two-way emoji reaction sync #200.)
  • Google Chat (82385bc): onNoteReactionChanged (create/delete reaction); reactions
    removed from onNoteUpdated, which now only syncs content edits. Unicode only — custom
    workspace emoji stay deferred, symmetric with sync-in, pending the custom-emoji image cache.

Inbound reaction sync already worked for both. No new OAuth scopes. No twister/SDK changes,
so no changeset (connector-only).

Supersedes #200, which GitHub auto-closed when its head branch feat/ms-teams-reactions
was renamed to feat/connector-reactions. Same MS Teams commit, now bundled with Google Chat.

The private connectors (LinkedIn, Instagram, WhatsApp) get the same migration in a separate
plotday/core PR.

Test plan

  • tsc --noEmit + pnpm build clean for google-chat and ms-teams
  • plot lint clean (google-chat)
  • Manual multi-account E2E: two users react in Plot; each reaction lands under the right account; removal clears only that user's reaction

KrisBraunand others added 2 commits June 14, 2026 14:35
Implement outbound reaction write-back (onNoteReactionChanged) for the
Microsoft Teams connector. Reactions a user adds or removes in Plot are
now pushed to Teams via Graph setReaction/unsetReaction, attributed to
the reacting user (the runtime dispatches the callback on that user's own
connector instance via twist_instance_for_actor, so getApi resolves to
their token).
- Channel messages and replies: replies are addressed through the
parent's replies/{id} collection, so a new GraphApi.channelReactionPath
helper switches setChannelReaction/unsetChannelReaction to the
reply-scoped endpoint when the note is a reply (note.key differs from
meta.messageId). Parents keep the top-level messages/{id} endpoint.
- DMs (chats): setChatReaction/unsetChatReaction on chats/{chatId}.
- Emoji is passed through as Unicode (Graph accepts it directly);
reactionCapabilities stays open-unicode with no custom emoji.
Inbound reaction sync was already wired via the message transforms. No
new OAuth scopes are required: ChannelMessage.Send (channels) and
Chat.ReadWrite / ChatMessage.Send (chats) are already granted.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…anged
Migrate outbound reactions off the connected-user onNoteUpdated reconcile to
the per-actor onNoteReactionChanged hook (Slack/MS-Teams pattern), so each
emoji is attributed to the user who reacted. onNoteUpdated keeps content-edit
sync only. Unicode only; custom workspace emoji remain deferred (symmetric
with sync-in), pending the custom-emoji image cache.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@KrisBraun
KrisBraun merged commit c39b767 into mainJun 14, 2026
1 check passed
@KrisBraun
KrisBraun deleted the feat/connector-reactions branch June 14, 2026 20:16
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@KrisBraun