fix(client): restore host-confirmed workspace order
This commit is contained in:
@@ -55,6 +55,8 @@ export class WorkspaceManager {
|
||||
private orderRequestGeneration = 0
|
||||
/** Increments on order frames so a later remote commit outranks an older unary echo. */
|
||||
private orderFrameGeneration = 0
|
||||
/** Last complete order accepted from a Host baseline, frame, or current unary echo. */
|
||||
private committedOrder: WorkspaceId[] = []
|
||||
/**
|
||||
* Ids this process has seen removed, kept for the connection's lifetime so
|
||||
* a late changed frame or a stale baseline row cannot resurrect a deleted
|
||||
@@ -171,8 +173,8 @@ export class WorkspaceManager {
|
||||
): Promise<RpcResult<{ workspaceIds: WorkspaceId[] }>> {
|
||||
const requestGeneration = ++this.orderRequestGeneration
|
||||
const frameGeneration = this.orderFrameGeneration
|
||||
const previousOrder = this.itemViews().map(workspace => workspace.workspaceId)
|
||||
this.installOrder(insertIdBefore(previousOrder, workspaceId, beforeWorkspaceId))
|
||||
const localOrder = this.itemViews().map(workspace => workspace.workspaceId)
|
||||
this.installOrder(insertIdBefore(localOrder, workspaceId, beforeWorkspaceId))
|
||||
let result: RpcResult<{ workspaceIds: WorkspaceId[] }>
|
||||
try {
|
||||
;({ result } = await this.api.workspace.insertBefore({
|
||||
@@ -182,16 +184,16 @@ export class WorkspaceManager {
|
||||
} catch (error) {
|
||||
if (requestGeneration === this.orderRequestGeneration
|
||||
&& frameGeneration === this.orderFrameGeneration) {
|
||||
this.installOrder(previousOrder)
|
||||
this.installOrder(this.committedOrder)
|
||||
}
|
||||
throw error
|
||||
}
|
||||
if (result.ok && requestGeneration === this.orderRequestGeneration
|
||||
&& frameGeneration === this.orderFrameGeneration) {
|
||||
this.installOrder(result.value.workspaceIds)
|
||||
this.installOrder(result.value.workspaceIds, true)
|
||||
} else if (!result.ok && requestGeneration === this.orderRequestGeneration
|
||||
&& frameGeneration === this.orderFrameGeneration) {
|
||||
this.installOrder(previousOrder)
|
||||
this.installOrder(this.committedOrder)
|
||||
}
|
||||
return result
|
||||
}
|
||||
@@ -239,7 +241,7 @@ export class WorkspaceManager {
|
||||
else if (envelope.payload.type === 'host/workspace-removed') this.remove(envelope.payload.workspaceId)
|
||||
else if (envelope.payload.type === 'host/workspace-order-changed') {
|
||||
this.orderFrameGeneration++
|
||||
this.installOrder(envelope.payload.workspaceIds)
|
||||
this.installOrder(envelope.payload.workspaceIds, true)
|
||||
}
|
||||
else if (envelope.payload.type === 'host/archived-sessions-changed') {
|
||||
this.installArchived(envelope.payload.archivedSessionIds)
|
||||
@@ -292,9 +294,12 @@ export class WorkspaceManager {
|
||||
this.notifier.markDirty()
|
||||
}
|
||||
|
||||
/** Reorder known Workspace objects by a complete Host id sequence. */
|
||||
private installOrder(workspaceIds: readonly WorkspaceId[]): void {
|
||||
this.refreshFrames?.push({ type: 'order', workspaceIds })
|
||||
/** Reorder known Workspace objects, optionally recording a Host-committed sequence. */
|
||||
private installOrder(workspaceIds: readonly WorkspaceId[], committed = false): void {
|
||||
if (committed) {
|
||||
this.refreshFrames?.push({ type: 'order', workspaceIds })
|
||||
this.committedOrder = [...workspaceIds]
|
||||
}
|
||||
const rank = new Map(workspaceIds.map((id, index) => [id, index]))
|
||||
const items = [...this.items].sort((left, right) => {
|
||||
const leftId = left.getSnapshot().view?.workspaceId
|
||||
@@ -317,6 +322,9 @@ export class WorkspaceManager {
|
||||
// late unary response cannot roll back a newer frame.
|
||||
const installed = index === -1 ? undefined : this.items[index]?.getSnapshot().view
|
||||
if (installed !== undefined && Date.parse(view.updatedAt) < Date.parse(installed.updatedAt)) return
|
||||
if (!this.committedOrder.includes(view.workspaceId)) {
|
||||
this.committedOrder = [view.workspaceId, ...this.committedOrder]
|
||||
}
|
||||
if (identity !== undefined) {
|
||||
this.items = index === -1
|
||||
? [identity, ...this.items]
|
||||
@@ -334,6 +342,7 @@ export class WorkspaceManager {
|
||||
private remove(workspaceId: WorkspaceId, direct = false): void {
|
||||
this.refreshFrames?.push({ type: 'remove', workspaceId })
|
||||
this.removedIds.add(workspaceId)
|
||||
this.committedOrder = this.committedOrder.filter(id => id !== workspaceId)
|
||||
const items = this.items.filter(item =>
|
||||
item.getSnapshot().view?.workspaceId !== workspaceId)
|
||||
if (items.length === this.items.length) {
|
||||
@@ -367,6 +376,7 @@ export class WorkspaceManager {
|
||||
installed.set(view.workspaceId, workspace)
|
||||
}
|
||||
this.items = [...installed.values()]
|
||||
this.committedOrder = views.map(view => view.workspaceId)
|
||||
}
|
||||
|
||||
private itemViews(): readonly WorkspaceView[] {
|
||||
|
||||
Reference in New Issue
Block a user