Browse Source

feat: add recent proposals component

this adapts ensureProposalSummaries so that it works with no repo filter
master
DanConwayDev 2 years ago
parent
commit
b7883063e2
No known key found for this signature in database
GPG Key ID: 68E15486D73F75E1
  1. 19
      src/lib/components/proposals/ProposalsList.svelte
  2. 17
      src/lib/components/proposals/ProposalsListItem.svelte
  3. 6
      src/lib/components/proposals/type.ts
  4. 2
      src/lib/stores/Proposal.ts
  5. 56
      src/lib/stores/Proposals.ts
  6. 20
      src/lib/wrappers/RecentProposals.svelte

19
src/lib/components/proposals/ProposalsList.svelte

@ -5,6 +5,10 @@
export let title: string = '' export let title: string = ''
export let proposals: ProposalSummary[] = [] export let proposals: ProposalSummary[] = []
export let loading: boolean = false export let loading: boolean = false
export let show_repo: boolean = false
export let limit: number = 0
export let allow_more = true
let current_limit = limit
</script> </script>
<div class=""> <div class="">
@ -16,9 +20,11 @@
{#if proposals.length == 0 && !loading} {#if proposals.length == 0 && !loading}
<p class="prose">None</p> <p class="prose">None</p>
{/if} {/if}
<ul class=" divide-y divide-neutral-600"> <ul class=" divide-y divide-base-400">
{#each proposals as proposal} {#each proposals as proposal, index}
<ProposalsListItem {...proposal} /> {#if current_limit === 0 || index + 1 <= current_limit}
<ProposalsListItem {...proposal} {show_repo} />
{/if}
{/each} {/each}
{#if loading} {#if loading}
<ProposalsListItem loading={true} /> <ProposalsListItem loading={true} />
@ -26,6 +32,13 @@
<ProposalsListItem loading={true} /> <ProposalsListItem loading={true} />
<ProposalsListItem loading={true} /> <ProposalsListItem loading={true} />
{/if} {/if}
{:else if allow_more && proposals.length > current_limit}
<button
on:click={() => {
current_limit = current_limit + 5
}}
class="btn mt-3 p-3 font-normal">more</button
>
{/if} {/if}
</ul> </ul>
</div> </div>

17
src/lib/components/proposals/ProposalsListItem.svelte

@ -19,7 +19,7 @@
title, title,
descritpion, descritpion,
id, id,
repo_id, repo_identifier,
comments, comments,
status, status,
status_date, status_date,
@ -27,6 +27,7 @@
created_at, created_at,
loading, loading,
} = summary_defaults } = summary_defaults
export let show_repo: boolean = false
let short_title: string let short_title: string
let created_at_ago: string let created_at_ago: string
$: { $: {
@ -37,9 +38,7 @@
} }
</script> </script>
<li <li class="flex p-2 pt-4 {!loading ? 'cursor-pointer hover:bg-base-200' : ''}">
class="flex p-2 pt-4 {!loading ? 'cursor-pointer hover:bg-neutral-700' : ''}"
>
<!-- <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 || !status} {#if loading || !status}
@ -74,7 +73,7 @@
> >
{/if} {/if}
<a <a
href="/repo/{repo_id}/proposal/{id}" href="/repo/{repo_identifier}/proposal/{id}"
class="ml-3 grow overflow-hidden text-xs text-neutral-content" class="ml-3 grow overflow-hidden text-xs text-neutral-content"
class:pointer-events-none={loading} class:pointer-events-none={loading}
> >
@ -83,6 +82,7 @@
<div class="skeleton mb-1 mt-3 h-3 w-40 flex-none"></div> <div class="skeleton mb-1 mt-3 h-3 w-40 flex-none"></div>
{:else} {:else}
<div class="text-sm text-base-content"> <div class="text-sm text-base-content">
{show_repo ? repo_identifier : ''}
{short_title} {short_title}
</div> </div>
<!-- <div class="text-xs text-neutral-content"> <!-- <div class="text-xs text-neutral-content">
@ -109,6 +109,13 @@
<li class="inline"> <li class="inline">
<UserHeader user={author} inline={true} size="xs" /> <UserHeader user={author} inline={true} size="xs" />
</li> </li>
{#if show_repo && repo_identifier.length > 0}
<li class="ml-3 inline">
<a class="link-primary z-10" href="/repo/{repo_identifier}">
{repo_identifier}
</a>
</li>
{/if}
</ul> </ul>
{/if} {/if}
</a> </a>

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

@ -6,7 +6,7 @@ import type { NDKEvent } from '@nostr-dev-kit/ndk'
export interface ProposalSummary { export interface ProposalSummary {
title: string title: string
descritpion: string descritpion: string
repo_id: string repo_identifier: string
id: string id: string
comments: number comments: number
status: undefined | number status: undefined | number
@ -19,7 +19,7 @@ export interface ProposalSummary {
export const summary_defaults: ProposalSummary = { export const summary_defaults: ProposalSummary = {
title: '', title: '',
descritpion: '', descritpion: '',
repo_id: '', repo_identifier: '',
id: '', id: '',
comments: 0, comments: 0,
status: undefined, status: undefined,
@ -30,7 +30,7 @@ export const summary_defaults: ProposalSummary = {
} }
export interface ProposalSummaries { export interface ProposalSummaries {
id: string id: string | undefined
summaries: ProposalSummary[] summaries: ProposalSummary[]
loading: boolean loading: boolean
} }

2
src/lib/stores/Proposal.ts

@ -51,7 +51,7 @@ export const ensureProposalFull = (repo_id: string, proposal_id: string) => {
summary: { summary: {
...full_defaults.summary, ...full_defaults.summary,
id: proposal_id, id: proposal_id,
repo_id: repo_id, repo_identifier: repo_id,
loading: true, loading: true,
}, },
loading: true, loading: true,

56
src/lib/stores/Proposals.ts

@ -17,7 +17,6 @@ import {
proposal_status_open, proposal_status_open,
repo_kind, repo_kind,
} from '$lib/kinds' } from '$lib/kinds'
import type { RepoEvent } from '$lib/components/repo/type'
import { extractPatchMessage } from '$lib/components/events/content/utils' import { extractPatchMessage } from '$lib/components/events/content/utils'
import { selectRepoFromCollection } from '$lib/components/repo/utils' import { selectRepoFromCollection } from '$lib/components/repo/utils'
@ -27,13 +26,13 @@ export const proposal_summaries: Writable<ProposalSummaries> = writable({
loading: false, loading: false,
}) })
let selected_repo_id: string = '' let selected_repo_id: string | undefined = ''
let authors_unsubscribers: Unsubscriber[] = [] let authors_unsubscribers: Unsubscriber[] = []
let sub: NDKSubscription let sub: NDKSubscription
export const ensureProposalSummaries = async (repo_id: string) => { export const ensureProposalSummaries = async (repo_id: string | undefined) => {
if (selected_repo_id == repo_id) return if (selected_repo_id == repo_id) return
proposal_summaries.set({ proposal_summaries.set({
id: repo_id, id: repo_id,
@ -57,37 +56,50 @@ export const ensureProposalSummaries = async (repo_id: string) => {
}) })
}, 6000) }, 6000)
let relays_to_use = [...base_relays]
let filter: NDKFilter = {
kinds: [patch_kind],
limit: 50,
}
if (repo_id) {
const repo_collection = await awaitSelectedRepoCollection(repo_id) const repo_collection = await awaitSelectedRepoCollection(repo_id)
const repo = selectRepoFromCollection(repo_collection) const repo = selectRepoFromCollection(repo_collection)
if (!repo) { if (!repo) {
// TODO: display error info bar
return return
} }
const relays_to_use = relays_to_use =
repo.relays.length > 3 ? repo.relays : [...base_relays].concat(repo.relays) repo.relays.length > 3
? repo.relays
: [...base_relays].concat(repo.relays)
const without_root_tag = !repo.unique_commit const without_root_tag = !repo.unique_commit
const filter_with_root: NDKFilter = { if (without_root_tag) {
filter = {
kinds: [patch_kind], kinds: [patch_kind],
'#a': repo.maintainers.map( '#a': repo.maintainers.map(
(m) => `${repo_kind}:${m.hexpubkey}:${repo.identifier}` (m) => `${repo_kind}:${m.hexpubkey}:${repo.identifier}`
), ),
'#t': ['root'],
limit: 50, limit: 50,
} }
} else {
const filter_without_root: NDKFilter = { filter = {
kinds: [patch_kind], kinds: [patch_kind],
'#a': repo.maintainers.map( '#a': repo.maintainers.map(
(m) => `${repo_kind}:${m.hexpubkey}:${repo.identifier}` (m) => `${repo_kind}:${m.hexpubkey}:${repo.identifier}`
), ),
'#t': ['root'],
limit: 50, limit: 50,
} }
}
}
sub = ndk.subscribe( sub = ndk.subscribe(
[without_root_tag ? filter_without_root : filter_with_root], filter,
{ {
closeOnEose: true, closeOnEose: true,
}, },
@ -109,7 +121,8 @@ export const ensureProposalSummaries = async (repo_id: string) => {
{ {
...summary_defaults, ...summary_defaults,
id: event.id, id: event.id,
repo_id: repo_id, repo_identifier:
extractRepoIdentiferFromProposalEvent(event) || repo_id || '',
title: ( title: (
event.tagValue('name') || event.tagValue('name') ||
event.tagValue('description') || event.tagValue('description') ||
@ -126,7 +139,7 @@ export const ensureProposalSummaries = async (repo_id: string) => {
}, },
loading: false, loading: false,
}, },
], ].sort((a, b) => (b.created_at || 0) - (a.created_at || 0)),
} }
}) })
} }
@ -148,7 +161,7 @@ export const ensureProposalSummaries = async (repo_id: string) => {
}) })
sub.on('eose', () => { sub.on('eose', () => {
proposal_summaries.update((proposals) => { proposal_summaries.update((proposals) => {
getAndUpdateProposalStatus(proposals, repo) getAndUpdateProposalStatus(proposals, relays_to_use)
return { return {
...proposals, ...proposals,
loading: false, loading: false,
@ -161,11 +174,8 @@ let sub_statuses: NDKSubscription
function getAndUpdateProposalStatus( function getAndUpdateProposalStatus(
proposals: ProposalSummaries, proposals: ProposalSummaries,
repo: RepoEvent relays: string[]
): void { ): void {
const relays_to_use =
repo.relays.length > 3 ? repo.relays : [...base_relays].concat(repo.relays)
if (sub_statuses) sub_statuses.stop() if (sub_statuses) sub_statuses.stop()
sub_statuses = ndk.subscribe( sub_statuses = ndk.subscribe(
{ {
@ -175,7 +185,7 @@ function getAndUpdateProposalStatus(
{ {
closeOnEose: true, closeOnEose: true,
}, },
NDKRelaySet.fromRelayUrls(relays_to_use, ndk) NDKRelaySet.fromRelayUrls(relays, ndk)
) )
sub_statuses.on('event', (event: NDKEvent) => { sub_statuses.on('event', (event: NDKEvent) => {
const tagged_proposal_event = event.tagValue('e') const tagged_proposal_event = event.tagValue('e')
@ -220,3 +230,13 @@ function getAndUpdateProposalStatus(
}) })
}) })
} }
export const extractRepoIdentiferFromProposalEvent = (
event: NDKEvent
): string | undefined => {
const value = event.tagValue('a')
if (!value) return undefined
const split = value.split(':')
if (split.length < 3) return undefined
return split[2]
}

20
src/lib/wrappers/RecentProposals.svelte

@ -0,0 +1,20 @@
<script lang="ts">
import ProposalsList from '$lib/components/proposals/ProposalsList.svelte'
import {
ensureProposalSummaries,
proposal_summaries,
} from '$lib/stores/Proposals'
ensureProposalSummaries(undefined)
let limit = 6
let allow_more = true
</script>
<ProposalsList
title="Recent Proposals"
proposals={$proposal_summaries.summaries}
show_repo={true}
loading={$proposal_summaries.loading}
{limit}
{allow_more}
/>
Loading…
Cancel
Save