Bring reactions to comments and issues

Signed-off-by: Sebastian Martinez <me@sebastinez.dev>
This commit is contained in:
Sebastian Martinez
2023-07-12 15:36:02 +02:00
committed by Rūdolfs Ošiņš
parent 28718ba0cf
commit 205fc814bc
7 changed files with 91 additions and 4 deletions
+27
View File
@@ -3,6 +3,7 @@
import Authorship from "@app/components/Authorship.svelte";
import Button from "@app/components/Button.svelte";
import Chip from "@app/components/Chip.svelte";
import Icon from "@app/components/Icon.svelte";
import Markdown from "@app/components/Markdown.svelte";
import Textarea from "@app/components/Textarea.svelte";
@@ -14,12 +15,18 @@
export let authorAliasColor: AuthorAliasColor = "--color-foreground-5";
export let timestamp: number;
export let body: string;
export let reactions: [string, string][];
export let showReplyIcon: boolean = false;
export let action: "create" | "view" = "view";
export let caption = "commented";
export let rawPath: string;
const dispatch = createEventDispatcher<{ toggleReply: null }>();
$: groupedReactions = reactions?.reduce(
(acc, [nid, emoji]) => acc.set(emoji, [...(acc.get(emoji) ?? []), nid]),
new Map<string, string[]>(),
);
</script>
<style>
@@ -48,6 +55,14 @@
display: flex;
gap: 0.5rem;
}
.reactions {
margin-top: 1rem;
}
.reaction {
display: inline-flex;
flex-direction: row;
gap: 0.5rem;
}
</style>
<div class="card" {id}>
@@ -84,5 +99,17 @@
{:else}
<Markdown {rawPath} content={body} />
{/if}
{#if groupedReactions.size > 0}
<div class="reactions">
{#each groupedReactions as [reaction, nids], key}
<Chip {key}>
<div class="reaction">
<span>{reaction}</span>
<span title={nids.join("\n")}>{nids.length}</span>
</div>
</Chip>
{/each}
</div>
{/if}
</div>
</div>
+2
View File
@@ -77,6 +77,7 @@
id={root.id}
authorId={root.author.id}
authorAlias={root.author.alias}
reactions={root.reactions}
timestamp={root.timestamp}
body={root.body}
showReplyIcon={Boolean($httpdStore.state === "authenticated")}
@@ -90,6 +91,7 @@
authorId={reply.author.id}
authorAlias={reply.author.alias}
caption="replied"
reactions={reply.reactions}
timestamp={reply.timestamp}
body={reply.body} />
</div>
+3
View File
@@ -378,11 +378,14 @@
class:comment-review={review.verdict === null}
class:positive-review={review.verdict === "accept"}
class:negative-review={review.verdict === "reject"}>
<!-- TODO: Empty array for reactions prop is a workaround
until review comments have reactions -->
<CommentComponent
caption={formatVerdict(review.verdict)}
authorId={author}
authorAlias={review.author.alias}
authorAliasColor={aliasColorForVerdict(review.verdict)}
reactions={[]}
timestamp={review.timestamp}
rawPath={utils.getRawBasePath(
projectId,
+29
View File
@@ -15,6 +15,7 @@
import Authorship from "@app/components/Authorship.svelte";
import Badge from "@app/components/Badge.svelte";
import Button from "@app/components/Button.svelte";
import Chip from "@app/components/Chip.svelte";
import CobHeader from "@app/views/projects/Cob/CobHeader.svelte";
import CobStateButton from "@app/views/projects/Cob/CobStateButton.svelte";
import ErrorModal from "@app/views/projects/Cob/ErrorModal.svelte";
@@ -32,6 +33,11 @@
const rawPath = utils.getRawBasePath(projectId, baseUrl, projectHead);
const api = new HttpdClient(baseUrl);
$: groupedReactions = issue.discussion[0].reactions.reduce(
(acc, [nid, emoji]) => acc.set(emoji, [...(acc.get(emoji) ?? []), nid]),
new Map<string, string[]>(),
);
let action: "edit" | "view";
$: action =
$httpdStore.state === "authenticated" && utils.isLocal(baseUrl.hostname)
@@ -267,6 +273,17 @@
padding-left: 1rem;
margin-left: 1rem;
}
.reactions {
display: inline-flex;
gap: 0.5rem;
margin-top: 1rem;
user-select: none;
}
.reaction {
display: inline-flex;
flex-direction: row;
gap: 0.5rem;
}
.actions {
display: flex;
@@ -334,6 +351,18 @@
<Markdown
content={issue.discussion[0].body}
rawPath={utils.getRawBasePath(projectId, baseUrl, projectHead)} />
{#if issue.discussion[0].reactions}
<div class="reactions txt-tiny">
{#each groupedReactions as [reaction, nids], key}
<Chip {key}>
<div class="reaction">
<span>{reaction}</span>
<span title={nids.join("\n")}>{nids.length}</span>
</div>
</Chip>
{/each}
</div>
{/if}
</div>
<div class="author" slot="author">
opened by <Authorship
+2 -2
View File
@@ -274,7 +274,7 @@ test("peer and branch switching", async ({ page }) => {
await expect(page.getByTitle("Change peer")).toHaveText(
`did:key:${aliceRemote.substring(8).substring(0, 6)}…${aliceRemote.slice(
-6,
)} (radicle) delegate`,
)} (alice) delegate`,
);
await expect(
page.locator(
@@ -339,7 +339,7 @@ test("peer and branch switching", async ({ page }) => {
await expect(page.getByTitle("Change peer")).toHaveText(
`did:key:${bobRemote.substring(8).substring(0, 6)}…${bobRemote.slice(
-6,
)}`,
)} (bob)`,
);
await expect(page.getByTitle("Change peer")).not.toHaveText("delegate");
+4 -2
View File
@@ -20,7 +20,7 @@ test("peer and branch switching", async ({ page }) => {
await expect(page.getByTitle("Change peer")).toHaveText(
` did:key:${aliceRemote
.substring(8)
.substring(0, 6)}…${aliceRemote.slice(-6)} (radicle) delegate`,
.substring(0, 6)}…${aliceRemote.slice(-6)} (alice) delegate`,
);
await expect(page.getByText("Thursday, November 17, 2022")).toBeVisible();
@@ -122,7 +122,9 @@ test("relative timestamps", async ({ page }) => {
await page.getByTitle("Change peer").click();
await page.getByText(bobRemote).click();
await expect(page.getByTitle("Change peer")).toHaveText(
`did:key:${bobRemote.substring(8).substring(0, 6)}…${bobRemote.slice(-6)}`,
`did:key:${bobRemote.substring(8).substring(0, 6)}…${bobRemote.slice(
-6,
)} (bob)`,
);
const latestCommit = page.locator(".teaser").first();
await expect(latestCommit).toContainText("Bob Belcher committed now");
+24
View File
@@ -370,6 +370,18 @@ export async function createCobsFixture(peer: RadiclePeer) {
["bug", "feature-request"],
{ cwd: projectFolder },
);
await peer.rad(
["issue", "react", issueOne, "--emoji", "👍", "--to", issueOne],
{
cwd: projectFolder,
},
);
await peer.rad(
["issue", "react", issueOne, "--emoji", "🎉", "--to", issueOne],
{
cwd: projectFolder,
},
);
await peer.rad(
["assign", issueOne, "--to", `did:key:${peer.nodeId}`],
createOptions(projectFolder, 1),
@@ -384,6 +396,12 @@ export async function createCobsFixture(peer: RadiclePeer) {
createOptions(projectFolder, 2),
);
await peer.rad(
["issue", "react", issueOne, "--emoji", "🙏", "--to", commentIssueOne],
{
cwd: projectFolder,
},
);
const { stdout: replyIssueOne } = await peer.rad(
[
"comment",
issueOne,
@@ -394,6 +412,12 @@ export async function createCobsFixture(peer: RadiclePeer) {
],
createOptions(projectFolder, 3),
);
await peer.rad(
["issue", "react", issueOne, "--emoji", "🚀", "--to", replyIssueOne],
{
cwd: projectFolder,
},
);
await peer.rad(
[
"comment",