Browse Source

feat: improve and turn on readme display

for github only. added notes for enabling displaying readme for
other git servers in the future
master
DanConwayDev 2 years ago
parent
commit
61c3259148
No known key found for this signature in database
GPG Key ID: 68E15486D73F75E1
  1. 18
      src/lib/components/repo/utils.spec.ts
  2. 18
      src/lib/components/repo/utils.ts
  3. 44
      src/lib/stores/repo.ts
  4. 3
      src/lib/wrappers/RepoMenu.svelte
  5. 28
      src/routes/git_proxy/readme/[clone]/+server.ts
  6. 59
      src/routes/repo/[repo_id]/+page.svelte
  7. 39
      src/routes/repo/[repo_id]/proposals/+page.svelte
  8. 5
      src/routes/repo/[repo_id]/proposals/+page.ts

18
src/lib/components/repo/utils.spec.ts

@ -1,5 +1,5 @@
import { describe, expect, test } from 'vitest' import { describe, expect, test } from 'vitest'
import { selectRepoFromCollection } from './utils' import { extractGithubDetails, selectRepoFromCollection } from './utils'
import { import {
collection_defaults, collection_defaults,
event_defaults, event_defaults,
@ -159,3 +159,19 @@ describe('getSelectedRepo', () => {
}) })
}) })
}) })
describe('extractGithubDetails', () => {
;[
'https://github.com/orgname/reponame.git',
'https://github.com/orgname/reponame',
'git@github.com:orgname/reponame',
].forEach((clone) => {
describe(clone, () => {
test('returns correct org and repo', () => {
const res = extractGithubDetails(clone)
expect(res?.org).toEqual('orgname')
expect(res?.repo_name).toEqual('reponame')
})
})
})
})

18
src/lib/components/repo/utils.ts

@ -15,3 +15,21 @@ export const selectRepoFromCollection = (
return b_ref - a_ref return b_ref - a_ref
})[0] })[0]
} }
export const extractGithubDetails = (
clone: string
): { org: string; repo_name: string } | undefined => {
if (clone.indexOf('github.') > -1) {
const g_split = clone.split('github.')
if (g_split.length > 0) {
const final = g_split[1].replace(':', '/').split('/')
if (final.length > 2) {
return {
org: final[1],
repo_name: final[2].split('.')[0],
}
}
}
}
return undefined
}

44
src/lib/stores/repo.ts

@ -10,7 +10,10 @@ import {
readme_defaults, readme_defaults,
} from '$lib/components/repo/type' } from '$lib/components/repo/type'
import { ensureRepoCollection } from './repos' import { ensureRepoCollection } from './repos'
import { selectRepoFromCollection } from '$lib/components/repo/utils' import {
extractGithubDetails,
selectRepoFromCollection,
} from '$lib/components/repo/utils'
import { get } from 'svelte/store' import { get } from 'svelte/store'
export const selected_repo_collection: Writable<RepoCollection> = writable({ export const selected_repo_collection: Writable<RepoCollection> = writable({
@ -103,41 +106,28 @@ const ensureRepoReadme = async (
} }
try { try {
const github_details = extractGithubDetails(clone) const github_details = extractGithubDetails(clone)
// feature stapled off let res: Response
const feature_staple = false if (github_details) {
if (github_details && feature_staple) { try {
const res = await fetch( res = await fetch(
// `/git_proxy/readme?clone=${encodeURIComponent(clone)}`
`https://raw.githubusercontent.com/${github_details.org}/${github_details.repo_name}/HEAD/README.md` `https://raw.githubusercontent.com/${github_details.org}/${github_details.repo_name}/HEAD/README.md`
) )
if (!res.ok) { if (!res.ok) {
throw 'api request error' throw 'api request error'
} }
} catch {
res = await fetch(
`https://raw.githubusercontent.com/${github_details.org}/${github_details.repo_name}/HEAD/readme.md`
)
}
} else res = await fetch(`/git_proxy/readme/${encodeURIComponent(clone)}`)
if (!res.ok) {
throw 'api request error'
}
let text = '' let text = ''
text = await res.text() text = await res.text()
update(text) update(text)
} else {
// use proxy to get readme using 'git archive' or 'git clone'
}
} catch (e) { } catch (e) {
update() update()
} }
} }
const extractGithubDetails = (
clone: string
): { org: string; repo_name: string } | undefined => {
if (clone.indexOf('github.') > -1) {
const g_split = clone.split('github.')
if (g_split.length > 0) {
const slash_split = g_split[1].split('/')
if (slash_split.length > 2) {
return {
org: slash_split[1],
repo_name: slash_split[2].split('.')[0],
}
}
}
}
return undefined
}

3
src/lib/wrappers/RepoMenu.svelte

@ -1,6 +1,7 @@
<script lang="ts"> <script lang="ts">
import { issue_summaries } from '$lib/stores/Issues' import { issue_summaries } from '$lib/stores/Issues'
import { proposal_summaries } from '$lib/stores/Proposals' import { proposal_summaries } from '$lib/stores/Proposals'
import { selected_repo_readme } from '$lib/stores/repo'
export let selected_tab: '' | 'proposals' | 'issues' = '' export let selected_tab: '' | 'proposals' | 'issues' = ''
export let identifier = '' export let identifier = ''
@ -8,6 +9,7 @@
<div class="flex border-b border-base-400"> <div class="flex border-b border-base-400">
<div role="tablist" class="tabs tabs-bordered flex-none"> <div role="tablist" class="tabs tabs-bordered flex-none">
{#if !$selected_repo_readme.failed}
<a <a
href={`/repo/${identifier}`} href={`/repo/${identifier}`}
class="tab" class="tab"
@ -15,6 +17,7 @@
> >
Code Code
</a> </a>
{/if}
<a <a
href={`/repo/${identifier}/proposals`} href={`/repo/${identifier}/proposals`}
class="tab" class="tab"

28
src/routes/git_proxy/readme/[clone]/+server.ts

@ -0,0 +1,28 @@
import { extractGithubDetails } from '$lib/components/repo/utils'
export const GET = async ({ params }: { params: { clone: string } }) => {
const github_details = extractGithubDetails(decodeURIComponent(params.clone))
if (github_details) {
const res = await fetch(
`https://raw.githubusercontent.com/${github_details.org}/${github_details.repo_name}/HEAD/README.md`
)
const text = await res.text()
return new Response(text)
} else {
// options:
// * add support for different git server implementations that serve raw
// files and cycle through the urls until we find the readme
// * add a worker that can use 'git archive' to get specific files
// * unfortunately the two options that can easily embeded within this
// sveltekit backend (wasm-git and isomorphicgit) don't support the
// 'archive' command
// https://github.com/petersalomonsen/wasm-git/
// https://github.com/isomorphic-git
// * 'git clone' is too expensive for retrieving single files. even when
// done using treeless or blobless flags. see:
// https://noise.getoto.net/2020/12/21/get-up-to-speed-with-partial-clone-and-shallow-clone/
return new Response(null)
}
}

59
src/routes/repo/[repo_id]/+page.svelte

@ -1,39 +1,42 @@
<script lang="ts"> <script lang="ts">
import ProposalsList from '$lib/components/proposals/ProposalsList.svelte' import { selected_repo_readme } from '$lib/stores/repo'
import { proposal_summaries } from '$lib/stores/Proposals' import SvelteMarkdown from 'svelte-markdown'
import RepoPageWrapper from '$lib/wrappers/RepoPageWrapper.svelte' import RepoPageWrapper from '$lib/wrappers/RepoPageWrapper.svelte'
import { goto } from '$app/navigation'
export let data: { repo_id: string } export let data: { repo_id: string }
let identifier = data.repo_id let identifier = data.repo_id
let selected_tab: '' | 'issues' | 'proposals' = ''
$: {
if ($selected_repo_readme.failed === true)
goto(`/repo/${identifier}/proposals`)
}
</script> </script>
<RepoPageWrapper {identifier} selected_tab="proposals"> <RepoPageWrapper {identifier} {selected_tab}>
<ProposalsList <div class="my-3 rounded-lg border border-base-400">
proposals_or_issues={$proposal_summaries.summaries} <div class="border-b border-base-400 bg-base-300 px-6 py-3">
loading={$proposal_summaries.loading} <h4 class="">README.md</h4>
</div>
<div class="p-6">
{#if $selected_repo_readme.loading}
<div class="skeleton my-3 h-5 w-20"></div>
<div class="skeleton my-2 h-4"></div>
<div class="skeleton my-2 mb-3 h-4 w-2/3"></div>
<div class="skeleton my-3 h-5 w-20"></div>
<div class="skeleton my-2 h-4"></div>
<div class="skeleton my-2 mb-3 h-4 w-2/3"></div>
{:else if $selected_repo_readme.failed}
<div>failed to load readme from git server...</div>
{:else}
<article class="prose prose-sm">
<SvelteMarkdown
options={{ gfm: true }}
source={$selected_repo_readme.md}
/> />
<div role="alert" class="alert mt-6"> </article>
<svg {/if}
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
class="h-6 w-6 shrink-0 stroke-info"
><path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
></path></svg
>
<div>
<h3 class="prose mb-2 text-sm font-bold">want to submit a proposal?</h3>
<p class="prose text-xs">
<a href="/ngit">install ngit</a>, create add a feature in the local
repository and run
<span class="rounded bg-neutral p-1 font-mono"
><span class="py-3">ngit send</span></span
>
</p>
</div> </div>
</div> </div>
</RepoPageWrapper> </RepoPageWrapper>

39
src/routes/repo/[repo_id]/proposals/+page.svelte

@ -0,0 +1,39 @@
<script lang="ts">
import ProposalsList from '$lib/components/proposals/ProposalsList.svelte'
import { proposal_summaries } from '$lib/stores/Proposals'
import RepoPageWrapper from '$lib/wrappers/RepoPageWrapper.svelte'
export let data: { repo_id: string }
let identifier = data.repo_id
</script>
<RepoPageWrapper {identifier} selected_tab="proposals">
<ProposalsList
proposals_or_issues={$proposal_summaries.summaries}
loading={$proposal_summaries.loading}
/>
<div role="alert" class="alert mt-6">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
class="h-6 w-6 shrink-0 stroke-info"
><path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
></path></svg
>
<div>
<h3 class="prose mb-2 text-sm font-bold">want to submit a proposal?</h3>
<p class="prose text-xs">
<a href="/ngit">install ngit</a>, create add a feature in the local
repository and run
<span class="rounded bg-neutral p-1 font-mono"
><span class="py-3">ngit send</span></span
>
</p>
</div>
</div>
</RepoPageWrapper>

5
src/routes/repo/[repo_id]/proposals/+page.ts

@ -0,0 +1,5 @@
export const load = ({ params }: { params: { repo_id: string } }) => {
return {
repo_id: decodeURIComponent(params.repo_id),
}
}
Loading…
Cancel
Save