mirror of
https://seed.radicle.dev/rad:z4V1sjrXqjvFdnCUbxPFqd5p4DtH5.git
synced 2026-11-15 11:20:36 +08:00
Improve project error handling
Fail gracefully if we can't load a peer. Signed-off-by: Alexis Sellier <self@cloudhead.io>
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
<script lang="ts">
|
||||
export let icon: string;
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.placeholder {
|
||||
text-align: center;
|
||||
border-radius: 0.25rem;
|
||||
padding-bottom: 2rem;
|
||||
color: var(--color-foreground-faded) !important;
|
||||
background-color: var(--color-foreground-background);
|
||||
}
|
||||
.placeholder header {
|
||||
padding: 1rem 0;
|
||||
font-weight: bold;
|
||||
}
|
||||
.placeholder .icon {
|
||||
font-size: 1.5rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="error error-message placeholder">
|
||||
<header>
|
||||
<div class="icon">{icon}</div>
|
||||
<slot name="title"></slot>
|
||||
</header>
|
||||
<slot name="body"></slot>
|
||||
</div>
|
||||
@@ -2,6 +2,7 @@
|
||||
import type { Readable } from 'svelte/store';
|
||||
import * as proj from '@app/project';
|
||||
import Loading from '@app/Loading.svelte';
|
||||
import Placeholder from '@app/Placeholder.svelte';
|
||||
import * as utils from '@app/utils';
|
||||
|
||||
import Tree from './Tree.svelte';
|
||||
@@ -100,27 +101,9 @@
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.error-grey {
|
||||
color: var(--color-foreground-faded) !important;
|
||||
background-color: var(--color-foreground-background);
|
||||
}
|
||||
|
||||
.source-tree {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
.file-not-found {
|
||||
text-align: center;
|
||||
border-radius: 0.25rem;
|
||||
padding-bottom: 2rem;
|
||||
}
|
||||
.file-not-found header {
|
||||
padding: 1rem 0;
|
||||
font-weight: bold;
|
||||
}
|
||||
.file-not-found .icon {
|
||||
font-size: 1.5rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
nav {
|
||||
padding: 0 2rem;
|
||||
}
|
||||
@@ -181,19 +164,20 @@
|
||||
<Blob line={browser.line} {blob} />
|
||||
{/if}
|
||||
{:catch}
|
||||
<div class="error error-grey error-message file-not-found">
|
||||
<header>
|
||||
<div class="icon">🍂</div>
|
||||
<Placeholder icon="🍂">
|
||||
<span slot="title">
|
||||
{#if path != "/"}
|
||||
<div><code>{path}</code></div>
|
||||
{/if}
|
||||
</header>
|
||||
{#if path == "/"}
|
||||
The README could not be loaded.
|
||||
{:else}
|
||||
This path could not be loaded.
|
||||
{/if}
|
||||
</div>
|
||||
</span>
|
||||
<span slot="body">
|
||||
{#if path == "/"}
|
||||
The README could not be loaded.
|
||||
{:else}
|
||||
This path could not be loaded.
|
||||
{/if}
|
||||
</span>
|
||||
</Placeholder>
|
||||
{/await}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import type { Config } from '@app/config';
|
||||
import * as proj from '@app/project';
|
||||
import Avatar from '@app/Avatar.svelte';
|
||||
import Placeholder from '@app/Placeholder.svelte';
|
||||
import Clipboard from '@app/Clipboard.svelte';
|
||||
import { formatProfile, formatSeedId, setOpenGraphMetaTag } from '@app/utils';
|
||||
import { browserStore } from '@app/project';
|
||||
@@ -17,7 +18,7 @@
|
||||
export let config: Config;
|
||||
export let project: proj.Project;
|
||||
export let content: proj.ProjectContent;
|
||||
export let revision: string;
|
||||
export let revision: string | null;
|
||||
|
||||
let parentName = project.profile ? formatProfile(project.profile.nameOrAddress, config) : null;
|
||||
let pageTitle = parentName ? `${parentName}/${project.name}` : project.name;
|
||||
@@ -49,9 +50,6 @@
|
||||
</script>
|
||||
|
||||
<style>
|
||||
header {
|
||||
padding: 0 2rem 0 8rem;
|
||||
}
|
||||
.title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -87,8 +85,12 @@
|
||||
margin: 1rem 0 1.5rem 0;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 0 2rem 0 8rem;
|
||||
}
|
||||
|
||||
@media (max-width: 960px) {
|
||||
header {
|
||||
.content {
|
||||
padding-left: 2rem;
|
||||
}
|
||||
|
||||
@@ -112,7 +114,7 @@
|
||||
<title>{pageTitle}</title>
|
||||
</svelte:head>
|
||||
|
||||
<header>
|
||||
<header class="content">
|
||||
<div class="title bold">
|
||||
{#if project.profile}
|
||||
<a class="org-avatar" title={project.profile.nameOrAddress} href="/{project.profile.nameOrAddress}">
|
||||
@@ -134,22 +136,37 @@
|
||||
<div class="description">{project.description}</div>
|
||||
</header>
|
||||
|
||||
{#await project.getRoot(revision) then { tree, commit }}
|
||||
<Header {tree} {commit} {browserStore} {project} peerSelector={! project.profile} />
|
||||
{#if revision}
|
||||
{#await project.getRoot(revision) then { tree, commit }}
|
||||
<Header {tree} {commit} {browserStore} {project} peerSelector={! project.profile} />
|
||||
|
||||
{#if content == proj.ProjectContent.Tree}
|
||||
<Browser {project} {tree} {browserStore} />
|
||||
{:else if content == proj.ProjectContent.History}
|
||||
<History {project} {commit} />
|
||||
{:else if content == proj.ProjectContent.Commit}
|
||||
<Commit {project} {commit} />
|
||||
{/if}
|
||||
{:catch err}
|
||||
<div class="container center-content">
|
||||
<div class="error error-message text-xsmall">
|
||||
<!-- TODO: Differentiate between (1) commit doesn't exist and (2) failed
|
||||
to fetch - this needs a change to the backend. -->
|
||||
API request to <code class="text-xsmall">{err.url}</code> failed
|
||||
{#if content == proj.ProjectContent.Tree}
|
||||
<Browser {project} {tree} {browserStore} />
|
||||
{:else if content == proj.ProjectContent.History}
|
||||
<History {project} {commit} />
|
||||
{:else if content == proj.ProjectContent.Commit}
|
||||
<Commit {project} {commit} />
|
||||
{/if}
|
||||
{:catch err}
|
||||
<div class="container center-content">
|
||||
<div class="error error-message text-xsmall">
|
||||
<!-- TODO: Differentiate between (1) commit doesn't exist and (2) failed
|
||||
to fetch - this needs a change to the backend. -->
|
||||
API request to <code class="text-xsmall">{err.url}</code> failed
|
||||
</div>
|
||||
</div>
|
||||
{/await}
|
||||
{:else}
|
||||
<div class="content">
|
||||
{#if peer}
|
||||
<Placeholder icon="🍂">
|
||||
<span slot="title"><code>{formatSeedId(peer)}</code></span>
|
||||
<span slot="body">Couldn't load remote source tree.</span>
|
||||
</Placeholder>
|
||||
{:else}
|
||||
<Placeholder icon="🍂">
|
||||
<span slot="body">Couldn't load source tree.</span>
|
||||
</Placeholder>
|
||||
{/if}
|
||||
</div>
|
||||
{/await}
|
||||
{/if}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
export let hash: string | null = null;
|
||||
|
||||
const browse: proj.BrowseTo = { content, peer, path: "/" };
|
||||
const head = project.branches[project.defaultBranch];
|
||||
const head = project.branches[project.defaultBranch] || null;
|
||||
|
||||
// If line-number hash changes, we update the browser.
|
||||
$: browse.line = formatLocationHash(hash);
|
||||
|
||||
+5
-1
@@ -349,7 +349,11 @@ export class Project implements ProjectInfo {
|
||||
};
|
||||
|
||||
if (peer) {
|
||||
remote = await Project.getRemote(urn, peer, seed.api);
|
||||
try {
|
||||
remote = await Project.getRemote(urn, peer, seed.api);
|
||||
} catch {
|
||||
remote.heads = {};
|
||||
}
|
||||
}
|
||||
|
||||
return new Project(urn, info, seed, peers, remote.heads, profile, anchors);
|
||||
|
||||
Reference in New Issue
Block a user