Take a deleted bot out of the rail at once

Deleting a bot only changed the page after a reload. The delete route now
reads who could see the bot before removing it, since its assignments and
workspace places go with it, then pushes server:bot-removed
(BotRemovedData) to them. useLiveBots drops the row, so every tab and
every workspace the bot was in updates together.
This commit is contained in:
2026-10-19 12:20:38 +01:00
parent fccaa6e280
commit 731ea73486
5 changed files with 62 additions and 2 deletions
+28
View File
@@ -0,0 +1,28 @@
import { sendToUser } from "@/src/websocket/(functions)/send-to-user";
type Params = {
bot_id: number | string;
/**
* Everyone who saw the bot, read before its row was deleted: afterwards
* its assignments and workspace places are gone with it, so its
* audience can't be worked out any more.
*/
user_ids: number[];
};
/**
* Pushes `server:bot-removed` to everyone who could see a bot that was
* deleted, so its rail row goes at once and nothing opens a dead
* conversation.
*/
export default function pushBotRemoved({ bot_id, user_ids }: Params) {
for (const user_id of user_ids) {
sendToUser({
user_id,
data: {
event: "server:bot-removed",
data: { bot_id: Number(bot_id) },
},
});
}
}
+12 -1
View File
@@ -1,6 +1,11 @@
import { useState } from "react";
import type { BUN_SQLITE_COBBLE_BOT_MESSAGES } from "@/db/types/db";
import type { BotCreatedData, BotUpdatedData, BotWithLastMessage } from "@/src/types";
import type {
BotCreatedData,
BotRemovedData,
BotUpdatedData,
BotWithLastMessage,
} from "@/src/types";
import useServerEvent from "./use-server-event";
type Params = {
@@ -49,6 +54,12 @@ export default function useLiveBots({ bots, open_bot_id, workspace_id = null }:
},
});
useServerEvent({
event: "server:bot-removed",
onData: (data: BotRemovedData) =>
setLive((prev) => prev.filter((bot) => bot.id != data.bot_id)),
});
useServerEvent({
event: "server:bot-updated",
onData: (data: BotUpdatedData) =>
+10
View File
@@ -1,4 +1,6 @@
import pushBotRemoved from "@/src/bots-queue/push-bot-removed";
import userAuth from "@/src/functions/backend/auth/user-auth";
import grabBotAudience from "@/src/functions/backend/db/access/grab-bot-audience";
import deleteBot from "@/src/functions/backend/db/bots/delete-bot";
import logEvent, { grabRequestIP } from "@/src/functions/backend/logger";
import { BotIdRequestSchema } from "@/src/schemas/bot-schema";
@@ -33,8 +35,16 @@ export const handler: BunextAPIRouteHandler<APIResponseObject> = async ({ req, b
const { bot_id } = parseWithSchema({ schema: BotIdRequestSchema, data: body });
/**
* Read before the delete: its assignments and workspace places go
* with it, so who saw it can't be worked out afterwards.
*/
const audience = await grabBotAudience({ bot_id });
const bot = await deleteBot({ user_id: user.id, bot_id });
pushBotRemoved({ bot_id, user_ids: audience });
await logEvent({
title: "Bot deleted",
category: "system",
+11
View File
@@ -134,6 +134,13 @@ export type BotCreatedData = {
in_own_chat: boolean;
};
/**
* `server:bot-removed` data: the bot that was deleted.
*/
export type BotRemovedData = {
bot_id: number;
};
/**
* `server:bot-updated` data: the bot's new face and status line, and its
* active task (null when there is none).
@@ -550,6 +557,10 @@ export const WebSocketEvents = [
* `BotCreatedData`)
*/
"server:bot-created",
/**
* A bot the user could see was deleted (`data`: `BotRemovedData`)
*/
"server:bot-removed",
/**
* A bot's face or status line changed (`data`: `BotUpdatedData`)
*/