Wait for sidebar frames before reloading on Cable connections

This commit is contained in:
GPT on behalf of DHH
2026-10-07 16:18:39 +02:00
parent dbc7620a76
commit 2b9685c35c
@@ -7,7 +7,7 @@ export default class extends Controller {
static classes = [ "unread" ]
#disconnected = true
#readAt = new Map()
#connection = 0
async connect() {
this.channel ??= await cable.subscribeTo({ channel: "UnreadRoomsChannel" }, {
@@ -19,6 +19,7 @@ export default class extends Controller {
disconnect() {
ignoringBriefDisconnects(this.element, () => {
this.#channelDisconnected()
this.channel?.unsubscribe()
this.channel = null
})
@@ -28,23 +29,24 @@ export default class extends Controller {
this.read({ detail: { roomId: Current.room.id } })
}
read({ detail: { roomId, at } }) {
read({ detail: { roomId } }) {
const room = this.#findRoomTarget(roomId)
if (at) {
this.#readAt.set(Number(roomId), Math.max(Number(at), this.#readAt.get(Number(roomId)) ?? 0))
}
if (room) {
room.classList.remove(this.unreadClass)
this.dispatch("read", { detail: { targetId: roomId } })
}
}
#channelConnected() {
async #channelConnected() {
if (this.#disconnected) {
this.#disconnected = false
this.element.reload()
const connection = ++this.#connection
// Reloading an unfinished frame aborts its response body reader.
await this.element.loaded
if (this.element.isConnected && !this.#disconnected && connection === this.#connection) {
this.element.reload()
}
}
}
@@ -52,11 +54,11 @@ export default class extends Controller {
this.#disconnected = true
}
#unread({ roomId, at }) {
#unread({ roomId }) {
const unreadRoom = this.#findRoomTarget(roomId)
if (unreadRoom) {
if (Current.room.id != roomId && !this.#readSince(roomId, at)) {
if (Current.room.id != roomId) {
unreadRoom.classList.add(this.unreadClass)
}
@@ -64,12 +66,6 @@ export default class extends Controller {
}
}
// Notices fan out one member at a time, so one can arrive after the member has already
// read the room in another tab. It still reorders the room, but doesn't mark it unread.
#readSince(roomId, at) {
return Number(at) <= this.#readAt.get(Number(roomId))
}
#findRoomTarget(roomId) {
return this.roomTargets.find(roomTarget => roomTarget.dataset.roomId == roomId)
}