Skip to content

docs(ui-kit/angular): thread subscription, pin & save messages and co… - #454

Open
aanshisingh-cometchat wants to merge 6 commits into
mainfrom
feature/angular-thread-subscription-pin-save
Open

aanshisingh-cometchat wants to merge 6 commits into
mainfrom
feature/angular-thread-subscription-pin-save

Conversation

@aanshisingh-cometchat

Copy link
Copy Markdown
Contributor

…nversations

Documents the three features shipped in Angular UI Kit v5.2.0 (cometchat-team/uikit-angular#559).

New pages:

  • components/cometchat-pinned-messages — the conversation-wide pinned panel
  • components/cometchat-saved-messages — the private, cross-conversation panel
  • guides/thread-subscription — follow/unfollow end to end: the feature gate, both surfaces, ThreadSubscriptionService, events, and the optimistic/ debounce/revert behaviour
  • guides/pin-and-save-messages — pin and save messages, pin conversations, PinSaveService, events, limits and localization

Updated where the feature landed: thread-header (follow control, hideThreadSubscriptionToggle, trailingView, threadSubscriptionChange), message-list (five hide-inputs, threadSubscriptionChange, the Organise flyout), message-header (showPinnedMessagesOption, pinnedMessagesClick), conversations (hidePinConversation, pinned-first ordering), conversation-item and message-bubble (the markers), events (CometChatThreadEvents, CometChatPinSaveEvents), global-config (the three feature gates), core-features, both overviews, and docs.json navigation.

Written against the implementation rather than the PR description, which corrects three points the source's own docs and JSDoc get wrong:

  • the pinned panel handles Message Information internally; only Translate and Report are forwarded via messageOptionClick
  • thread-header's trailingView replaces only the follow control, not the close button
  • CometChatPinSaveEvents emits source "optimistic"/"revert"/"sdk", not "local"

No Storybook iframes on the two new panel pages: neither component has a published story yet.

Description

Related Issue(s)

Type of Change

  • Documentation correction/update
  • New documentation
  • Improvement to existing documentation
  • Typo fix
  • Other (please specify)

Checklist

  • I have read the CONTRIBUTING document
  • My branch name follows the naming convention
  • My changes follow the documentation style guide
  • I have checked for spelling and grammar errors
  • All links in my changes are valid and working
  • My changes are accurately described in this pull request

Additional Information

Screenshots (if applicable)

…nversations

Documents the three features shipped in Angular UI Kit v5.2.0
(cometchat-team/uikit-angular#559).

New pages:
- components/cometchat-pinned-messages — the conversation-wide pinned panel
- components/cometchat-saved-messages — the private, cross-conversation panel
- guides/thread-subscription — follow/unfollow end to end: the feature gate,
  both surfaces, ThreadSubscriptionService, events, and the optimistic/
  debounce/revert behaviour
- guides/pin-and-save-messages — pin and save messages, pin conversations,
  PinSaveService, events, limits and localization

Updated where the feature landed: thread-header (follow control,
hideThreadSubscriptionToggle, trailingView, threadSubscriptionChange),
message-list (five hide-inputs, threadSubscriptionChange, the Organise
flyout), message-header (showPinnedMessagesOption, pinnedMessagesClick),
conversations (hidePinConversation, pinned-first ordering), conversation-item
and message-bubble (the markers), events (CometChatThreadEvents,
CometChatPinSaveEvents), global-config (the three feature gates),
core-features, both overviews, and docs.json navigation.

Written against the implementation rather than the PR description, which
corrects three points the source's own docs and JSDoc get wrong:
- the pinned panel handles Message Information internally; only Translate
  and Report are forwarded via messageOptionClick
- thread-header's trailingView replaces only the follow control, not the
  close button
- CometChatPinSaveEvents emits source "optimistic"/"revert"/"sdk", not "local"

No Storybook iframes on the two new panel pages: neither component has a
published story yet.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@mintlify

mintlify Bot commented Aug 7, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
cometchat 🟢 Ready View Preview Aug 7, 2026, 3:01 AM

💡 Tip: Enable Workflows to automatically generate PRs for you.

Two things in one commit: the pending working-tree expansion of these pages,
and a set of corrections found by diffing every documented symbol against
uikit-angular#559 and against React's docs PR #464.

Corrections — the docs described an API that does not exist:

- `IThreadSubscriptionChanged` was documented with `state:
  CometChat.ThreadSubscriptionState` (`SUBSCRIBED`/`NOT_SUBSCRIBED`/`UNKNOWN`)
  and a `source` string. Neither field exists, and `ThreadSubscriptionState` is
  nowhere in the repo. The payload is `{ parentMessageId, subscribed }`. React
  publishes the identical shape on `ui:thread/subscription-changed`, so this was
  a superseded design, never a platform difference.
- `IPinSaveChanged.source` likewise does not exist; the payload is `{ message }`.
- `ccConversationPinned`, `ccConversationUnpinned` and `IConversationPinChanged`
  do not exist. `CometChatConversationEvents` has only `ccConversationDeleted`
  and `ccUpdateConversation`. See the note below.
- `ThreadSubscriptionService.getState()` does not exist, and `isFollowing()` /
  `toggle()` take the message, not a parent id, returning a boolean. The worked
  example passed an id to both.
- The capability probe checks `subscribeToThread` and `unsubscribeFromThread`
  only. `getThreadSubscriptionState` was listed as a third probe and is not one.
- The debounce was described backwards: docs said rapid taps collapse so the
  user's *last* intent reaches the server and a mid-request tap is re-armed. The
  service is leading-edge — the write leaves on the FIRST tap and anything
  within 400ms, or while in flight, is swallowed whole. A failed write clears
  the stamp so a deliberate retry is not swallowed.
- "The service holds the unacked value as an overlay" described a mechanism that
  is not there. State is read off the message; toggle() publishes and each
  surface stamps its held copies, and a failure publishes the reverse.

Additions — real API that was undocumented:

- The optimistic tier, `ccMessagePinChanged` / `ccMessageSaveChanged` with
  `IPinChanged` / `ISaveChanged`. React documents its equivalent
  (`ui:message/pin-changed`, `ui:message/save-changed`) with the same payloads.
- The merged observables `pinned$` / `unpinned$` / `saved$` / `unsaved$`, which
  pair both tiers per direction. The source says to prefer these over the raw
  subjects; the docs taught only the raw subjects.
- The typed `on*` helpers, which take a `DestroyRef` and unsubscribe with the
  component — while events.mdx was telling readers to hand-manage subscriptions
  to avoid leaks.
- `getSystemPinnedMessagesLimit()` / `getSystemPinnedConversationsLimit()`,
  folded into the existing system-pin paragraph rather than given a section of
  their own, since that paragraph already had the app-setting keys.

Known gap, deliberately not papered over: React has three conversation pin
events (`conversation/pinned`, `conversation/unpinned`, and optimistic
`ui:conversation/pin-changed`); Angular publishes none. Conversation pinning
works in the UI but emits nothing, so an integrator's own sidebar has no sync
path. The false claim is removed and readers are pointed at
`conversation.isPinned()` on render; the missing events are raised against #559.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018rhePm8oMBbjPeRFzN7HTg
…hey exist

The previous commit removed `ccConversationPinned` / `ccConversationUnpinned`
because nothing in the kit published them — `CometChatConversationEvents` had
only `ccConversationDeleted` and `ccUpdateConversation`, and the docs were
describing React's design rather than Angular's code.

uikit-angular 919f52e6 ("publish conversation-pin events and honour the SDK's
...") has since added them, so the claim is true again. Restored with the real
shapes rather than the ones the docs originally guessed:

- `ccConversationPinned` / `ccConversationUnpinned` carry
  `IConversationPinSaveChanged` — `{ conversation }`. The old docs named the
  payload `IConversationPinChanged` for these; that interface exists but is the
  optimistic one.
- `ccConversationPinChanged` carries `IConversationPinChanged` —
  `{ conversation, pinned }`, where `pinned` is the state this client claims.
- `conversationPinned$` / `conversationUnpinned$` merge both tiers, with
  `onConversationPinned` / `onConversationUnpinned` as the DestroyRef-aware
  helpers. Documented as the thing to prefer, matching how the message events
  are now documented.

Neither the invented `source` field nor `CometChat.ThreadSubscriptionState`
comes back — those remain absent from the code.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018rhePm8oMBbjPeRFzN7HTg
Re-checked the pin/save/thread docs against uikit-angular#559 at 4d890f5c and
found one claim of my own that was wrong.

The note added alongside the conversation-pin events said a conversation pin is
"private and multi-device: it rearranges only that user's list, so these arrive
on their own devices and nowhere else". That is true of a personal pin and false
of an app-wide one. An admin can pin a conversation globally, carrying
`pinnedBy === "app_system"`, and that reaches every user — so a frame can arrive
in a session whose user did nothing. It also contradicted this doc set's own
cometchat-conversations page, which already said `isPinned()` covers both.

Both pages now name `isSystemPinned()` as the way to tell the two apart. The SDK
exposes it for exactly this and its own docstring points at it, so comparing
`getPinnedBy()` against the literal "app_system" was advice worth removing from
the conversations page too. Precedence when both pins exist is the server's, and
that is now stated rather than left to the reader.

Also documented, from 919f52e6's own reasoning: the SDK does not echo a pin back
to the device that made it, which is why CometChatConversations publishes on its
own confirmed toggle — and why a surface should take the merged
conversationPinned$ / conversationUnpinned$ rather than a single tier.

Verified against the branch: all 57 event symbols the page names exist in
projects/cometchat-uikit/src, including the six merged observables and both
conversation subscribe helpers; every Conversation accessor named — isPinned,
isSystemPinned, getPinnedBy, getPinnedAt — exists in the SDK typings
(4.1.14-beta-15); and no phantom API has crept back.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018rhePm8oMBbjPeRFzN7HTg
… missing

Every neighbouring component page carries a live preview — conversations has
four, thread-header and message-list two each — while the two newest pages had
none, which made them look less finished than the components around them.

The stories now exist on #559 itself (4d890f5c), and the public Angular
Storybook is already serving that build, so both ids resolve today:

  components-messages-cometchat-pinned-messages--default
  components-messages-cometchat-saved-messages--default

Note the shape of those ids. Angular titles these 'CometChat Pinned Messages',
so the slug carries `cometchat-`; React's docs link
`components-messages-pinned-messages--default` without it. The two platforms
name the same component differently, and that is worth reconciling — but the
docs must match the stories that exist, so these follow Angular's.

Height is 600px rather than the 250px thread-header uses: these are scrolling
lists, and a short frame would show one row and hide the point of the panel.

Verified: all 44 story ids referenced anywhere in ui-kit/angular resolve
against https://storybook.cometchat.io/angular/index.json, these two included.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018rhePm8oMBbjPeRFzN7HTg
…t the code

Every claim below was checked against the Angular UI Kit source; each was wrong
in a way an integrator would act on.

Pin permissions had three mutually contradictory versions and none matched the
kit. The pinned-messages page described an allow-list (owner/admin/moderator),
the guide and message-list page a deny-list (participants denied), and the
implementation has no client-side role gate at all — both `pin-save-utils.ts`
and the option builder say so explicitly. The worst line told integrators a
participant would not see Unpin; they do, and the server refuses the call. All
three now say the same thing: no client gate, the server decides, and an
allow-list was tried and removed because `getScope()` is frequently absent on a
Group derived from a conversation.

`event.state` does not exist — the field is `subscribed`. Two code examples
used it, contradicting the events table twenty lines below one of them.

`source` on `CometChatPinSaveEvents` does not exist. A code example destructured
it and a paragraph documented its three values as an API contract; the two-tier
design replaced it. Replaced with what the events actually carry, and pointed
readers at the merged `pinned$` / `unpinned$` / `saved$` / `unsaved$`
observables.

Auto-subscribe does not arrive through an SDK thread listener. The SDK emits no
subscription events — as the same page correctly states 68 lines earlier. The
kit derives it from the message itself: a reply you authored, or one that
mentions you.

Four of the six documented thread localization keys were invented
(`thread_mute`, `thread_unmute`, `thread_followed_toast`,
`thread_unfollowed_toast`). Replaced with the real `thread_subscription_*` keys
and their actual English. The "Mute thread" / "Unmute thread" labels went with
them: both surfaces share one pair of strings, which contradicts the stated
rationale for wording them differently.

Also corrected: the minimum SDK version (4.1.14-beta-1 was never published, and
released 4.1.14 carries none of these APIs — everything lands in 4.2.0), three
limit-error strings, the claim that the conversation pin cap is read from the
rejection rather than app settings, and `messageOptionClick` forwarding Message
Privately as well as Translate and Report.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C2hqhfy48PEPCbAsgKHMQH
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant