feat(guild): moveChannelToParent for category drag-drop (v0.8.168)

Move channels between categories with position compaction in the old parent.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Raven Scott
2026-05-22 21:55:28 -04:00
co-authored by Cursor
parent fa0af043c2
commit d9cd75151a
2 changed files with 38 additions and 0 deletions
+1
View File
@@ -31,6 +31,7 @@ Create and load guilds in local storage, join peers on `pearcord:guild:{guildId}
| `PearcordGuild#listChannels()` / `#listMembers()` | DB queries with thread meta attached | | `PearcordGuild#listChannels()` / `#listMembers()` | DB queries with thread meta attached |
| `PearcordGuild#createChannel`, `#createCategory`, `#createThread`, `#createForumThread` | Channel tree | | `PearcordGuild#createChannel`, `#createCategory`, `#createThread`, `#createForumThread` | Channel tree |
| `PearcordGuild#reorderChannelsInParent` | Reassign `position` for siblings under one category/root | | `PearcordGuild#reorderChannelsInParent` | Reassign `position` for siblings under one category/root |
| `PearcordGuild#moveChannelToParent` | Move channel into category (v0.8.168) |
| `PearcordGuild#reorderCategories` | Reassign `position` for category rows | | `PearcordGuild#reorderCategories` | Reassign `position` for category rows |
| `PearcordGuild#updateChannel`, `#ingestChannel` | Upsert + thread meta | | `PearcordGuild#updateChannel`, `#ingestChannel` | Upsert + thread meta |
| `PearcordGuild#setMessageHandler(fn)` | Inbound `RPC.MESSAGE_CREATE` persistence hook (platform sets this) | | `PearcordGuild#setMessageHandler(fn)` | Inbound `RPC.MESSAGE_CREATE` persistence hook (platform sets this) |
+37
View File
@@ -1118,6 +1118,43 @@ class PearcordGuild extends EventEmitter {
return updated return updated
} }
async moveChannelToParent ({ channelId, parentId = null } = {}) {
if (!this.guild) throw new Error('no active guild')
if (!channelId) throw new Error('channelId required')
const pid = parentId || null
const existing = await this.listChannels()
const ch = existing.find((c) => c.id === channelId)
if (!ch) throw new Error('channel not found')
if (ch.type === CHANNEL_TYPES.CATEGORY || ch.type === CHANNEL_TYPES.THREAD) {
throw new Error('cannot move category or thread')
}
if (pid) {
const parent = existing.find((c) => c.id === pid)
if (!parent || parent.type !== CHANNEL_TYPES.CATEGORY) {
throw new Error('parent must be a category')
}
}
const currentParent = ch.parentId || null
if (currentParent === pid) return []
const position = this._nextPosition(existing, pid)
const merged = await this.updateChannel({ ...ch, parentId: pid, position })
const updated = [merged]
const oldSiblings = existing.filter(
(c) =>
c.id !== channelId &&
c.type !== CHANNEL_TYPES.CATEGORY &&
c.type !== CHANNEL_TYPES.THREAD &&
(c.parentId || null) === currentParent
)
oldSiblings.sort((a, b) => (a.position || 0) - (b.position || 0))
for (let i = 0; i < oldSiblings.length; i++) {
const sib = oldSiblings[i]
if ((sib.position || 0) === i) continue
updated.push(await this.updateChannel({ ...sib, position: i }))
}
return updated
}
async reorderCategories ({ categoryIds = [] } = {}) { async reorderCategories ({ categoryIds = [] } = {}) {
if (!this.guild) throw new Error('no active guild') if (!this.guild) throw new Error('no active guild')
const existing = await this.listChannels() const existing = await this.listChannels()