From f0758de9f3acd0807f9e5f9d476448b0ee5fc32d Mon Sep 17 00:00:00 2001 From: Sebastian Martinez Date: Fri, 2 Feb 2024 12:56:47 +0100 Subject: [PATCH] Add reactions to patch revisions - Also adapts to the new reactions API schema everywhere. --- httpd-client/index.ts | 4 +- httpd-client/lib/project/comment.ts | 7 +- httpd-client/lib/project/issue.ts | 18 ++--- httpd-client/lib/project/patch.ts | 63 ++++++--------- httpd-client/lib/shared.ts | 24 +++++- src/components/Comment.svelte | 19 +++-- src/components/ReactionSelector.svelte | 22 +++--- src/components/Reactions.svelte | 14 ++-- src/components/Thread.svelte | 35 ++------- src/lib/reactions.ts | 17 ----- src/views/projects/Cob/Revision.svelte | 52 +++++++++++-- src/views/projects/Issue.svelte | 15 ++-- src/views/projects/Patch.svelte | 101 ++++++++++++++++++++++--- tests/e2e/project/issue.spec.ts | 3 +- tests/e2e/project/threads.spec.ts | 3 +- tests/support/project.ts | 49 +++++++----- 16 files changed, 273 insertions(+), 173 deletions(-) delete mode 100644 src/lib/reactions.ts diff --git a/httpd-client/index.ts b/httpd-client/index.ts index e461b1d8a..a68a3761f 100644 --- a/httpd-client/index.ts +++ b/httpd-client/index.ts @@ -6,7 +6,7 @@ import type { Tree, DiffResponse, } from "./lib/project.js"; -import type { SuccessResponse } from "./lib/shared.js"; +import type { SuccessResponse, CodeLocation, Range } from "./lib/shared.js"; import type { Comment, Embed } from "./lib/project/comment.js"; import type { Commit, @@ -20,13 +20,11 @@ import type { } from "./lib/project/commit.js"; import type { Issue, IssueState } from "./lib/project/issue.js"; import type { - CodeLocation, LifecycleState, Merge, Patch, PatchState, PatchUpdateAction, - Range, Review, Revision, Verdict, diff --git a/httpd-client/lib/project/comment.ts b/httpd-client/lib/project/comment.ts index 78a3f5437..56d726001 100644 --- a/httpd-client/lib/project/comment.ts +++ b/httpd-client/lib/project/comment.ts @@ -1,5 +1,6 @@ import type { z } from "zod"; -import { array, number, object, string, tuple } from "zod"; +import { array, boolean, number, object, string } from "zod"; +import { codeLocationSchema } from "../shared"; export type Comment = z.infer; export type Embed = z.infer["embeds"][0]; @@ -17,7 +18,9 @@ export const commentSchema = object({ }), ), embeds: array(object({ name: string(), content: string() })), - reactions: array(tuple([string(), string()])), + reactions: array(object({ emoji: string(), authors: array(string()) })), timestamp: number(), + location: codeLocationSchema.nullable().optional(), + resolved: boolean(), replyTo: string().nullable(), }); diff --git a/httpd-client/lib/project/issue.ts b/httpd-client/lib/project/issue.ts index a6d70143c..9ca0fe982 100644 --- a/httpd-client/lib/project/issue.ts +++ b/httpd-client/lib/project/issue.ts @@ -1,5 +1,5 @@ -import type { Comment, Embed } from "./comment.js"; -import type { ZodSchema } from "zod"; +import type { Embed } from "./comment.js"; +import type { ZodSchema, z } from "zod"; import { array, boolean, literal, object, string, union } from "zod"; import { commentSchema } from "./comment.js"; @@ -16,16 +16,6 @@ const issueStateSchema = union([ }), ]) satisfies ZodSchema; -export interface Issue { - id: string; - author: { id: string; alias?: string }; - title: string; - state: IssueState; - discussion: Comment[]; - labels: string[]; - assignees: string[]; -} - export const issueSchema = object({ id: string(), author: object({ id: string(), alias: string().optional() }), @@ -34,7 +24,9 @@ export const issueSchema = object({ discussion: array(commentSchema), labels: array(string()), assignees: array(string()), -}) satisfies ZodSchema; +}); + +export type Issue = z.infer; export interface IssueCreated { success: boolean; diff --git a/httpd-client/lib/project/patch.ts b/httpd-client/lib/project/patch.ts index 3f5141085..f9cb0e404 100644 --- a/httpd-client/lib/project/patch.ts +++ b/httpd-client/lib/project/patch.ts @@ -1,5 +1,6 @@ import type { Embed } from "./comment.js"; import type { ZodSchema, z } from "zod"; +import type { CodeLocation } from "../shared.js"; import { commentSchema } from "./comment.js"; @@ -14,6 +15,7 @@ import { tuple, union, } from "zod"; +import { codeLocationSchema } from "../shared.js"; export type PatchState = | { status: "draft" } @@ -55,23 +57,15 @@ const mergeSchema = object({ export type Verdict = "accept" | "reject"; -export interface Review { - author: { id: string; alias?: string }; - verdict?: Verdict | null; - summary: string | null; - comments: string[]; - timestamp: number; -} - const reviewSchema = object({ author: object({ id: string(), alias: string().optional() }), verdict: optional(union([literal("accept"), literal("reject")]).nullable()), - comments: array(string()), + comments: array(commentSchema), summary: string().nullable(), timestamp: number(), -}) satisfies ZodSchema; +}); -export type Revision = z.infer; +export type Review = z.infer; const revisionSchema = object({ id: string(), @@ -85,6 +79,13 @@ const revisionSchema = object({ timestamp: number(), }), ), + reactions: array( + object({ + emoji: string(), + location: codeLocationSchema.nullable(), + authors: array(string()), + }), + ), base: string(), oid: string(), refs: array(string()), @@ -93,17 +94,7 @@ const revisionSchema = object({ timestamp: number(), }); -export interface Patch { - id: string; - author: { id: string; alias?: string }; - title: string; - state: PatchState; - target: string; - labels: string[]; - merges: Merge[]; - assignees: string[]; - revisions: Revision[]; -} +export type Revision = z.infer; export const patchSchema = object({ id: string(), @@ -115,7 +106,9 @@ export const patchSchema = object({ merges: array(mergeSchema), assignees: array(string()), revisions: array(revisionSchema), -}) satisfies ZodSchema; +}); + +export type Patch = z.infer; export const patchesSchema = array(patchSchema) satisfies ZodSchema; @@ -124,23 +117,6 @@ export type LifecycleState = | { status: "open" } | { status: "archived" }; -export type Range = - | { - type: "lines"; - range: { start: number; end: number }; - } - | { - type: "chars"; - line: number; - range: { start: number; end: number }; - }; - -export type CodeLocation = { - path: string; - old?: Range; - new?: Range; -}; - export type PatchUpdateAction = | { type: "edit"; title: string; target: "delegates" } | { type: "label"; labels: string[] } @@ -189,6 +165,13 @@ export type PatchUpdateAction = description: string; embeds?: Embed[]; } + | { + type: "revision.react"; + revision: string; + reaction: string; + location?: CodeLocation; + active: boolean; + } | { type: "revision.redact"; revision: string } | { type: "revision.comment"; diff --git a/httpd-client/lib/shared.ts b/httpd-client/lib/shared.ts index 64827daaa..10a87cbc4 100644 --- a/httpd-client/lib/shared.ts +++ b/httpd-client/lib/shared.ts @@ -1,4 +1,4 @@ -import type { ZodSchema } from "zod"; +import type { ZodSchema, z } from "zod"; import { array, boolean, literal, number, object, string, union } from "zod"; @@ -41,3 +41,25 @@ export const nodeConfigSchema = object({ policy: union([literal("allow"), literal("block")]), scope: union([literal("followed"), literal("all")]), }); + +export const rangeSchema = union([ + object({ + type: literal("lines"), + range: object({ start: number(), end: number() }), + }), + object({ + type: literal("chars"), + line: number(), + range: object({ start: number(), end: number() }), + }), +]); + +export type Range = z.infer; + +export const codeLocationSchema = object({ + path: string(), + old: rangeSchema.optional(), + new: rangeSchema.optional(), +}); + +export type CodeLocation = z.infer; diff --git a/src/components/Comment.svelte b/src/components/Comment.svelte index 1ad52e475..b0d6eebc0 100644 --- a/src/components/Comment.svelte +++ b/src/components/Comment.svelte @@ -1,6 +1,5 @@ @@ -175,22 +174,22 @@ {/if} - {#if (id && handleReaction) || (id && reactions && reactions.size > 0)} + {#if (id && reactOnComment) || (id && reactions && reactions.length > 0)}
- {#if id && handleReaction} - {@const handleReaction_ = handleReaction} + {#if id && reactOnComment} + {@const reactOnComment_ = reactOnComment} { + on:select={async ({ detail: { authors, emoji } }) => { try { - await handleReaction_(nids, reaction); + await reactOnComment_(authors, emoji); } finally { closeFocused(); } }} /> {/if} - {#if id && reactions && reactions.size > 0} - + {#if id && reactions && reactions.length > 0} + {/if}
{/if} diff --git a/src/components/ReactionSelector.svelte b/src/components/ReactionSelector.svelte index 13acd807b..e21134319 100644 --- a/src/components/ReactionSelector.svelte +++ b/src/components/ReactionSelector.svelte @@ -1,5 +1,5 @@ @@ -56,13 +56,17 @@
{#each config.reactions as reaction} + {@const lookedUpReaction = reactions?.find( + ({ emoji }) => emoji === reaction, + )} {/each} diff --git a/src/components/Reactions.svelte b/src/components/Reactions.svelte index 48a20e477..79b73be14 100644 --- a/src/components/Reactions.svelte +++ b/src/components/Reactions.svelte @@ -1,11 +1,11 @@ @@ -24,16 +24,16 @@
- {#each reactions as [reaction, { all: nids }]} + {#each reactions as { emoji, authors }} { if (handleReaction) { - await handleReaction(nids, reaction); + await handleReaction(authors, emoji); } }}>
- {reaction} - {nids.length} + {emoji} + {authors.length}
{/each} diff --git a/src/components/Thread.svelte b/src/components/Thread.svelte index 1aebbcb5a..3d52954e0 100644 --- a/src/components/Thread.svelte +++ b/src/components/Thread.svelte @@ -1,26 +1,6 @@ - -