From d18f4bb400dab7fd8e8a8484255b82bf358ade68 Mon Sep 17 00:00:00 2001 From: eti Date: Wed, 2 Sep 2026 23:52:42 +0200 Subject: [PATCH] web/repo: merge the issue and pull components into tickets Signed-off-by: eti --- web/src/fixtures/pull.ts | 36 +--- .../components/notifications/notification.ts | 2 +- .../components/repo/issues/IssueBody.svelte | 17 -- .../repo/issues/IssueCard.stories.svelte | 32 ---- .../components/repo/issues/IssueCard.svelte | 27 --- .../repo/issues/IssueHeader.stories.svelte | 26 --- .../components/repo/issues/IssueHeader.svelte | 16 -- .../repo/issues/IssueInfoBar.stories.svelte | 28 --- .../repo/issues/IssueInfoBar.svelte | 35 ---- .../repo/issues/IssueList.stories.svelte | 41 ---- .../components/repo/issues/IssueList.svelte | 24 --- .../repo/issues/IssueSearch.stories.svelte | 17 -- .../repo/issues/IssueStatePill.stories.svelte | 22 --- .../repo/issues/IssueStatePill.svelte | 43 ----- .../repo/issues/IssueThreadView.svelte | 178 +++++++----------- .../repo/issues/IssueToolbar.stories.svelte | 28 --- .../repo/issues/IssueToolbar.svelte | 82 -------- .../repo/pulls/PullCardContent.svelte | 52 ----- .../repo/pulls/PullList.stories.svelte | 27 --- .../lib/components/repo/pulls/PullList.svelte | 24 --- .../PullReviewCommentForm.stories.svelte | 2 +- .../components/repo/pulls/PullSearch.svelte | 42 ----- .../repo/pulls/PullStatePill.stories.svelte | 23 --- .../repo/pulls/PullStatePill.svelte | 47 ----- .../repo/pulls/PullToolbar.stories.svelte | 19 -- .../lib/components/repo/tickets/Ticket.svelte | 23 ++- .../TicketBody.stories.svelte} | 10 +- .../repo/tickets/TicketCard.stories.svelte | 46 +++++ .../TicketCard.svelte} | 12 +- .../TicketCardContent.svelte} | 30 +-- .../repo/tickets/TicketInfoBar.svelte | 6 +- .../repo/tickets/TicketList.stories.svelte | 57 ++++++ .../components/repo/tickets/TicketList.svelte | 31 +++ .../repo/tickets/TicketSearch.stories.svelte | 25 +++ .../TicketSearch.svelte} | 14 +- .../repo/tickets/TicketToolbar.stories.svelte | 41 ++++ .../TicketToolbar.svelte} | 58 +++--- web/src/lib/components/timeline/types.ts | 2 +- .../[handle]/[repo]/issues/+page.svelte | 20 +- .../routes/[handle]/[repo]/pulls/+page.svelte | 22 ++- 40 files changed, 381 insertions(+), 906 deletions(-) delete mode 100644 web/src/lib/components/repo/issues/IssueBody.svelte delete mode 100644 web/src/lib/components/repo/issues/IssueCard.stories.svelte delete mode 100644 web/src/lib/components/repo/issues/IssueCard.svelte delete mode 100644 web/src/lib/components/repo/issues/IssueHeader.stories.svelte delete mode 100644 web/src/lib/components/repo/issues/IssueHeader.svelte delete mode 100644 web/src/lib/components/repo/issues/IssueInfoBar.stories.svelte delete mode 100644 web/src/lib/components/repo/issues/IssueInfoBar.svelte delete mode 100644 web/src/lib/components/repo/issues/IssueList.stories.svelte delete mode 100644 web/src/lib/components/repo/issues/IssueList.svelte delete mode 100644 web/src/lib/components/repo/issues/IssueSearch.stories.svelte delete mode 100644 web/src/lib/components/repo/issues/IssueStatePill.stories.svelte delete mode 100644 web/src/lib/components/repo/issues/IssueStatePill.svelte delete mode 100644 web/src/lib/components/repo/issues/IssueToolbar.stories.svelte delete mode 100644 web/src/lib/components/repo/issues/IssueToolbar.svelte delete mode 100644 web/src/lib/components/repo/pulls/PullCardContent.svelte delete mode 100644 web/src/lib/components/repo/pulls/PullList.stories.svelte delete mode 100644 web/src/lib/components/repo/pulls/PullList.svelte delete mode 100644 web/src/lib/components/repo/pulls/PullSearch.svelte delete mode 100644 web/src/lib/components/repo/pulls/PullStatePill.stories.svelte delete mode 100644 web/src/lib/components/repo/pulls/PullStatePill.svelte delete mode 100644 web/src/lib/components/repo/pulls/PullToolbar.stories.svelte rename web/src/lib/components/repo/{issues/IssueBody.stories.svelte => tickets/TicketBody.stories.svelte} (70%) create mode 100644 web/src/lib/components/repo/tickets/TicketCard.stories.svelte rename web/src/lib/components/repo/{pulls/PullCard.svelte => tickets/TicketCard.svelte} (61%) rename web/src/lib/components/repo/{issues/IssueCardContent.svelte => tickets/TicketCardContent.svelte} (51%) create mode 100644 web/src/lib/components/repo/tickets/TicketList.stories.svelte create mode 100644 web/src/lib/components/repo/tickets/TicketList.svelte create mode 100644 web/src/lib/components/repo/tickets/TicketSearch.stories.svelte rename web/src/lib/components/repo/{issues/IssueSearch.svelte => tickets/TicketSearch.svelte} (79%) create mode 100644 web/src/lib/components/repo/tickets/TicketToolbar.stories.svelte rename web/src/lib/components/repo/{pulls/PullToolbar.svelte => tickets/TicketToolbar.svelte} (62%) diff --git a/web/src/fixtures/pull.ts b/web/src/fixtures/pull.ts index ecf7ce017..42e831af3 100644 --- a/web/src/fixtures/pull.ts +++ b/web/src/fixtures/pull.ts @@ -1,5 +1,5 @@ // the fixture pull request the pull page stories share: ten commits over three -// versions, a five-file diff, and a fetch mock standing in for bobbin, the knot +// versions, a two-file diff, and a fetch mock standing in for bobbin, the knot // mirror and gitmirror, so a story can reach a rendered diff instead of an error. import type { CommentView } from "$lib/components/comment/comments"; import type { CommitSummary } from "$lib/api/repo"; @@ -190,39 +190,7 @@ export const createNotifications = () => { {/each} ` - }, - { - path: "src/routes/notifications/+page.server.ts", - row: 3, - old: `import type { PageServerLoad } from "./$types"; - -export const load: PageServerLoad = async ({ locals, url }) => { - const unreadOnly = url.searchParams.get("unread") === "1"; - return { notifications: await locals.deliberi.list({ unreadOnly }) }; -}; -` - }, - { - path: "src/lib/api/notifications.ts", - oldPath: "src/lib/api/notifs.ts", - row: 5, - old: `import { jsonGet } from "./_request"; - -const LIST_NSID = "org.tangled.notification.list"; - -export const listNotifications = (ctx: BobbinContext) => - jsonGet(ctx, LIST_NSID, {}); -`, - next: `import { jsonGet } from "./_request"; - -const LIST_NSID = "org.tangled.notification.list"; - -export const listNotifications = (ctx: BobbinContext, cursor?: string) => - jsonGet(ctx, LIST_NSID, { cursor, limit: 50 }); -` - }, - // both sides exist, so the card shows its name and a binary note instead of a diff - { path: "static/notification-bell.png", row: 4, old: "", next: "", binary: true } + } ]; const rowOf = (ref: string): number => { diff --git a/web/src/lib/components/notifications/notification.ts b/web/src/lib/components/notifications/notification.ts index 2ee90b031..57ceecdf0 100644 --- a/web/src/lib/components/notifications/notification.ts +++ b/web/src/lib/components/notifications/notification.ts @@ -67,7 +67,7 @@ const ICONS: Record = { }; // the design system has no purple, and a merged pull already reads as info on -// PullStatePill, so merges land on the same token here. +// TicketStatePill, so merges land on the same token here. const TONES: Record = { repo_starred: "text-foreground-warning", followed: "text-foreground-muted", diff --git a/web/src/lib/components/repo/issues/IssueBody.svelte b/web/src/lib/components/repo/issues/IssueBody.svelte deleted file mode 100644 index 5fd52ee1b..000000000 --- a/web/src/lib/components/repo/issues/IssueBody.svelte +++ /dev/null @@ -1,17 +0,0 @@ - - -{#if bodyHtml} - -
{@html bodyHtml}
-{:else if body} -
{body}
-{/if} diff --git a/web/src/lib/components/repo/issues/IssueCard.stories.svelte b/web/src/lib/components/repo/issues/IssueCard.stories.svelte deleted file mode 100644 index 2191e8631..000000000 --- a/web/src/lib/components/repo/issues/IssueCard.stories.svelte +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - diff --git a/web/src/lib/components/repo/issues/IssueCard.svelte b/web/src/lib/components/repo/issues/IssueCard.svelte deleted file mode 100644 index c6b571878..000000000 --- a/web/src/lib/components/repo/issues/IssueCard.svelte +++ /dev/null @@ -1,27 +0,0 @@ - - - - - diff --git a/web/src/lib/components/repo/issues/IssueHeader.stories.svelte b/web/src/lib/components/repo/issues/IssueHeader.stories.svelte deleted file mode 100644 index 071f376bc..000000000 --- a/web/src/lib/components/repo/issues/IssueHeader.stories.svelte +++ /dev/null @@ -1,26 +0,0 @@ - - - - diff --git a/web/src/lib/components/repo/issues/IssueHeader.svelte b/web/src/lib/components/repo/issues/IssueHeader.svelte deleted file mode 100644 index d934558b0..000000000 --- a/web/src/lib/components/repo/issues/IssueHeader.svelte +++ /dev/null @@ -1,16 +0,0 @@ - - -
-

- {title} - #{rkey} -

-
diff --git a/web/src/lib/components/repo/issues/IssueInfoBar.stories.svelte b/web/src/lib/components/repo/issues/IssueInfoBar.stories.svelte deleted file mode 100644 index dd66c199e..000000000 --- a/web/src/lib/components/repo/issues/IssueInfoBar.stories.svelte +++ /dev/null @@ -1,28 +0,0 @@ - - - - diff --git a/web/src/lib/components/repo/issues/IssueInfoBar.svelte b/web/src/lib/components/repo/issues/IssueInfoBar.svelte deleted file mode 100644 index 82ed0057b..000000000 --- a/web/src/lib/components/repo/issues/IssueInfoBar.svelte +++ /dev/null @@ -1,35 +0,0 @@ - - -
- - - - opened by - - - - - - - - {#if actions} -
- {@render actions()} -
- {/if} -
diff --git a/web/src/lib/components/repo/issues/IssueList.stories.svelte b/web/src/lib/components/repo/issues/IssueList.stories.svelte deleted file mode 100644 index e807c130c..000000000 --- a/web/src/lib/components/repo/issues/IssueList.stories.svelte +++ /dev/null @@ -1,41 +0,0 @@ - - - - diff --git a/web/src/lib/components/repo/issues/IssueList.svelte b/web/src/lib/components/repo/issues/IssueList.svelte deleted file mode 100644 index f74534225..000000000 --- a/web/src/lib/components/repo/issues/IssueList.svelte +++ /dev/null @@ -1,24 +0,0 @@ - - -{#if issues.length === 0} - -{:else} -
- {#each issues as issue (issue.rkey)} - - {/each} -
-{/if} diff --git a/web/src/lib/components/repo/issues/IssueSearch.stories.svelte b/web/src/lib/components/repo/issues/IssueSearch.stories.svelte deleted file mode 100644 index 14c31f9ab..000000000 --- a/web/src/lib/components/repo/issues/IssueSearch.stories.svelte +++ /dev/null @@ -1,17 +0,0 @@ - - - - -
- -
-
diff --git a/web/src/lib/components/repo/issues/IssueStatePill.stories.svelte b/web/src/lib/components/repo/issues/IssueStatePill.stories.svelte deleted file mode 100644 index c3360fb4f..000000000 --- a/web/src/lib/components/repo/issues/IssueStatePill.stories.svelte +++ /dev/null @@ -1,22 +0,0 @@ - - - - diff --git a/web/src/lib/components/repo/issues/IssueStatePill.svelte b/web/src/lib/components/repo/issues/IssueStatePill.svelte deleted file mode 100644 index 8241e8374..000000000 --- a/web/src/lib/components/repo/issues/IssueStatePill.svelte +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - diff --git a/web/src/lib/components/repo/issues/IssueThreadView.svelte b/web/src/lib/components/repo/issues/IssueThreadView.svelte index 2f76b9622..4e175b860 100644 --- a/web/src/lib/components/repo/issues/IssueThreadView.svelte +++ b/web/src/lib/components/repo/issues/IssueThreadView.svelte @@ -20,36 +20,26 @@ import { untrack } from "svelte"; import { goto } from "$app/navigation"; import { resolve } from "$app/paths"; - import Pencil from "$icon/pencil"; - import Trash2 from "$icon/trash-2"; - import Eye from "$icon/eye"; - import EyeOff from "$icon/eye-off"; - import { createAction } from "$lib/action.svelte"; + import BellMinus from "$icon/bell-minus"; + import BellPlus from "$icon/bell-plus"; import { createBobbinClient } from "$lib/api/client"; import { deleteSubscription, ensureEntitySubscription, getSubscriptionRkey } from "$lib/api/graph"; - import { deleteIssue, type IssueRecord } from "$lib/api/issue"; - import type { RecordView } from "$lib/api/records"; + import { deleteIssue, putIssue, type IssueRecord } from "$lib/api/issue"; import { getAuth } from "$lib/auth.svelte"; import { getNotifications } from "$lib/notifications.svelte"; import CommentBox from "$lib/components/comment/CommentBox.svelte"; import CommentList from "$lib/components/comment/CommentList.svelte"; import type { CommentThread, ThreadInput } from "$lib/components/comment/comments"; - import ReportItems from "$lib/components/moderation/ReportItems.svelte"; - import { createReporting } from "$lib/components/moderation/reporting.svelte"; - import MoreMenu from "$lib/components/ui/MoreMenu.svelte"; - import Reactions from "$lib/components/reaction/Reactions.svelte"; - import IssueBody from "$lib/components/repo/issues/IssueBody.svelte"; - import IssueForm from "$lib/components/repo/issues/IssueForm.svelte"; - import IssueHeader from "$lib/components/repo/issues/IssueHeader.svelte"; - import IssueInfoBar from "$lib/components/repo/issues/IssueInfoBar.svelte"; import IssueLabelPanel from "$lib/components/repo/issues/IssueLabelPanel.svelte"; + import Ticket from "$lib/components/repo/tickets/Ticket.svelte"; import type { RepoInfo } from "$lib/components/repo/types"; - import ErrorAlert from "$lib/components/ui/Error.svelte"; + import Button from "$lib/components/ui/Button.svelte"; import SignupPrompt from "$lib/components/ui/SignupPrompt.svelte"; + import Spinner from "$lib/components/ui/Spinner.svelte"; import TabPanel from "$lib/components/ui/TabPanel.svelte"; import { renderMarkup } from "$lib/markup"; import type { MarkupContext } from "$lib/markup/paths"; @@ -66,7 +56,6 @@ let props: Props = $props(); const auth = getAuth(); - const reporting = createReporting(); const notifications = getNotifications(); // local state for optimistic replies, re-synced when streamed props land @@ -77,8 +66,6 @@ comments = props.comments; }); - let editing = $state(false); - const entityUri = $derived(`at://${issue.authorDid}/sh.tangled.repo.issue/${issue.rkey}`); $effect(() => { @@ -87,6 +74,7 @@ let subscribed = $state(false); let subLoading = $state(true); + let subToggling = $state(false); let subRkey = $state(null); let subError = $state(null); @@ -123,8 +111,9 @@ const toggleSubscription = async () => { const agent = auth.agent; const did = auth.currentDid; - if (!agent || !did || !props.bobbinUrl) return; + if (!agent || !did || !props.bobbinUrl || subLoading || subToggling) return; subError = null; + subToggling = true; const ctx = createBobbinClient({ serviceUrl: props.bobbinUrl }); try { if (subscribed && subRkey) { @@ -137,10 +126,11 @@ } } catch { subError = "Failed to update subscription"; + } finally { + subToggling = false; } }; - const isAuthor = $derived(auth.hasAccount(issue.authorDid)); const issuesBase = $derived(`/${props.repo.ownerHandle}/${props.repo.name}/issues`); const insertComment = ({ comment, replyTo }: ThreadInput) => { @@ -178,23 +168,24 @@ .filter((thread) => thread !== null); }; - const handleSaved = async (saved: RecordView) => { - const { title, body = "" } = saved.value; + const updateIssue = async ({ title, body }: { title: string; body: string }) => { + const agent = await auth.agentFor(issue.authorDid as Did); + const record: IssueRecord = { + $type: "sh.tangled.repo.issue", + repo: (props.repo.repoDid ?? "") as IssueRecord["repo"], + title, + body, + createdAt: issue.createdAt + }; + await putIssue(agent, issue.rkey, record); const bodyHtml = body ? await renderMarkup(body, props.markup).catch(() => null) : null; issue = { ...issue, title, body, bodyHtml }; - editing = false; }; - const removeIssue = createAction(async () => { + const removeIssue = async () => { const agent = await auth.agentFor(issue.authorDid as Did); await deleteIssue(agent, issue.rkey); await goto(resolve(issuesBase as "/")); - }); - - const handleDelete = () => { - if (!auth.currentDid || removeIssue.loading) return; - if (!confirm("Delete this issue? This cannot be undone.")) return; - void removeIssue.run(); }; @@ -205,94 +196,51 @@ > -{#snippet issueActions()} - {#if auth.currentDid} - - {#if subError} - {subError} - {/if} - {/if} - - -{/snippet} -
- {#if editing} - (editing = false)} - /> - {:else} - - - -
- - {#if reporting.canReport(issue.authorDid)} - - - + + {#snippet extraActions()} + {#if auth.currentDid} + + {#if subError} + {subError} + {/if} {/if} -
- {#if removeIssue.error} -
- -
- {/if} - {/if} + {/snippet} +
diff --git a/web/src/lib/components/repo/issues/IssueToolbar.stories.svelte b/web/src/lib/components/repo/issues/IssueToolbar.stories.svelte deleted file mode 100644 index f34023798..000000000 --- a/web/src/lib/components/repo/issues/IssueToolbar.stories.svelte +++ /dev/null @@ -1,28 +0,0 @@ - - - - diff --git a/web/src/lib/components/repo/issues/IssueToolbar.svelte b/web/src/lib/components/repo/issues/IssueToolbar.svelte deleted file mode 100644 index 725bd4202..000000000 --- a/web/src/lib/components/repo/issues/IssueToolbar.svelte +++ /dev/null @@ -1,82 +0,0 @@ - - - -
-
- -
- - - - - - - - - -
- - -{#snippet pendingCount(value: number | Promise)} - - {#snippet skeleton()} - - {/snippet} - {formatCount(await value)} - -{/snippet} diff --git a/web/src/lib/components/repo/pulls/PullCardContent.svelte b/web/src/lib/components/repo/pulls/PullCardContent.svelte deleted file mode 100644 index 2c1770c9a..000000000 --- a/web/src/lib/components/repo/pulls/PullCardContent.svelte +++ /dev/null @@ -1,52 +0,0 @@ - - - - - diff --git a/web/src/lib/components/repo/pulls/PullList.stories.svelte b/web/src/lib/components/repo/pulls/PullList.stories.svelte deleted file mode 100644 index 350b29a99..000000000 --- a/web/src/lib/components/repo/pulls/PullList.stories.svelte +++ /dev/null @@ -1,27 +0,0 @@ - - - diff --git a/web/src/lib/components/repo/pulls/PullList.svelte b/web/src/lib/components/repo/pulls/PullList.svelte deleted file mode 100644 index 973ad5938..000000000 --- a/web/src/lib/components/repo/pulls/PullList.svelte +++ /dev/null @@ -1,24 +0,0 @@ - - -{#if pulls.length === 0} - -{:else} -
- {#each pulls as pull (pull.rkey)} - - {/each} -
-{/if} diff --git a/web/src/lib/components/repo/pulls/PullReviewCommentForm.stories.svelte b/web/src/lib/components/repo/pulls/PullReviewCommentForm.stories.svelte index 4f9b4e5dd..90cf3d1ae 100644 --- a/web/src/lib/components/repo/pulls/PullReviewCommentForm.stories.svelte +++ b/web/src/lib/components/repo/pulls/PullReviewCommentForm.stories.svelte @@ -3,7 +3,7 @@ import PullReviewCommentForm from "./PullReviewCommentForm.svelte"; const { Story } = defineMeta({ - title: "Pull/ReviewCommentForm", + title: "Repo/Pulls/PullReviewCommentForm", component: PullReviewCommentForm, tags: ["autodocs"], args: { diff --git a/web/src/lib/components/repo/pulls/PullSearch.svelte b/web/src/lib/components/repo/pulls/PullSearch.svelte deleted file mode 100644 index d320895f3..000000000 --- a/web/src/lib/components/repo/pulls/PullSearch.svelte +++ /dev/null @@ -1,42 +0,0 @@ - - -
- -
- - {#if value} -
-
diff --git a/web/src/lib/components/repo/pulls/PullStatePill.stories.svelte b/web/src/lib/components/repo/pulls/PullStatePill.stories.svelte deleted file mode 100644 index 126a2caff..000000000 --- a/web/src/lib/components/repo/pulls/PullStatePill.stories.svelte +++ /dev/null @@ -1,23 +0,0 @@ - - - - - diff --git a/web/src/lib/components/repo/pulls/PullStatePill.svelte b/web/src/lib/components/repo/pulls/PullStatePill.svelte deleted file mode 100644 index 03609a605..000000000 --- a/web/src/lib/components/repo/pulls/PullStatePill.svelte +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - diff --git a/web/src/lib/components/repo/pulls/PullToolbar.stories.svelte b/web/src/lib/components/repo/pulls/PullToolbar.stories.svelte deleted file mode 100644 index 790bff593..000000000 --- a/web/src/lib/components/repo/pulls/PullToolbar.stories.svelte +++ /dev/null @@ -1,19 +0,0 @@ - - - diff --git a/web/src/lib/components/repo/tickets/Ticket.svelte b/web/src/lib/components/repo/tickets/Ticket.svelte index d04f3a2a8..aaa789ca1 100644 --- a/web/src/lib/components/repo/tickets/Ticket.svelte +++ b/web/src/lib/components/repo/tickets/Ticket.svelte @@ -16,6 +16,7 @@ import type { Snippet } from "svelte"; import Reactions from "$lib/components/reaction/Reactions.svelte"; import Separator from "$lib/components/ui/Separator.svelte"; + import type { ReactionGroup } from "$lib/components/reaction/reactions"; interface Props { // ticketView @@ -36,6 +37,8 @@ targetBranch?: string; }; markup: MarkupContext; + reactions?: ReactionGroup[]; + reactionsAlwaysShow?: boolean; onedit?: (input: { title: string; body: string; targetBranch?: string }) => Promise; ondelete?: () => Promise; // rendered after the built-in edit/delete pair, for actions that are not acl-gated @@ -43,7 +46,16 @@ extraInfo?: Snippet; } - let { ticket, markup, onedit, ondelete, extraActions, extraInfo }: Props = $props(); + let { + ticket, + markup, + reactions = [], + reactionsAlwaysShow = false, + onedit, + ondelete, + extraActions, + extraInfo + }: Props = $props(); const auth = getAuth(); const reporting = createReporting(); @@ -82,15 +94,18 @@
{#if isAuthor && onedit} - + {/if} {#if isAuthor && ondelete} {/if} @@ -114,7 +129,7 @@
- + {#if reporting.canReport(ticket.author.did)} import { defineMeta } from "@storybook/addon-svelte-csf"; - import IssueBody from "./IssueBody.svelte"; + import TicketBody from "./TicketBody.svelte"; - // normally produced by $lib/markup (sanitised); inlined here for the story const sampleHtml = `

I'd like a /trending view that shows more than the five repositories currently listed in the timeline sidebar.

  • discover active projects
  • understand what's happening
curl https://tangled.org/trending
`; const { Story } = defineMeta({ - title: "Repo/Issues/IssueBody", - component: IssueBody, + title: "Repo/Tickets/TicketBody", + component: TicketBody, tags: ["autodocs"], argTypes: { body: { control: "text" }, @@ -22,14 +21,11 @@ }); - - - diff --git a/web/src/lib/components/repo/tickets/TicketCard.stories.svelte b/web/src/lib/components/repo/tickets/TicketCard.stories.svelte new file mode 100644 index 000000000..c28463f4b --- /dev/null +++ b/web/src/lib/components/repo/tickets/TicketCard.stories.svelte @@ -0,0 +1,46 @@ + + + + + + + + + diff --git a/web/src/lib/components/repo/pulls/PullCard.svelte b/web/src/lib/components/repo/tickets/TicketCard.svelte similarity index 61% rename from web/src/lib/components/repo/pulls/PullCard.svelte rename to web/src/lib/components/repo/tickets/TicketCard.svelte index f155ce2f2..0ab2ace33 100644 --- a/web/src/lib/components/repo/pulls/PullCard.svelte +++ b/web/src/lib/components/repo/tickets/TicketCard.svelte @@ -1,12 +1,13 @@ - + diff --git a/web/src/lib/components/repo/issues/IssueCardContent.svelte b/web/src/lib/components/repo/tickets/TicketCardContent.svelte similarity index 51% rename from web/src/lib/components/repo/issues/IssueCardContent.svelte rename to web/src/lib/components/repo/tickets/TicketCardContent.svelte index 1454272a2..4d5418b0e 100644 --- a/web/src/lib/components/repo/issues/IssueCardContent.svelte +++ b/web/src/lib/components/repo/tickets/TicketCardContent.svelte @@ -4,49 +4,51 @@ import User from "$lib/components/ui/User.svelte"; import ProfilePopover from "$lib/components/profile/ProfilePopover.svelte"; import TimeAgo from "$lib/components/ui/TimeAgo.svelte"; - import IssueStatePill from "./IssueStatePill.svelte"; - import type { IssueSummary } from "$lib/components/repo/types"; + import TicketStatePill from "./TicketStatePill.svelte"; + import type { IssueSummary, PullSummary } from "$lib/components/repo/types"; import Separator from "$lib/components/ui/Separator.svelte"; import { formatCount } from "$lib/format"; interface Props { ownerHandle: string; repoName: string; - issue: IssueSummary; + ticket: IssueSummary | PullSummary; + isPull?: boolean; } - let { ownerHandle, repoName, issue }: Props = $props(); + let { ownerHandle, repoName, ticket, isPull = false }: Props = $props(); - // the at-uri is appended after `resolve`, which would drop the empty segment in `at://` const href = $derived( - `${resolve(`/${ownerHandle}/${repoName}/issues` as "/")}/${issue.uri}` as ResolvedPathname + isPull + ? (`${resolve(`/${ownerHandle}/${repoName}/pulls` as "/")}/${ticket.uri}/latest` as ResolvedPathname) + : (`${resolve(`/${ownerHandle}/${repoName}/issues` as "/")}/${ticket.uri}` as ResolvedPathname) ); diff --git a/web/src/lib/components/repo/tickets/TicketInfoBar.svelte b/web/src/lib/components/repo/tickets/TicketInfoBar.svelte index 07493315f..6b38334ce 100644 --- a/web/src/lib/components/repo/tickets/TicketInfoBar.svelte +++ b/web/src/lib/components/repo/tickets/TicketInfoBar.svelte @@ -4,6 +4,7 @@ import User from "$lib/components/ui/User.svelte"; import TimeAgo from "$lib/components/ui/TimeAgo.svelte"; import Tag from "$lib/components/ui/Tag.svelte"; + import Separator from "$lib/components/ui/Separator.svelte"; interface Props { isPull?: boolean; @@ -34,9 +35,8 @@ - - - + + {#if targetBranch} diff --git a/web/src/lib/components/repo/tickets/TicketList.stories.svelte b/web/src/lib/components/repo/tickets/TicketList.stories.svelte new file mode 100644 index 000000000..86cc5ef0d --- /dev/null +++ b/web/src/lib/components/repo/tickets/TicketList.stories.svelte @@ -0,0 +1,57 @@ + + + + + diff --git a/web/src/lib/components/repo/tickets/TicketList.svelte b/web/src/lib/components/repo/tickets/TicketList.svelte new file mode 100644 index 000000000..126cdd657 --- /dev/null +++ b/web/src/lib/components/repo/tickets/TicketList.svelte @@ -0,0 +1,31 @@ + + +{#if tickets.length === 0} + +{:else} +
+ {#each tickets as ticket (ticket.rkey)} + + {/each} +
+{/if} diff --git a/web/src/lib/components/repo/tickets/TicketSearch.stories.svelte b/web/src/lib/components/repo/tickets/TicketSearch.stories.svelte new file mode 100644 index 000000000..e032e2422 --- /dev/null +++ b/web/src/lib/components/repo/tickets/TicketSearch.stories.svelte @@ -0,0 +1,25 @@ + + + +
+ +
+
+ + +
+ +
+
diff --git a/web/src/lib/components/repo/issues/IssueSearch.svelte b/web/src/lib/components/repo/tickets/TicketSearch.svelte similarity index 79% rename from web/src/lib/components/repo/issues/IssueSearch.svelte rename to web/src/lib/components/repo/tickets/TicketSearch.svelte index fd70e5749..4f42b3a2d 100644 --- a/web/src/lib/components/repo/issues/IssueSearch.svelte +++ b/web/src/lib/components/repo/tickets/TicketSearch.svelte @@ -5,8 +5,15 @@ import Button from "$lib/components/ui/Button.svelte"; import Input from "$lib/components/ui/Input.svelte"; + interface Props { + isPull?: boolean; + } + + let { isPull = false }: Props = $props(); + + const label = $derived(isPull ? "Search pull requests" : "Search issues"); + let form: HTMLFormElement; - // seed from the url so the query (and the clear button) survive a submit let value = $state(page.url.searchParams.get("q") ?? ""); const clear = () => { @@ -16,14 +23,13 @@
-
diff --git a/web/src/lib/components/repo/tickets/TicketToolbar.stories.svelte b/web/src/lib/components/repo/tickets/TicketToolbar.stories.svelte new file mode 100644 index 000000000..002ac7a3f --- /dev/null +++ b/web/src/lib/components/repo/tickets/TicketToolbar.stories.svelte @@ -0,0 +1,41 @@ + + + + + + + diff --git a/web/src/lib/components/repo/pulls/PullToolbar.svelte b/web/src/lib/components/repo/tickets/TicketToolbar.svelte similarity index 62% rename from web/src/lib/components/repo/pulls/PullToolbar.svelte rename to web/src/lib/components/repo/tickets/TicketToolbar.svelte index 995abbf26..4c9ddfdfd 100644 --- a/web/src/lib/components/repo/pulls/PullToolbar.svelte +++ b/web/src/lib/components/repo/tickets/TicketToolbar.svelte @@ -1,38 +1,45 @@ -
- +
@@ -40,29 +47,31 @@ href={resolve(`${base}?state=open` as "/")} {...segmentProps(state === "open")} size="small" - icon={GitPullRequest} + icon={isPull ? GitPullRequest : CircleDot} > Open - + {#if isPull} + + {/if}
- {#snippet pendingCount(value: number | Promise)} {#snippet skeleton()} - + {/snippet} {formatCount(await value)} diff --git a/web/src/lib/components/timeline/types.ts b/web/src/lib/components/timeline/types.ts index 639461a65..a53b18feb 100644 --- a/web/src/lib/components/timeline/types.ts +++ b/web/src/lib/components/timeline/types.ts @@ -1,6 +1,6 @@ // view models for the timeline rail, mirroring the appview's recents rows. -import type { PullState } from "$lib/components/repo/pulls/PullStatePill.svelte"; +import type { PullState } from "$lib/components/repo/types"; interface RecentBase { /** when the viewer last opened the page */ diff --git a/web/src/routes/[handle]/[repo]/issues/+page.svelte b/web/src/routes/[handle]/[repo]/issues/+page.svelte index bbec211c8..044b48784 100644 --- a/web/src/routes/[handle]/[repo]/issues/+page.svelte +++ b/web/src/routes/[handle]/[repo]/issues/+page.svelte @@ -1,10 +1,10 @@