fix: Improve plugin ui entry points, Fix chat scroll, fix notifications, fix user rights

This commit is contained in:
2026-05-17 16:09:16 +02:00
parent 8e3ccf4157
commit 8631290c01
35 changed files with 1560 additions and 619 deletions

View File

@@ -20,9 +20,10 @@ import type {
} from '../../shared-kernel';
import { RealtimeSessionFacade } from '../../core/realtime';
import { UsersActions } from '../users/users.actions';
import { selectCurrentUser } from '../users/users.selectors';
import { selectAllUsers, selectCurrentUser } from '../users/users.selectors';
import { RoomsActions } from './rooms.actions';
import { selectCurrentRoom, selectSavedRooms } from './rooms.selectors';
import { normalizeRoomAccessControl, resolveLegacyRole } from '../../domains/access-control';
import {
areRoomMembersEqual,
findRoomMember,
@@ -113,6 +114,40 @@ export class RoomMembersSyncEffects {
)
);
/** Keep active-room user roles derived from room access-control assignments. */
syncAccessControlRolesIntoUsers$ = createEffect(() =>
this.actions$.pipe(
ofType(
RoomsActions.createRoomSuccess,
RoomsActions.joinRoomSuccess,
RoomsActions.viewServerSuccess,
RoomsActions.updateRoom
),
withLatestFrom(
this.store.select(selectCurrentRoom),
this.store.select(selectSavedRooms),
this.store.select(selectAllUsers),
this.store.select(selectCurrentUser)
),
mergeMap(([
action,
currentRoom,
savedRooms,
allUsers,
currentUser
]) => {
const room = this.resolveRoleSyncRoom(action, currentRoom, savedRooms);
if (!room)
return EMPTY;
const actions = this.createUserRoleSyncActions(room, allUsers, currentUser ?? null);
return actions.length > 0 ? actions : EMPTY;
})
)
);
/** Update persisted room rosters when signaling presence changes arrive. */
signalingPresenceIntoRoomMembers$ = createEffect(() =>
this.webrtc.onSignalingMessage.pipe(
@@ -342,6 +377,88 @@ export class RoomMembersSyncEffects {
: [RoomsActions.updateRoom({ roomId: room.id, changes: { members } })];
}
private resolveRoleSyncRoom(
action:
| ReturnType<typeof RoomsActions.createRoomSuccess>
| ReturnType<typeof RoomsActions.joinRoomSuccess>
| ReturnType<typeof RoomsActions.viewServerSuccess>
| ReturnType<typeof RoomsActions.updateRoom>,
currentRoom: Room | null,
savedRooms: Room[]
): Room | null {
if ('room' in action) {
return normalizeRoomAccessControl(action.room);
}
if (currentRoom?.id !== action.roomId || !this.hasRoleRelevantRoomChanges(action.changes)) {
return null;
}
const room = this.resolveRoom(action.roomId, currentRoom, savedRooms);
return room ? normalizeRoomAccessControl({ ...room, ...action.changes }) : null;
}
private hasRoleRelevantRoomChanges(changes: Partial<Room>): boolean {
return (
Object.prototype.hasOwnProperty.call(changes, 'hostId') ||
Object.prototype.hasOwnProperty.call(changes, 'members') ||
Object.prototype.hasOwnProperty.call(changes, 'permissions') ||
Object.prototype.hasOwnProperty.call(changes, 'roles') ||
Object.prototype.hasOwnProperty.call(changes, 'roleAssignments') ||
Object.prototype.hasOwnProperty.call(changes, 'channelPermissions') ||
Object.prototype.hasOwnProperty.call(changes, 'slowModeInterval')
);
}
private createUserRoleSyncActions(room: Room, allUsers: User[], currentUser: User | null): Action[] {
const usersById = new Map<string, User>();
for (const user of allUsers) {
if (this.shouldSyncUserRoleForRoom(room, user, currentUser)) {
usersById.set(user.id, user);
}
}
if (currentUser) {
usersById.set(currentUser.id, currentUser);
}
return Array.from(usersById.values())
.map((user) => ({
user,
role: resolveLegacyRole(room, user)
}))
.filter(({ user, role }) => user.role !== role)
.map(({ user, role }) => UsersActions.updateUserRole({ userId: user.id,
role }));
}
private shouldSyncUserRoleForRoom(room: Room, user: User, currentUser: User | null): boolean {
if (currentUser && user.id === currentUser.id) {
return true;
}
if (room.hostId === user.id || room.hostId === user.oderId) {
return true;
}
if (Array.isArray(user.presenceServerIds) && user.presenceServerIds.includes(room.id)) {
return true;
}
if (findRoomMember(room.members ?? [], user.oderId || user.id)) {
return true;
}
return (room.roleAssignments ?? []).some((assignment) => (
assignment.userId === user.id ||
assignment.userId === user.oderId ||
assignment.oderId === user.id ||
assignment.oderId === user.oderId
));
}
private handleMemberRosterRequest(
event: ChatEvent,
currentRoom: Room | null,