diff --git a/api/src/chat/repositories/block.repository.ts b/api/src/chat/repositories/block.repository.ts index 5eb3cd3b..69e575c9 100644 --- a/api/src/chat/repositories/block.repository.ts +++ b/api/src/chat/repositories/block.repository.ts @@ -131,11 +131,12 @@ export class BlockRepository extends BaseRepository< ): Promise { if (criteria._id?.$in && updates?.$set?.category) { const ids: string[] = criteria._id?.$in || []; - const objIds = ids.map((b) => { - return new mongoose.Types.ObjectId(b); - }); const category: string = updates.$set.category; - const objCategory = new mongoose.Types.ObjectId(category); + + // Step 1: Map IDs and Category + const { objIds, objCategory } = this.mapIdsAndCategory(ids, category); + + // Step 2: Find other blocks const otherBlocks = await this.model.find({ _id: { $nin: objIds }, category: { $ne: objCategory }, @@ -145,51 +146,77 @@ export class BlockRepository extends BaseRepository< ], }); - for (const id of ids) { - const oldState = await this.model.findOne({ - _id: new mongoose.Types.ObjectId(id), - }); - if (oldState.category.toString() !== category) { - const updatedNextBlocks = oldState.nextBlocks.filter((nextBlock) => - ids.includes(nextBlock.toString()), - ); + // Step 3: Update blocks in the provided scope + await this.updateBlocksInScope(objCategory, ids); - const updatedAttachedBlock = ids.includes( - oldState.attachedBlock?.toString() || '', - ) - ? oldState.attachedBlock - : null; + // Step 4: Update external blocks + await this.updateExternalBlocks(otherBlocks, objIds); + } + } - await this.model.updateOne( - { _id: new mongoose.Types.ObjectId(id) }, - { - nextBlocks: updatedNextBlocks, - attachedBlock: updatedAttachedBlock, - }, - ); - } + private mapIdsAndCategory( + ids: string[], + category: string, + ): { + objIds: mongoose.Types.ObjectId[]; + objCategory: mongoose.Types.ObjectId; + } { + const objIds = ids.map((id) => new mongoose.Types.ObjectId(id)); + const objCategory = new mongoose.Types.ObjectId(category); + return { objIds, objCategory }; + } + + private async updateBlocksInScope( + objCategory: mongoose.Types.ObjectId, + ids: string[], + ): Promise { + for (const id of ids) { + const oldState = await this.model.findOne({ + _id: new mongoose.Types.ObjectId(id), + }); + if (oldState.category.toString() !== objCategory.toString()) { + const updatedNextBlocks = oldState.nextBlocks.filter((nextBlock) => + ids.includes(nextBlock.toString()), + ); + + const updatedAttachedBlock = ids.includes( + oldState.attachedBlock?.toString() || '', + ) + ? oldState.attachedBlock + : null; + + await this.model.updateOne( + { _id: new mongoose.Types.ObjectId(id) }, + { + nextBlocks: updatedNextBlocks, + attachedBlock: updatedAttachedBlock, + }, + ); + } + } + } + + private async updateExternalBlocks( + otherBlocks, + objIds: Types.ObjectId[], + ): Promise { + for (const block of otherBlocks) { + if ( + objIds.some((id) => id.toString() === block.attachedBlock?.toString()) + ) { + await this.model.updateOne({ _id: block.id }, { attachedBlock: null }); } - for (const block of otherBlocks) { - if (ids.includes(block.attachedBlock?.toString())) { - await this.model.updateOne( - { _id: block.id }, - { - attachedBlock: null, - }, - ); - } - if (block.nextBlocks.some((item) => ids.includes(item.toString()))) { - const updatedNextBlocks = block.nextBlocks.filter( - (nextBlock) => !ids.includes(nextBlock.toString()), - ); - await this.model.updateOne( - { _id: block.id }, - { - nextBlocks: updatedNextBlocks, - }, - ); - } + const updatedNextBlocks = block.nextBlocks.filter( + (nextBlock) => + !objIds.some((id) => id.toString() === nextBlock.toString()), + ); + + if (updatedNextBlocks.length !== block.nextBlocks.length) { + await this.model.updateOne( + { _id: block.id }, + { nextBlocks: updatedNextBlocks }, + ); } } } diff --git a/frontend/src/components/visual-editor/v2/Diagrams.tsx b/frontend/src/components/visual-editor/v2/Diagrams.tsx index 381ce482..52481a66 100644 --- a/frontend/src/components/visual-editor/v2/Diagrams.tsx +++ b/frontend/src/components/visual-editor/v2/Diagrams.tsx @@ -6,12 +6,11 @@ * 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file). */ -import { Add } from "@mui/icons-material"; +import { Add, MoveUp } from "@mui/icons-material"; import DeleteIcon from "@mui/icons-material/Delete"; import EditIcon from "@mui/icons-material/Edit"; import FitScreenIcon from "@mui/icons-material/FitScreen"; import RestartAltIcon from "@mui/icons-material/RestartAlt"; -import MoveIcon from "@mui/icons-material/Swipe"; import ZoomInIcon from "@mui/icons-material/ZoomIn"; import ZoomOutIcon from "@mui/icons-material/ZoomOut"; import { @@ -622,7 +621,7 @@ const Diagrams = () => {