From aab9149db01b38dc9b5a51f404e115db959c8358 Mon Sep 17 00:00:00 2001 From: estib Date: Mon, 27 Jan 2025 09:40:07 +0100 Subject: [PATCH 1/2] Shared array utils: Dedup by property Add a utility to deduplicate items in an array based on the values of a property --- packages/shared/src/lib/utils/array.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/packages/shared/src/lib/utils/array.ts b/packages/shared/src/lib/utils/array.ts index 492a55b7ba..5a79ce1c37 100644 --- a/packages/shared/src/lib/utils/array.ts +++ b/packages/shared/src/lib/utils/array.ts @@ -1,3 +1,18 @@ export function deduplicate(array: T[]): T[] { return Array.from(new Set(array)); } + +export function deduplicateBy(array: T[], key: K): T[] { + const seen = new Set(); + const result: T[] = []; + + for (const item of array) { + const value = item[key]; + if (!seen.has(value)) { + seen.add(value); + result.push(item); + } + } + + return result; +} From eb3d5031fe172809906c53f528a4c933a2657146 Mon Sep 17 00:00:00 2001 From: estib Date: Mon, 27 Jan 2025 09:40:34 +0100 Subject: [PATCH 2/2] Display the users that commented on the review --- .../lib/components/review/ReviewInfo.svelte | 30 +++++++++++++++-- apps/web/src/lib/diffParsing.ts | 2 -- .../[branchId]/commit/[changeId]/+page.svelte | 2 +- packages/shared/src/lib/branches/types.ts | 17 ++++++++++ .../lib/chat/chatChannelsPreview.svelte.ts | 32 ++++++++++++++++++- 5 files changed, 77 insertions(+), 6 deletions(-) diff --git a/apps/web/src/lib/components/review/ReviewInfo.svelte b/apps/web/src/lib/components/review/ReviewInfo.svelte index 94e08aa4b4..1dff134799 100644 --- a/apps/web/src/lib/components/review/ReviewInfo.svelte +++ b/apps/web/src/lib/components/review/ReviewInfo.svelte @@ -1,10 +1,15 @@ @@ -42,7 +62,13 @@ diff --git a/packages/shared/src/lib/branches/types.ts b/packages/shared/src/lib/branches/types.ts index 386f17d100..5be768dd40 100644 --- a/packages/shared/src/lib/branches/types.ts +++ b/packages/shared/src/lib/branches/types.ts @@ -210,6 +210,23 @@ async function getUsersWithAvatars(userEmails: string[]) { ); } +export type Commenter = { + avatarUrl: string | undefined; + name: string | undefined; +}; + +export async function getCommentersWithAvatars(commenters: Commenter[]) { + return await Promise.all( + commenters.map(async (commenter) => { + const name = commenter.name ?? 'unknown'; + return { + srcUrl: commenter.avatarUrl ?? (await gravatarUrlFromEmail(name)), + name + }; + }) + ); +} + export async function getPatchContributorsWithAvatars(patch: Patch) { return await getUsersWithAvatars(patch.contributors); } diff --git a/packages/shared/src/lib/chat/chatChannelsPreview.svelte.ts b/packages/shared/src/lib/chat/chatChannelsPreview.svelte.ts index c34c111b56..fe68c88466 100644 --- a/packages/shared/src/lib/chat/chatChannelsPreview.svelte.ts +++ b/packages/shared/src/lib/chat/chatChannelsPreview.svelte.ts @@ -1,6 +1,8 @@ import { chatChannelsSelectors } from './chatChannelsSlice'; -import { createChannelKey, type LoadableChatChannel } from '$lib/chat/types'; +import { createChannelKey, type ChatMessageUser, type LoadableChatChannel } from '$lib/chat/types'; import { registerInterest, type InView } from '$lib/interest/registerInterestFunction.svelte'; +import { map } from '$lib/network/loadable'; +import { deduplicateBy } from '$lib/utils/array'; import type { ChatChannelsService } from '$lib/chat/chatChannelsService'; import type { AppChatChannelsState } from '$lib/redux/store.svelte'; import type { Reactive } from '$lib/storeUtils'; @@ -26,3 +28,31 @@ export function getChatChannel( } }; } + +export function getChatChannelParticipants( + appState: AppChatChannelsState, + chatMessagesService: ChatChannelsService, + projectId: string, + changeId: string, + inView?: InView +): Reactive { + const chatMessagesInterest = chatMessagesService.getChatChannelInterest(projectId, changeId); + registerInterest(chatMessagesInterest, inView); + + const chatChannelKey = createChannelKey(projectId, changeId); + const chatChannelParticipants = $derived.by(() => { + const channel = chatChannelsSelectors.selectById(appState.chatChannels, chatChannelKey); + return map(channel, (channel) => + deduplicateBy( + channel.messages.map((message) => message.user), + 'id' + ) + ); + }); + + return { + get current() { + return chatChannelParticipants; + } + }; +}