fix(team): keep permission launch updates in store
This commit is contained in:
parent
6ea8b469f0
commit
e309eb8a0d
2 changed files with 73 additions and 1 deletions
|
|
@ -727,6 +727,8 @@ function areMemberSpawnStatusEntriesEqual(
|
||||||
): boolean {
|
): boolean {
|
||||||
if (left === right) return true;
|
if (left === right) return true;
|
||||||
if (!left || !right) return left === right;
|
if (!left || !right) return left === right;
|
||||||
|
const leftPendingPermissionIds = [...(left.pendingPermissionRequestIds ?? [])].sort();
|
||||||
|
const rightPendingPermissionIds = [...(right.pendingPermissionRequestIds ?? [])].sort();
|
||||||
// Renderer equality intentionally ignores raw timing fields that do not change
|
// Renderer equality intentionally ignores raw timing fields that do not change
|
||||||
// visible member status. This suppresses heartbeat-only churn in TeamDetailView.
|
// visible member status. This suppresses heartbeat-only churn in TeamDetailView.
|
||||||
return (
|
return (
|
||||||
|
|
@ -738,7 +740,9 @@ function areMemberSpawnStatusEntriesEqual(
|
||||||
left.runtimeAlive === right.runtimeAlive &&
|
left.runtimeAlive === right.runtimeAlive &&
|
||||||
left.runtimeModel === right.runtimeModel &&
|
left.runtimeModel === right.runtimeModel &&
|
||||||
left.bootstrapConfirmed === right.bootstrapConfirmed &&
|
left.bootstrapConfirmed === right.bootstrapConfirmed &&
|
||||||
left.hardFailure === right.hardFailure
|
left.hardFailure === right.hardFailure &&
|
||||||
|
leftPendingPermissionIds.length === rightPendingPermissionIds.length &&
|
||||||
|
leftPendingPermissionIds.every((value, index) => value === rightPendingPermissionIds[index])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3612,6 +3612,74 @@ describe('teamSlice actions', () => {
|
||||||
expect(store.getState().memberSpawnSnapshotsByTeam['my-team']).toBe(previousSnapshot);
|
expect(store.getState().memberSpawnSnapshotsByTeam['my-team']).toBe(previousSnapshot);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('does not suppress spawn snapshots when pending permission request ids change', async () => {
|
||||||
|
const store = createSliceStore();
|
||||||
|
const previousSnapshot = createMemberSpawnSnapshot({
|
||||||
|
teamLaunchState: 'partial_pending',
|
||||||
|
launchPhase: 'active',
|
||||||
|
summary: {
|
||||||
|
confirmedCount: 0,
|
||||||
|
pendingCount: 1,
|
||||||
|
failedCount: 0,
|
||||||
|
runtimeAlivePendingCount: 0,
|
||||||
|
},
|
||||||
|
statuses: {
|
||||||
|
alice: createMemberSpawnStatus({
|
||||||
|
status: 'waiting',
|
||||||
|
launchState: 'runtime_pending_bootstrap',
|
||||||
|
runtimeAlive: false,
|
||||||
|
livenessSource: undefined,
|
||||||
|
bootstrapConfirmed: false,
|
||||||
|
firstSpawnAcceptedAt: '2026-03-12T09:59:30.000Z',
|
||||||
|
lastHeartbeatAt: undefined,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
store.setState({
|
||||||
|
memberSpawnStatusesByTeam: {
|
||||||
|
'my-team': previousSnapshot.statuses,
|
||||||
|
},
|
||||||
|
memberSpawnSnapshotsByTeam: {
|
||||||
|
'my-team': previousSnapshot,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const nextSnapshot = createMemberSpawnSnapshot({
|
||||||
|
teamLaunchState: 'partial_pending',
|
||||||
|
launchPhase: 'active',
|
||||||
|
summary: {
|
||||||
|
confirmedCount: 0,
|
||||||
|
pendingCount: 1,
|
||||||
|
failedCount: 0,
|
||||||
|
runtimeAlivePendingCount: 0,
|
||||||
|
},
|
||||||
|
statuses: {
|
||||||
|
alice: createMemberSpawnStatus({
|
||||||
|
status: 'waiting',
|
||||||
|
launchState: 'runtime_pending_bootstrap',
|
||||||
|
runtimeAlive: false,
|
||||||
|
livenessSource: undefined,
|
||||||
|
bootstrapConfirmed: false,
|
||||||
|
firstSpawnAcceptedAt: '2026-03-12T09:59:30.000Z',
|
||||||
|
lastHeartbeatAt: undefined,
|
||||||
|
pendingPermissionRequestIds: ['perm-1'],
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
hoisted.getMemberSpawnStatuses.mockResolvedValue(nextSnapshot);
|
||||||
|
|
||||||
|
await store.getState().fetchMemberSpawnStatuses('my-team');
|
||||||
|
|
||||||
|
expect(store.getState().memberSpawnSnapshotsByTeam['my-team']).not.toBe(previousSnapshot);
|
||||||
|
expect(store.getState().memberSpawnStatusesByTeam['my-team']).not.toBe(
|
||||||
|
previousSnapshot.statuses
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
store.getState().memberSpawnStatusesByTeam['my-team']?.alice?.pendingPermissionRequestIds
|
||||||
|
).toEqual(['perm-1']);
|
||||||
|
});
|
||||||
|
|
||||||
it('ignores stale spawn-status fetches after runtime already went offline', async () => {
|
it('ignores stale spawn-status fetches after runtime already went offline', async () => {
|
||||||
const store = createSliceStore();
|
const store = createSliceStore();
|
||||||
store.setState({
|
store.setState({
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue