feat(channels): create & add bot participants#4265
Conversation
📝 WalkthroughSummary by CodeRabbitRelease Notes
WalkthroughThis PR adds bot management to the channel participants UI. A new storage service client gains HTTP methods for listing, creating, and channel-scoping bots and their tokens. Solid-Query hooks ( 🚥 Pre-merge checks | ✅ 3 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@js/app/packages/channel/Participants/AddBotDialog.tsx`:
- Around line 128-131: The close function in AddBotDialog dismisses the dialog
but does not prevent in-flight mutations from completing and executing their
onSuccess callbacks. To fix this, track whether the dialog is currently open
using a state variable, and update this state in the close function before
calling reset(). Then modify the mutation's onSuccess handler (around lines
160-174) to check if the dialog is still open before executing side effects like
props.onCreated(bot). This prevents the bot creation callback from executing
after the user has dismissed the dialog.
In `@js/app/packages/channel/Participants/ChannelParticipantsTab.tsx`:
- Around line 43-49: The useChannelBotsQuery hook is being executed
unconditionally regardless of the channelBotsFlag feature flag state, which
causes unnecessary requests when bots are disabled. Update the
useChannelBotsQuery call to include an enabled configuration option in its
options parameter that is set to the value of channelBotsFlag, ensuring the
query only executes when the ENABLE_CHANNEL_BOTS_FLAG feature flag is active.
This will prevent unnecessary network requests and errors in environments where
channel bots are not enabled.
- Around line 169-173: The removeBotFromChannelMutation.mutate call in the
isBotSenderId block does not handle errors, causing bot removal failures to fail
silently and only log to the hook. Add an onError handler to the mutate call
that triggers user-facing error feedback such as a toast notification or error
message to provide immediate visual feedback when the bot removal operation
fails.
In `@js/app/packages/queries/bots/bots.ts`:
- Around line 46-74: The mutationFn in the createBotWithToken mutation performs
two sequential dependent writes (createBot followed by createBotToken). If the
second operation fails after the first succeeds, an orphaned bot remains in the
backend. Refactor this to use a single atomic backend operation that creates
both the bot and token together in one call, or implement explicit compensation
logic that rolls back the bot creation if the token creation fails. Reference
the storageServiceClient.createBot and storageServiceClient.createBotToken calls
within the mutationFn to determine the best approach with your backend team.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: d017ea38-1498-4f16-8c53-b7ae894f48d3
📒 Files selected for processing (14)
js/app/packages/channel/Participants/AddBotDialog.tsxjs/app/packages/channel/Participants/AddBotMenu.tsxjs/app/packages/channel/Participants/ChannelParticipantsTab.tsxjs/app/packages/channel/Participants/ParticipantsList.tsxjs/app/packages/channel/Participants/ParticipantsListItem.tsxjs/app/packages/core/component/LoadingSpinner.tsxjs/app/packages/core/constant/featureFlags.tsjs/app/packages/queries/bots/bots.tsjs/app/packages/queries/bots/keys.tsjs/app/packages/queries/channel/channel-bots.tsjs/app/packages/queries/channel/keys.tsjs/app/packages/service-clients/service-storage/client.tsjs/app/packages/ui/components/Select.tsxjs/app/packages/ui/index.ts
| const close = () => { | ||
| props.onOpenChange(false); | ||
| reset(); | ||
| }; |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Prevent hidden post-close side effects while create is in flight.
The dialog can be closed during step 1, but the in-flight mutation still runs and later executes onSuccess (including props.onCreated(bot)). This can create/add a bot after the user already dismissed the flow.
Suggested fix
const close = () => {
+ if (step() === 1) return;
props.onOpenChange(false);
reset();
};
return (
<Dialog
open={props.open}
onOpenChange={(open) => {
if (open) props.onOpenChange(true);
- else close();
+ else if (step() !== 1) close();
}}
>
@@
<Dialog.CloseButton
as={Button}
class="ml-auto"
variant="ghost"
size="icon-sm"
+ disabled={step() === 1}
>
<IconX />
</Dialog.CloseButton>Also applies to: 160-174
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@js/app/packages/channel/Participants/AddBotDialog.tsx` around lines 128 -
131, The close function in AddBotDialog dismisses the dialog but does not
prevent in-flight mutations from completing and executing their onSuccess
callbacks. To fix this, track whether the dialog is currently open using a state
variable, and update this state in the close function before calling reset().
Then modify the mutation's onSuccess handler (around lines 160-174) to check if
the dialog is still open before executing side effects like
props.onCreated(bot). This prevents the bot creation callback from executing
after the user has dismissed the dialog.
| const channelBotsFlag = useFeatureFlag(ENABLE_CHANNEL_BOTS_FLAG, { | ||
| enabledOverride: ENABLE_CHANNEL_BOTS_OVERRIDE, | ||
| }); | ||
| const participantsQuery = useChannelParticipantsQuery(() => props.channelId); | ||
| const channelBotsQuery = useChannelBotsQuery(() => ({ | ||
| channelId: props.channelId, | ||
| })); |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift
Gate useChannelBotsQuery execution behind the feature flag.
The bots panel is feature-gated, but useChannelBotsQuery still runs even when the flag is off. That can produce unnecessary requests/errors in environments where bots are disabled.
Suggested direction
- const channelBotsQuery = useChannelBotsQuery(() => ({
- channelId: props.channelId,
- }));
+ const channelBotsQuery = useChannelBotsQuery(() => ({
+ channelId: props.channelId,
+ enabled: channelBotsFlag().enabled,
+ }));And update useChannelBotsQuery options to honor enabled in the query config.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@js/app/packages/channel/Participants/ChannelParticipantsTab.tsx` around lines
43 - 49, The useChannelBotsQuery hook is being executed unconditionally
regardless of the channelBotsFlag feature flag state, which causes unnecessary
requests when bots are disabled. Update the useChannelBotsQuery call to include
an enabled configuration option in its options parameter that is set to the
value of channelBotsFlag, ensuring the query only executes when the
ENABLE_CHANNEL_BOTS_FLAG feature flag is active. This will prevent unnecessary
network requests and errors in environments where channel bots are not enabled.
| if (isBotSenderId(participantId)) { | ||
| removeBotFromChannelMutation.mutate({ | ||
| channelId: props.channelId, | ||
| botId: senderFromStorageId(participantId).id, | ||
| }); |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
Add user-facing error feedback for bot removal failures.
Bot removal currently fails silently in UI (hook logs only). Provide an onError handler here so users get immediate feedback when removal fails.
Suggested fix
if (isBotSenderId(participantId)) {
- removeBotFromChannelMutation.mutate({
- channelId: props.channelId,
- botId: senderFromStorageId(participantId).id,
- });
+ removeBotFromChannelMutation.mutate(
+ {
+ channelId: props.channelId,
+ botId: senderFromStorageId(participantId).id,
+ },
+ {
+ onError: () => toast.failure('Failed to remove bot from channel'),
+ }
+ );
return;
}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@js/app/packages/channel/Participants/ChannelParticipantsTab.tsx` around lines
169 - 173, The removeBotFromChannelMutation.mutate call in the isBotSenderId
block does not handle errors, causing bot removal failures to fail silently and
only log to the hook. Add an onError handler to the mutate call that triggers
user-facing error feedback such as a toast notification or error message to
provide immediate visual feedback when the bot removal operation fails.
| mutationFn: async ( | ||
| vars: CreateBotWithTokenParams | ||
| ): Promise<CreateBotWithTokenResponse> => { | ||
| const bot = await throwOnErr(() => | ||
| storageServiceClient.createBot({ | ||
| avatar_url: vars.avatarUrl, | ||
| description: vars.description, | ||
| handle: vars.handle, | ||
| name: vars.name, | ||
| team_id: vars.teamId, | ||
| }) | ||
| ); | ||
| const tokenResponse = await throwOnErr(() => | ||
| storageServiceClient.createBotToken({ | ||
| bot_id: bot.id, | ||
| expires_at: vars.tokenExpiresAt, | ||
| label: vars.tokenLabel, | ||
| }) | ||
| ); | ||
|
|
||
| return { | ||
| bot, | ||
| token: tokenResponse.token, | ||
| bot_token: tokenResponse.bearer_token, | ||
| }; | ||
| }, | ||
| onSuccess: () => { | ||
| void invalidateBots(); | ||
| }, |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift
Make bot+token creation atomic (or add compensation) to prevent partial writes.
This mutation does two dependent writes; if token creation fails after bot creation, the operation surfaces as failed while backend state is already mutated. That creates orphaned bots and retry hazards. Please move to a single atomic backend operation (preferred) or implement explicit compensation/idempotency semantics for this flow.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@js/app/packages/queries/bots/bots.ts` around lines 46 - 74, The mutationFn in
the createBotWithToken mutation performs two sequential dependent writes
(createBot followed by createBotToken). If the second operation fails after the
first succeeds, an orphaned bot remains in the backend. Refactor this to use a
single atomic backend operation that creates both the bot and token together in
one call, or implement explicit compensation logic that rolls back the bot
creation if the token creation fails. Reference the
storageServiceClient.createBot and storageServiceClient.createBotToken calls
within the mutationFn to determine the best approach with your backend team.
No description provided.