Skip to content

Show a "via connected app" label on chat posts from a connected app #344

Description

@HMarzban

Parent

#328. Related: #230, #228

What to build

Heading chat on a public pad is public, and a connected app posts there as the document owner. Visitors read its summary as the owner's own words. History already labels an MCP version "Connected app", but chat has no label.

After this change, a post that carries metadata.via = 'connected_app' shows a muted "via connected app" in its message footer, beside "edited". It shows on desktop and phone, on group-start and compact rows.

Acceptance criteria

  • The maintainer's ruling is recorded on this issue before any code lands: show the label or not, and the exact visible words.
  • A message with metadata.via === 'connected_app' shows the label in the footer indicators, beside EditedBadge.
  • The label shows on desktop and on phone, on a group-start row and on a compact row.
  • A screen reader reads "Posted through a connected app". The visible text stays short.
  • A message without the key shows no label. An edited connected-app post shows both "via connected app" and "edited".
  • The label uses text-base-content/60 text-xs. Light and dark themes both meet the design-system contrast floor (4.5:1).
  • Chat code does not import History code. The words are copied, not shared.

Blocked by

Agent brief

Type: HITL — the maintainer, as chat owner, must rule whether connected-app posts show a visible label, and give the exact words. The answer goes in a comment on this issue. If the ruling is no, close this issue; the stored key from #336 stays.

Category: enhancement

Current behavior:

  • The footer indicators render on every row, group-start and compact. Desktop: apps/webapp/src/components/chatroom/components/ChatList/DesktopMessageBody.tsx:13-16. Phone: apps/webapp/src/components/chatroom/components/ChatList/MobileMessageBody.tsx:76-81.
  • The header meta row is absent on a compact row. An MCP post carries the owner's user_id, so a connected-app post right after the owner's own post is compact (samePrev in apps/webapp/src/components/chatroom/components/ChatList/ItemContent.tsx). That is why the label goes in the footer.
  • EditedBadge is the model for shape: it reads message from useMessageCardContext() and returns null when it has nothing to show (.../MessageFooter/components/MessageIndicators/components/EditedBadge.tsx:8-16). Its class text-opacity-50 is a Tailwind 3 class. The repo is on Tailwind 4 (root package.json), so do not copy that class.
  • ReplyCount already reads a metadata key in the footer with getMetadataProperty from @utils/metadata (.../MessageIndicators/components/ReplyCount.tsx:12).
  • MessageIndicators.tsx attaches each badge as a static property, for example MessageIndicators.EditedBadge = EditedBadge.
  • History shows mcp: 'Connected app' (apps/webapp/src/components/pages/history/components/HistorySidebarRowParts.tsx:91).

Desired behavior:

  1. New ConnectedAppBadge.tsx beside EditedBadge.tsx. It returns null unless getMetadataProperty<string>(message.metadata, 'via') === 'connected_app'.
  2. Visible text: the ruled words, "via connected app" by default. Add sr-only text "Posted through a connected app", and hide the short visible text from screen readers so it is read once.
  3. Use text-base-content/60 text-xs: the design-system tier for muted informational text. Use no colour or icon alone to carry the meaning. Leave EditedBadge as it is.
  4. Export it from MessageIndicators/components/index.ts. In MessageIndicators.tsx, attach it as MessageIndicators.ConnectedAppBadge.
  5. Render it next to EditedBadge in DesktopMessageBody.tsx and MobileMessageBody.tsx. Leave samePrev and the header meta row alone.

Where to start: EditedBadge, ReplyCount and MessageIndicators under apps/webapp/src/components/chatroom/components/MessageCard/components/MessageFooter/components/MessageIndicators/; DesktopMessageBody and MobileMessageBody in apps/webapp/src/components/chatroom/components/ChatList/. Line numbers are hints as of 2026-09-28; the agent searches by symbol.

Rules that apply:

  • apps/webapp/src/components/chatroom/CLAUDE.md §Message Grouping Projection (never persist grouping flags; compact rows keep the rail).
  • .cursor/docs/design-system.md §Ink ladder (/60 is the floor for text a person must read) and .cursor/rules/design-system.mdc.
  • AGENTS.md §UI And Theme and §Test Policy: no unit test. Check the real path in a browser.
  • CONTEXT.md names this source Connected app.

Verify:

  • bun run --filter @docs.plus/webapp typecheck exits 0. bun run lint, bun run lint:styles and bun run format pass at the repo root.
  • Start the local stack with make dev-local. Sign in as the owner of a test pad and open a heading chat.
  • Make posts with the key. After Mark MCP chat posts with a fixed connected-app metadata key #336 lands, post through the post_chat_message MCP tool on the local stack. Or, in local Supabase Studio only, set metadata to {"via":"connected_app"} on a test message in public.messages. Reload the pad after a Studio edit.
  • Desktop browser, light and dark:
    1. The owner sends two messages in a row. Give the second one the key. It renders as a compact row, and its footer shows "via connected app".
    2. Give the key to a message that starts a group, such as the first one after another person's message. Its footer shows the label too.
    3. Edit the connected-app post. The footer shows both labels.
    4. A plain message shows no label.
  • Phone: use a mobile user agent (the mobile shell is user-agent gated on the server). Repeat steps 1 to 4, light and dark.
  • Screen reader (VoiceOver on macOS): the row reads "Posted through a connected app" once.

Out of scope

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    ChatRelated to chat featuresUIenhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions