Browse Source

fix: update pr status accross app

- move status from PRFull into PRSummary
- fetch statuses when fetching pr summaries
- ensure status gets displayed accurately across the app
master
DanConwayDev 2 years ago
parent
commit
fd73f0952b
No known key found for this signature in database
GPG Key ID: 68E15486D73F75E1
  1. BIN
      __snapshots__/prs-list-item--status-closed.png
  2. BIN
      __snapshots__/prs-list-item--status-draft.png
  3. BIN
      __snapshots__/prs-list-item--status-loading.png
  4. BIN
      __snapshots__/prs-list-item--status-merged.png
  5. 143
      __snapshots__/prs-list-item.test.js.snap
  6. 4
      __snapshots__/prs-status.test.js.snap
  7. 4
      src/lib/components/prs/PRDetails.svelte
  8. 16
      src/lib/components/prs/PRHeader.svelte
  9. 8
      src/lib/components/prs/PRsListItem.stories.svelte
  10. 54
      src/lib/components/prs/PRsListItem.svelte
  11. 22
      src/lib/components/prs/Status.svelte
  12. 13
      src/lib/components/prs/StatusSelector.svelte
  13. 6
      src/lib/components/prs/icons.ts
  14. 6
      src/lib/components/prs/type.ts
  15. 36
      src/lib/components/prs/vectors.ts
  16. 13
      src/lib/stores/PR.ts
  17. 71
      src/lib/stores/PRs.ts
  18. 1
      src/routes/repo/[repo_id]/pr/[pr_id]/+page.svelte

BIN
__snapshots__/prs-list-item--status-closed.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
__snapshots__/prs-list-item--status-draft.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
__snapshots__/prs-list-item--status-loading.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
__snapshots__/prs-list-item--status-merged.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

143
__snapshots__/prs-list-item.test.js.snap

@ -139,6 +139,149 @@ exports[`PRs/List/Item Short Details smoke-test 1`] = `
</li> </li>
`; `;
exports[`PRs/List/Item Status Closed smoke-test 1`] = `
<li class="flex p-2 pt-4 hover:bg-neutral-700 cursor-pointer">
<svg xmlns="http://www.w3.org/2000/svg"
viewbox="0 0 16 16"
class="h-5 w-5 pt-1 flex-none fill-neutral-content"
>
<path d="M3.25 1A2.25 2.25 0 0 1 4 5.372v5.256a2.251 2.251 0 1 1-1.5 0V5.372A2.251 2.251 0 0 1 3.25 1m9.5 5.5a.75.75 0 0 1 .75.75v3.378a2.251 2.251 0 1 1-1.5 0V7.25a.75.75 0 0 1 .75-.75m-2.03-5.273a.75.75 0 0 1 1.06 0l.97.97l.97-.97a.748.748 0 0 1 1.265.332a.75.75 0 0 1-.205.729l-.97.97l.97.97a.751.751 0 0 1-.018 1.042a.751.751 0 0 1-1.042.018l-.97-.97l-.97.97a.749.749 0 0 1-1.275-.326a.749.749 0 0 1 .215-.734l.97-.97l-.97-.97a.75.75 0 0 1 0-1.06ZM2.5 3.25a.75.75 0 1 0 1.5 0a.75.75 0 0 0-1.5 0M3.25 12a.75.75 0 1 0 0 1.5a.75.75 0 0 0 0-1.5m9.5 0a.75.75 0 1 0 0 1.5a.75.75 0 0 0 0-1.5">
</path>
</svg>
<a href="/repo//pr/"
class="ml-3 overflow-hidden grow text-xs text-neutral-content"
>
<div class="text-sm text-base-content">
short title
</div>
<ul class="pt-2">
<li class="align-middle inline mr-3">
<svg xmlns="http://www.w3.org/2000/svg"
class="h-3 w-3 pt-0 flex-none fill-base-content inline-block"
viewbox="0 0 16 16"
>
<path d="M1 2.75C1 1.784 1.784 1 2.75 1h10.5c.966 0 1.75.784 1.75 1.75v7.5A1.75 1.75 0 0 1 13.25 12H9.06l-2.573 2.573A1.458 1.458 0 0 1 4 13.543V12H2.75A1.75 1.75 0 0 1 1 10.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h2a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h4.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z">
</path>
</svg>
2
</li>
<li class="inline mr-3">
opened 7 days ago
</li>
<li class="inline">
DanConwayDev
</li>
</ul>
</a>
</li>
`;
exports[`PRs/List/Item Status Draft smoke-test 1`] = `
<li class="flex p-2 pt-4 hover:bg-neutral-700 cursor-pointer">
<svg xmlns="http://www.w3.org/2000/svg"
viewbox="0 0 16 16"
class="h-5 w-5 pt-1 flex-none fill-neutral-content"
>
<path d="M3.25 1A2.25 2.25 0 0 1 4 5.372v5.256a2.251 2.251 0 1 1-1.5 0V5.372A2.251 2.251 0 0 1 3.25 1m9.5 14a2.25 2.25 0 1 1 0-4.5a2.25 2.25 0 0 1 0 4.5M2.5 3.25a.75.75 0 1 0 1.5 0a.75.75 0 0 0-1.5 0M3.25 12a.75.75 0 1 0 0 1.5a.75.75 0 0 0 0-1.5m9.5 0a.75.75 0 1 0 0 1.5a.75.75 0 0 0 0-1.5M14 7.5a1.25 1.25 0 1 1-2.5 0a1.25 1.25 0 0 1 2.5 0m0-4.25a1.25 1.25 0 1 1-2.5 0a1.25 1.25 0 0 1 2.5 0">
</path>
</svg>
<a href="/repo//pr/"
class="ml-3 overflow-hidden grow text-xs text-neutral-content"
>
<div class="text-sm text-base-content">
short title
</div>
<ul class="pt-2">
<li class="align-middle inline mr-3">
<svg xmlns="http://www.w3.org/2000/svg"
class="h-3 w-3 pt-0 flex-none fill-base-content inline-block"
viewbox="0 0 16 16"
>
<path d="M1 2.75C1 1.784 1.784 1 2.75 1h10.5c.966 0 1.75.784 1.75 1.75v7.5A1.75 1.75 0 0 1 13.25 12H9.06l-2.573 2.573A1.458 1.458 0 0 1 4 13.543V12H2.75A1.75 1.75 0 0 1 1 10.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h2a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h4.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z">
</path>
</svg>
2
</li>
<li class="inline mr-3">
opened 7 days ago
</li>
<li class="inline">
DanConwayDev
</li>
</ul>
</a>
</li>
`;
exports[`PRs/List/Item Status Loading smoke-test 1`] = `
<li class="flex p-2 pt-4 hover:bg-neutral-700 cursor-pointer">
<div class="h-5 w-5 pt-1 flex-none skeleton">
</div>
<a href="/repo//pr/"
class="ml-3 overflow-hidden grow text-xs text-neutral-content"
>
<div class="text-sm text-base-content">
short title
</div>
<ul class="pt-2">
<li class="align-middle inline mr-3">
<svg xmlns="http://www.w3.org/2000/svg"
class="h-3 w-3 pt-0 flex-none fill-base-content inline-block"
viewbox="0 0 16 16"
>
<path d="M1 2.75C1 1.784 1.784 1 2.75 1h10.5c.966 0 1.75.784 1.75 1.75v7.5A1.75 1.75 0 0 1 13.25 12H9.06l-2.573 2.573A1.458 1.458 0 0 1 4 13.543V12H2.75A1.75 1.75 0 0 1 1 10.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h2a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h4.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z">
</path>
</svg>
2
</li>
<li class="inline mr-3">
opened 7 days ago
</li>
<li class="inline">
DanConwayDev
</li>
</ul>
</a>
</li>
`;
exports[`PRs/List/Item Status Merged smoke-test 1`] = `
<li class="flex p-2 pt-4 hover:bg-neutral-700 cursor-pointer">
<svg xmlns="http://www.w3.org/2000/svg"
viewbox="0 0 16 16"
class="h-5 w-5 pt-1 flex-none fill-primary"
>
<path d="M5.45 5.154A4.25 4.25 0 0 0 9.25 7.5h1.378a2.251 2.251 0 1 1 0 1.5H9.25A5.734 5.734 0 0 1 5 7.123v3.505a2.25 2.25 0 1 1-1.5 0V5.372a2.25 2.25 0 1 1 1.95-.218M4.25 13.5a.75.75 0 1 0 0-1.5a.75.75 0 0 0 0 1.5m8.5-4.5a.75.75 0 1 0 0-1.5a.75.75 0 0 0 0 1.5M5 3.25a.75.75 0 1 0 0 .005z">
</path>
</svg>
<a href="/repo//pr/"
class="ml-3 overflow-hidden grow text-xs text-neutral-content"
>
<div class="text-sm text-base-content">
short title
</div>
<ul class="pt-2">
<li class="align-middle inline mr-3">
<svg xmlns="http://www.w3.org/2000/svg"
class="h-3 w-3 pt-0 flex-none fill-base-content inline-block"
viewbox="0 0 16 16"
>
<path d="M1 2.75C1 1.784 1.784 1 2.75 1h10.5c.966 0 1.75.784 1.75 1.75v7.5A1.75 1.75 0 0 1 13.25 12H9.06l-2.573 2.573A1.458 1.458 0 0 1 4 13.543V12H2.75A1.75 1.75 0 0 1 1 10.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h2a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h4.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z">
</path>
</svg>
2
</li>
<li class="inline mr-3">
opened 7 days ago
</li>
<li class="inline">
DanConwayDev
</li>
</ul>
</a>
</li>
`;
exports[`PRs/List/Item loading smoke-test 1`] = ` exports[`PRs/List/Item loading smoke-test 1`] = `
<li class="flex p-2 pt-4 "> <li class="flex p-2 pt-4 ">
<div class="h-5 w-5 pt-1 flex-none skeleton"> <div class="h-5 w-5 pt-1 flex-none skeleton">

4
__snapshots__/prs-status.test.js.snap

@ -33,7 +33,7 @@ exports[`PRs/Status Draft smoke-test 1`] = `
`; `;
exports[`PRs/Status Loading smoke-test 1`] = ` exports[`PRs/Status Loading smoke-test 1`] = `
<div class="skeleton w-28 h-8 rounded-md"> <div class="skeleton w-24 h-8 rounded-md inline-block align-middle">
</div> </div>
`; `;
@ -68,7 +68,7 @@ exports[`PRs/Status Open Edit Mode smoke-test 1`] = `
Open Open
<svg xmlns="http://www.w3.org/2000/svg" <svg xmlns="http://www.w3.org/2000/svg"
viewbox="0 0 24 24" viewbox="0 0 24 24"
class="h-5 w-5s flex-none fill-success-content" class="h-5 w-5 flex-none fill-success-content"
> >
<path fill="currentColor" <path fill="currentColor"
d="M11.646 15.146L5.854 9.354a.5.5 0 0 1 .353-.854h11.586a.5.5 0 0 1 .353.854l-5.793 5.792a.5.5 0 0 1-.707 0" d="M11.646 15.146L5.854 9.354a.5.5 0 0 1 .353-.854h11.586a.5.5 0 0 1 .353.854l-5.793 5.792a.5.5 0 0 1-.707 0"

4
src/lib/components/prs/PRDetails.svelte

@ -3,7 +3,7 @@
import UserHeader from "../users/UserHeader.svelte"; import UserHeader from "../users/UserHeader.svelte";
import StatusSelector from "./StatusSelector.svelte"; import StatusSelector from "./StatusSelector.svelte";
export let { summary, status, labels, loading } = { ...full_defaults }; export let { summary, labels, loading } = { ...full_defaults };
</script> </script>
<div class="max-w-md"> <div class="max-w-md">
@ -26,7 +26,7 @@
{:else} {:else}
<h4>Status</h4> <h4>Status</h4>
<StatusSelector <StatusSelector
{status} status={summary.status}
repo_id={summary.repo_id} repo_id={summary.repo_id}
pr_id={summary.id} pr_id={summary.id}
/> />

16
src/lib/components/prs/PRHeader.svelte

@ -10,8 +10,18 @@
import Status from "./Status.svelte"; import Status from "./Status.svelte";
dayjs.extend(relativeTime); dayjs.extend(relativeTime);
export let { title, id, repo_id, comments, author, created_at, loading } = export let {
summary_defaults; title,
descritpion,
id,
repo_id,
comments,
status,
status_date,
author,
created_at,
loading,
} = summary_defaults;
let short_title: string; let short_title: string;
let created_at_ago: string; let created_at_ago: string;
let author_name = ""; let author_name = "";
@ -51,7 +61,7 @@
</div> </div>
<div class="pt-1"> <div class="pt-1">
<div class="inline mr-3 align-middle"> <div class="inline mr-3 align-middle">
<Status status="Open" /> <Status {status} />
</div> </div>
<div class="inline mr-3 align-middle"> <div class="inline mr-3 align-middle">
opened {created_at_ago} opened {created_at_ago}

8
src/lib/components/prs/PRsListItem.stories.svelte

@ -23,4 +23,12 @@
<Story name="Author Loading" args={vectors.AuthorLoading} /> <Story name="Author Loading" args={vectors.AuthorLoading} />
<Story name="Status Loading" args={vectors.StatusLoading} />
<Story name="Status Draft" args={vectors.StatusDraft} />
<Story name="Status Closed" args={vectors.StatusClosed} />
<Story name="Status Merged" args={vectors.StatusMerged} />
<Story name="loading" args={{ loading: true }} /> <Story name="loading" args={{ loading: true }} />

54
src/lib/components/prs/PRsListItem.svelte

@ -6,10 +6,19 @@
import relativeTime from "dayjs/plugin/relativeTime"; import relativeTime from "dayjs/plugin/relativeTime";
import { summary_defaults } from "./type"; import { summary_defaults } from "./type";
import { getName } from "../users/type"; import { getName } from "../users/type";
import { pr_icon_path } from "./icons";
dayjs.extend(relativeTime); dayjs.extend(relativeTime);
export let { title, id, repo_id, comments, author, created_at, loading } = export let {
summary_defaults; title,
id,
repo_id,
comments,
status,
author,
created_at,
loading,
} = summary_defaults;
let short_title: string; let short_title: string;
let created_at_ago: string; let created_at_ago: string;
let author_name = ""; let author_name = "";
@ -31,28 +40,37 @@
> >
<!-- <figure class="p-4 pl-0 text-color-primary"> --> <!-- <figure class="p-4 pl-0 text-color-primary"> -->
<!-- http://icon-sets.iconify.design/octicon/git-pull-request-16/ --> <!-- http://icon-sets.iconify.design/octicon/git-pull-request-16/ -->
{#if loading} {#if loading || !status}
<div class="h-5 w-5 pt-1 flex-none skeleton"></div> <div class="h-5 w-5 pt-1 flex-none skeleton"></div>
{:else} {:else if status === "Open"}
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16" viewBox="0 0 16 16"
class="h-5 w-5 pt-1 flex-none fill-success" class="h-5 w-5 pt-1 flex-none fill-success"
><path ><path d={pr_icon_path.open} /></svg
d="M1.5 3.25a2.25 2.25 0 1 1 3 2.122v5.256a2.251 2.251 0 1 1-1.5 0V5.372A2.25 2.25 0 0 1 1.5 3.25m5.677-.177L9.573.677A.25.25 0 0 1 10 .854V2.5h1A2.5 2.5 0 0 1 13.5 5v5.628a2.251 2.251 0 1 1-1.5 0V5a1 1 0 0 0-1-1h-1v1.646a.25.25 0 0 1-.427.177L7.177 3.427a.25.25 0 0 1 0-.354M3.75 2.5a.75.75 0 1 0 0 1.5a.75.75 0 0 0 0-1.5m0 9.5a.75.75 0 1 0 0 1.5a.75.75 0 0 0 0-1.5m8.25.75a.75.75 0 1 0 1.5 0a.75.75 0 0 0-1.5 0" >
/> {:else if status === "Closed"}
</svg> <svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
class="h-5 w-5 pt-1 flex-none fill-neutral-content"
><path d={pr_icon_path.close} /></svg
>
{:else if status === "Draft"}
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
class="h-5 w-5 pt-1 flex-none fill-neutral-content"
><path d={pr_icon_path.draft} /></svg
>
{:else if status === "Merged"}
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
class="h-5 w-5 pt-1 flex-none fill-primary"
><path d={pr_icon_path.merge} /></svg
>
{/if} {/if}
<!-- <svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 16 16"
class="fill-base-content"
><path
d="M3.25 1A2.25 2.25 0 0 1 4 5.372v5.256a2.251 2.251 0 1 1-1.5 0V5.372A2.251 2.251 0 0 1 3.25 1m9.5 14a2.25 2.25 0 1 1 0-4.5a2.25 2.25 0 0 1 0 4.5M2.5 3.25a.75.75 0 1 0 1.5 0a.75.75 0 0 0-1.5 0M3.25 12a.75.75 0 1 0 0 1.5a.75.75 0 0 0 0-1.5m9.5 0a.75.75 0 1 0 0 1.5a.75.75 0 0 0 0-1.5M14 7.5a1.25 1.25 0 1 1-2.5 0a1.25 1.25 0 0 1 2.5 0m0-4.25a1.25 1.25 0 1 1-2.5 0a1.25 1.25 0 0 1 2.5 0"
/></svg
> -->
<a <a
href="/repo/{repo_id}/pr/{id}" href="/repo/{repo_id}/pr/{id}"
class="ml-3 overflow-hidden grow text-xs text-neutral-content" class="ml-3 overflow-hidden grow text-xs text-neutral-content"

22
src/lib/components/prs/Status.svelte

@ -1,10 +1,12 @@
<script lang="ts"> <script lang="ts">
import { pr_icon_path } from "./icons";
export let status: string | undefined = undefined; export let status: string | undefined = undefined;
export let edit_mode = false; export let edit_mode = false;
</script> </script>
{#if !status} {#if !status}
<div class="skeleton w-28 h-8 rounded-md"></div> <div class="skeleton w-24 h-8 rounded-md inline-block align-middle"></div>
{:else} {:else}
<div <div
tabIndex={0} tabIndex={0}
@ -21,9 +23,7 @@
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 18 18" viewBox="0 0 18 18"
class="h-5 w-5 pt-1 flex-none fill-success-content" class="h-5 w-5 pt-1 flex-none fill-success-content"
><path ><path d={pr_icon_path.open} />
d="M1.5 3.25a2.25 2.25 0 1 1 3 2.122v5.256a2.251 2.251 0 1 1-1.5 0V5.372A2.25 2.25 0 0 1 1.5 3.25m5.677-.177L9.573.677A.25.25 0 0 1 10 .854V2.5h1A2.5 2.5 0 0 1 13.5 5v5.628a2.251 2.251 0 1 1-1.5 0V5a1 1 0 0 0-1-1h-1v1.646a.25.25 0 0 1-.427.177L7.177 3.427a.25.25 0 0 1 0-.354M3.75 2.5a.75.75 0 1 0 0 1.5a.75.75 0 0 0 0-1.5m0 9.5a.75.75 0 1 0 0 1.5a.75.75 0 0 0 0-1.5m8.25.75a.75.75 0 1 0 1.5 0a.75.75 0 0 0-1.5 0"
/>
</svg> </svg>
Open Open
{:else if status === "Merged"} {:else if status === "Merged"}
@ -32,9 +32,7 @@
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16" viewBox="0 0 16 16"
class="h-5 w-5 pt-1 flex-none fill-primary-content" class="h-5 w-5 pt-1 flex-none fill-primary-content"
><path ><path d={pr_icon_path.merge} /></svg
d="M5.45 5.154A4.25 4.25 0 0 0 9.25 7.5h1.378a2.251 2.251 0 1 1 0 1.5H9.25A5.734 5.734 0 0 1 5 7.123v3.505a2.25 2.25 0 1 1-1.5 0V5.372a2.25 2.25 0 1 1 1.95-.218M4.25 13.5a.75.75 0 1 0 0-1.5a.75.75 0 0 0 0 1.5m8.5-4.5a.75.75 0 1 0 0-1.5a.75.75 0 0 0 0 1.5M5 3.25a.75.75 0 1 0 0 .005z"
/></svg
> >
Merged Merged
{:else if status === "Closed"} {:else if status === "Closed"}
@ -43,9 +41,7 @@
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16" viewBox="0 0 16 16"
class="h-5 w-5 pt-1 flex-none fill-neutral-content" class="h-5 w-5 pt-1 flex-none fill-neutral-content"
><path ><path d={pr_icon_path.close} /></svg
d="M3.25 1A2.25 2.25 0 0 1 4 5.372v5.256a2.251 2.251 0 1 1-1.5 0V5.372A2.251 2.251 0 0 1 3.25 1m9.5 5.5a.75.75 0 0 1 .75.75v3.378a2.251 2.251 0 1 1-1.5 0V7.25a.75.75 0 0 1 .75-.75m-2.03-5.273a.75.75 0 0 1 1.06 0l.97.97l.97-.97a.748.748 0 0 1 1.265.332a.75.75 0 0 1-.205.729l-.97.97l.97.97a.751.751 0 0 1-.018 1.042a.751.751 0 0 1-1.042.018l-.97-.97l-.97.97a.749.749 0 0 1-1.275-.326a.749.749 0 0 1 .215-.734l.97-.97l-.97-.97a.75.75 0 0 1 0-1.06ZM2.5 3.25a.75.75 0 1 0 1.5 0a.75.75 0 0 0-1.5 0M3.25 12a.75.75 0 1 0 0 1.5a.75.75 0 0 0 0-1.5m9.5 0a.75.75 0 1 0 0 1.5a.75.75 0 0 0 0-1.5"
/></svg
> >
Closed Closed
{:else if status === "Draft"} {:else if status === "Draft"}
@ -54,9 +50,7 @@
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16" viewBox="0 0 16 16"
class="h-5 w-5 pt-1 flex-none fill-neutral-content" class="h-5 w-5 pt-1 flex-none fill-neutral-content"
><path ><path d={pr_icon_path.draft} /></svg
d="M3.25 1A2.25 2.25 0 0 1 4 5.372v5.256a2.251 2.251 0 1 1-1.5 0V5.372A2.251 2.251 0 0 1 3.25 1m9.5 14a2.25 2.25 0 1 1 0-4.5a2.25 2.25 0 0 1 0 4.5M2.5 3.25a.75.75 0 1 0 1.5 0a.75.75 0 0 0-1.5 0M3.25 12a.75.75 0 1 0 0 1.5a.75.75 0 0 0 0-1.5m9.5 0a.75.75 0 1 0 0 1.5a.75.75 0 0 0 0-1.5M14 7.5a1.25 1.25 0 1 1-2.5 0a1.25 1.25 0 0 1 2.5 0m0-4.25a1.25 1.25 0 1 1-2.5 0a1.25 1.25 0 0 1 2.5 0"
/></svg
> >
Draft Draft
{:else} {:else}
@ -66,7 +60,7 @@
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24" viewBox="0 0 24 24"
class="h-5 w-5s flex-none fill-success-content" class="h-5 w-5 flex-none fill-success-content"
><path ><path
fill="currentColor" fill="currentColor"
d="M11.646 15.146L5.854 9.354a.5.5 0 0 1 .353-.854h11.586a.5.5 0 0 1 .353.854l-5.793 5.792a.5.5 0 0 1-.707 0" d="M11.646 15.146L5.854 9.354a.5.5 0 0 1 .353-.854h11.586a.5.5 0 0 1 .353.854l-5.793 5.792a.5.5 0 0 1-.707 0"

13
src/lib/components/prs/StatusSelector.svelte

@ -2,13 +2,13 @@
import { ndk } from "$lib/stores/ndk"; import { ndk } from "$lib/stores/ndk";
import { NDKEvent, NDKRelaySet, type NDKTag } from "@nostr-dev-kit/ndk"; import { NDKEvent, NDKRelaySet, type NDKTag } from "@nostr-dev-kit/ndk";
import type { PRStatus } from "./type"; import type { PRStatus } from "./type";
import { selected_pr_full } from "$lib/stores/PR"; import { selected_pr_full, selected_pr_replies } from "$lib/stores/PR";
import { pr_status_kind } from "$lib/kinds"; import { pr_status_kind } from "$lib/kinds";
import { getUserRelays, logged_in_user } from "$lib/stores/users"; import { getUserRelays, logged_in_user } from "$lib/stores/users";
import { selected_repo } from "$lib/stores/repo"; import { selected_repo } from "$lib/stores/repo";
import Status from "$lib/components/prs/Status.svelte"; import Status from "$lib/components/prs/Status.svelte";
export let status: PRStatus = "Draft"; export let status: PRStatus | undefined = undefined;
export let repo_id: string = ""; export let repo_id: string = "";
export let pr_id: string = ""; export let pr_id: string = "";
@ -54,15 +54,20 @@
if (pr_full.summary.id !== pr_id) return pr_full; if (pr_full.summary.id !== pr_id) return pr_full;
return { return {
...pr_full, ...pr_full,
status: new_status, summary: {
...pr_full.summary,
status: new_status,
status_date: event.created_at || 0,
},
}; };
}); });
selected_pr_replies.update((responses) => [...responses, event]);
loading = false; loading = false;
} catch {} } catch {}
} }
</script> </script>
{#if loading} {#if loading || !status}
<Status /> <Status />
{:else} {:else}
<div class="dropdown"> <div class="dropdown">

6
src/lib/components/prs/icons.ts

@ -0,0 +1,6 @@
export let pr_icon_path = {
open: "M1.5 3.25a2.25 2.25 0 1 1 3 2.122v5.256a2.251 2.251 0 1 1-1.5 0V5.372A2.25 2.25 0 0 1 1.5 3.25m5.677-.177L9.573.677A.25.25 0 0 1 10 .854V2.5h1A2.5 2.5 0 0 1 13.5 5v5.628a2.251 2.251 0 1 1-1.5 0V5a1 1 0 0 0-1-1h-1v1.646a.25.25 0 0 1-.427.177L7.177 3.427a.25.25 0 0 1 0-.354M3.75 2.5a.75.75 0 1 0 0 1.5a.75.75 0 0 0 0-1.5m0 9.5a.75.75 0 1 0 0 1.5a.75.75 0 0 0 0-1.5m8.25.75a.75.75 0 1 0 1.5 0a.75.75 0 0 0-1.5 0",
close: "M3.25 1A2.25 2.25 0 0 1 4 5.372v5.256a2.251 2.251 0 1 1-1.5 0V5.372A2.251 2.251 0 0 1 3.25 1m9.5 5.5a.75.75 0 0 1 .75.75v3.378a2.251 2.251 0 1 1-1.5 0V7.25a.75.75 0 0 1 .75-.75m-2.03-5.273a.75.75 0 0 1 1.06 0l.97.97l.97-.97a.748.748 0 0 1 1.265.332a.75.75 0 0 1-.205.729l-.97.97l.97.97a.751.751 0 0 1-.018 1.042a.751.751 0 0 1-1.042.018l-.97-.97l-.97.97a.749.749 0 0 1-1.275-.326a.749.749 0 0 1 .215-.734l.97-.97l-.97-.97a.75.75 0 0 1 0-1.06ZM2.5 3.25a.75.75 0 1 0 1.5 0a.75.75 0 0 0-1.5 0M3.25 12a.75.75 0 1 0 0 1.5a.75.75 0 0 0 0-1.5m9.5 0a.75.75 0 1 0 0 1.5a.75.75 0 0 0 0-1.5",
draft: "M3.25 1A2.25 2.25 0 0 1 4 5.372v5.256a2.251 2.251 0 1 1-1.5 0V5.372A2.251 2.251 0 0 1 3.25 1m9.5 14a2.25 2.25 0 1 1 0-4.5a2.25 2.25 0 0 1 0 4.5M2.5 3.25a.75.75 0 1 0 1.5 0a.75.75 0 0 0-1.5 0M3.25 12a.75.75 0 1 0 0 1.5a.75.75 0 0 0 0-1.5m9.5 0a.75.75 0 1 0 0 1.5a.75.75 0 0 0 0-1.5M14 7.5a1.25 1.25 0 1 1-2.5 0a1.25 1.25 0 0 1 2.5 0m0-4.25a1.25 1.25 0 1 1-2.5 0a1.25 1.25 0 0 1 2.5 0",
merge: "M5.45 5.154A4.25 4.25 0 0 0 9.25 7.5h1.378a2.251 2.251 0 1 1 0 1.5H9.25A5.734 5.734 0 0 1 5 7.123v3.505a2.25 2.25 0 1 1-1.5 0V5.372a2.25 2.25 0 1 1 1.95-.218M4.25 13.5a.75.75 0 1 0 0-1.5a.75.75 0 0 0 0 1.5m8.5-4.5a.75.75 0 1 0 0-1.5a.75.75 0 0 0 0 1.5M5 3.25a.75.75 0 1 0 0 .005z",
};

6
src/lib/components/prs/type.ts

@ -9,6 +9,8 @@ export interface PRSummary {
repo_id: string; repo_id: string;
id: string; id: string;
comments: number; comments: number;
status: undefined | PRStatus,
status_date: number,
author: User; author: User;
created_at: number | undefined; created_at: number | undefined;
loading: boolean; loading: boolean;
@ -20,6 +22,8 @@ export const summary_defaults: PRSummary = {
repo_id: "", repo_id: "",
id: "", id: "",
comments: 0, comments: 0,
status: undefined,
status_date: 0,
author: { ...user_defaults }, author: { ...user_defaults },
created_at: 0, created_at: 0,
loading: true, loading: true,
@ -51,7 +55,6 @@ export function isPRStatus(potential_status: string | undefined): potential_stat
export interface PRFull { export interface PRFull {
summary: PRSummary; summary: PRSummary;
pr_event: NDKEvent | undefined; pr_event: NDKEvent | undefined;
status: PRStatus;
labels: string[]; labels: string[];
events: Event[]; events: Event[];
loading: boolean; loading: boolean;
@ -60,7 +63,6 @@ export interface PRFull {
export const full_defaults: PRFull = { export const full_defaults: PRFull = {
summary: { ...summary_defaults }, summary: { ...summary_defaults },
pr_event: undefined, pr_event: undefined,
status: "Open",
labels: [], labels: [],
events: [], events: [],
loading: true, loading: true,

36
src/lib/components/prs/vectors.ts

@ -5,19 +5,23 @@ import { UserVectors } from "../users/vectors";
dayjs.extend(relativeTime); dayjs.extend(relativeTime);
let Short = {
title: "short title",
author: { ...UserVectors.default },
created_at: dayjs().subtract(7, 'days').unix(),
comments: 2,
status: "Open",
loading: false,
} as PRSummary;
export let PRsListItemArgsVectors = { export let PRsListItemArgsVectors = {
Short: { Short,
title: "short title",
author: { ...UserVectors.default },
created_at: dayjs().subtract(7, 'days').unix(),
comments: 2,
loading: false,
} as PRSummary,
Long: { Long: {
title: "rather long title that goes on and on and on and on and on and on and on and on and on and on and on and on and on and on and on", title: "rather long title that goes on and on and on and on and on and on and on and on and on and on and on and on and on and on and on",
author: { ...UserVectors.default }, author: { ...UserVectors.default },
created_at: dayjs().subtract(1, 'minute').unix(), created_at: dayjs().subtract(1, 'minute').unix(),
comments: 0, comments: 0,
status: "Open",
loading: false, loading: false,
} as PRSummary, } as PRSummary,
LongNoSpaces: { LongNoSpaces: {
@ -25,6 +29,7 @@ export let PRsListItemArgsVectors = {
author: { ...UserVectors.default }, author: { ...UserVectors.default },
created_at: dayjs().subtract(3, 'month').subtract(3, 'days').unix(), created_at: dayjs().subtract(3, 'month').subtract(3, 'days').unix(),
comments: 1, comments: 1,
status: "Open",
loading: false, loading: false,
} as PRSummary, } as PRSummary,
AuthorLoading: { AuthorLoading: {
@ -32,6 +37,23 @@ export let PRsListItemArgsVectors = {
author: { ...UserVectors.loading }, author: { ...UserVectors.loading },
created_at: dayjs().subtract(3, 'month').subtract(3, 'days').unix(), created_at: dayjs().subtract(3, 'month').subtract(3, 'days').unix(),
comments: 1, comments: 1,
status: "Open",
loading: false, loading: false,
} as PRSummary, } as PRSummary,
StatusLoading: {
...Short,
status: undefined,
} as PRSummary,
StatusDraft: {
...Short,
status: "Draft",
} as PRSummary,
StatusClosed: {
...Short,
status: "Closed",
} as PRSummary,
StatusMerged: {
...Short,
status: "Merged",
} as PRSummary,
}; };

13
src/lib/stores/PR.ts

@ -145,7 +145,12 @@ export let ensurePRFull = (repo_id: string, pr_id: string) => {
selected_pr_full.update(full => { selected_pr_full.update(full => {
return { return {
...full, ...full,
status: potential_status as PRStatus, summary: {
...full.summary,
status: potential_status as PRStatus,
// this wont be 0 as we are ensuring it is not undefined above
status_date: event.created_at || 0,
},
}; };
}); });
} }
@ -158,10 +163,14 @@ export let ensurePRFull = (repo_id: string, pr_id: string) => {
}); });
}); });
sub.on("eose", () => { sub_replies.on("eose", () => {
selected_pr_full.update(full => { selected_pr_full.update(full => {
let updated = { let updated = {
...full, ...full,
summary: {
...full.summary,
status: full.summary.status || "Open",
},
loading: false, loading: false,
}; };
if (full.summary.loading === false) { if (full.summary.loading === false) {

71
src/lib/stores/PRs.ts

@ -1,11 +1,13 @@
import { NDKRelaySet, type NDKEvent, NDKSubscription } from "@nostr-dev-kit/ndk"; import { NDKRelaySet, type NDKEvent, NDKSubscription } from "@nostr-dev-kit/ndk";
import { writable, type Unsubscriber, type Writable } from "svelte/store" import { writable, type Unsubscriber, type Writable } from "svelte/store"
import { ndk } from "./ndk"; import { ndk } from "./ndk";
import { summary_defaults } from "$lib/components/prs/type"; import { isPRStatus, summary_defaults } from "$lib/components/prs/type";
import type { User } from "$lib/components/users/type"; import type { User } from "$lib/components/users/type";
import { ensureUser } from "./users"; import { ensureUser } from "./users";
import type { PRSummaries } from "$lib/components/prs/type"; import type { PRStatus, PRSummaries } from "$lib/components/prs/type";
import { ensureSelectedRepo } from "./repo"; import { ensureSelectedRepo } from "./repo";
import { pr_status_kind } from "$lib/kinds";
import type { Repo } from "$lib/components/repo/type";
export let pr_summaries: Writable<PRSummaries> = writable({ export let pr_summaries: Writable<PRSummaries> = writable({
id: "", id: "",
@ -104,6 +106,7 @@ export let ensurePRSummaries = async (repo_id: string) => {
}); });
sub.on("eose", () => { sub.on("eose", () => {
pr_summaries.update(prs => { pr_summaries.update(prs => {
getAndUpdatePRStatus(prs, repo);
return { return {
...prs, ...prs,
loading: false, loading: false,
@ -111,3 +114,67 @@ export let ensurePRSummaries = async (repo_id: string) => {
}); });
}); });
} }
let sub_statuses: NDKSubscription;
function getAndUpdatePRStatus(prs: PRSummaries, repo: Repo): void {
if (sub_statuses) sub_statuses.stop();
sub_statuses = ndk.subscribe(
{
kinds: [pr_status_kind],
"#e": prs.summaries.map(pr => pr.id),
'#r': [`r-${prs.id}`],
},
{
closeOnEose: false,
},
NDKRelaySet.fromRelayUrls(repo.relays, ndk),
);
sub_statuses.on("event", (event: NDKEvent) => {
let tagged_pr_event = event.tagValue('e');
if (event.kind == pr_status_kind
&& tagged_pr_event
&& event.created_at
&& event.getMatchingTags("t").length === 1
&& event.getMatchingTags("t")[0].length > 1
) {
let potential_status = event.getMatchingTags("t")[0][1];
if (isPRStatus(potential_status)) {
pr_summaries.update(prs => {
return {
...prs,
summaries: prs.summaries.map(o => {
if (
o.id === tagged_pr_event
&& event.created_at
&& o.status_date < event.created_at
) {
return {
...o,
status: potential_status as PRStatus,
status_date: event.created_at,
}
}
return o;
}),
}
});
}
}
});
sub_statuses.on("eose", () => {
pr_summaries.update(prs => {
return {
...prs,
summaries: prs.summaries.map(o => ({
...o,
status: o.status || "Open",
})),
}
});
});
}

1
src/routes/repo/[repo_id]/pr/[pr_id]/+page.svelte

@ -75,7 +75,6 @@
<div class="w-1/3 ml-2 prose hidden md:flex"> <div class="w-1/3 ml-2 prose hidden md:flex">
<PrDetails <PrDetails
summary={$selected_pr_full.summary} summary={$selected_pr_full.summary}
status={$selected_pr_full.status}
labels={$selected_pr_full.labels} labels={$selected_pr_full.labels}
loading={$selected_pr_full.loading} loading={$selected_pr_full.loading}
/> />

Loading…
Cancel
Save