mirror of
https://seed.radicle.dev/rad:z4V1sjrXqjvFdnCUbxPFqd5p4DtH5.git
synced 2026-10-18 19:30:27 +08:00
Refactor projects
Signed-off-by: Sebastian Martinez <sebastinez@me.com>
This commit is contained in:
@@ -5,6 +5,7 @@ import { styles } from "@test/support/index";
|
||||
const defaultProps = {
|
||||
project: {
|
||||
head: "e678629cd37c770c640a2cd997fc76303c815772",
|
||||
urn: "rad:git:hnrkqdpm9ub19oc8dccx44echy76hzfsezyio",
|
||||
name: "nakamoto",
|
||||
description: "Privacy-preserving Bitcoin light-client implementation in Rust",
|
||||
defaultBranch: "master",
|
||||
|
||||
@@ -17,15 +17,13 @@
|
||||
{ status: Status.Loading; path: string }
|
||||
| { status: Status.Loaded; path: string; blob: proj.Blob };
|
||||
|
||||
export let source: proj.Source;
|
||||
export let project: proj.Project;
|
||||
export let tree: proj.Tree;
|
||||
export let browserStore: Readable<proj.Browser>;
|
||||
|
||||
const { urn, project } = source;
|
||||
|
||||
$: browser = $browserStore;
|
||||
$: path = browser.path || "/";
|
||||
$: revision = browser.revision || source.branches[project.head];
|
||||
$: revision = browser.revision || project.branches[project.head];
|
||||
|
||||
// When the component is loaded the first time, the blob is yet to be loaded.
|
||||
let state: State = { status: Status.Loading, path };
|
||||
@@ -39,8 +37,8 @@
|
||||
|
||||
const isMarkdownPath = utils.isMarkdownPath(path);
|
||||
const promise = path === "/"
|
||||
? proj.getReadme(urn, commit, source.seed.api)
|
||||
: proj.getBlob(urn, commit, path, { highlight: !isMarkdownPath }, source.seed.api);
|
||||
? project.getReadme(commit)
|
||||
: project.getBlob(commit, path, { highlight: !isMarkdownPath });
|
||||
|
||||
state = { status: Status.Loading, path };
|
||||
state = { status: Status.Loaded, path, blob: await promise };
|
||||
@@ -59,19 +57,19 @@
|
||||
mobileFileTree = false;
|
||||
|
||||
if (path) {
|
||||
proj.navigateTo({ path: newPath, revision }, source);
|
||||
project.navigateTo({ path: newPath, revision });
|
||||
}
|
||||
};
|
||||
|
||||
const fetchTree = async (path: string) => {
|
||||
return proj.getTree(urn, commit, path, source.seed.api);
|
||||
return project.getTree(commit, path);
|
||||
};
|
||||
|
||||
const toggleMobileFileTree = () => {
|
||||
mobileFileTree = !mobileFileTree;
|
||||
};
|
||||
|
||||
$: commit = proj.getOid(revision, source.branches) || project.head;
|
||||
$: commit = proj.getOid(revision, project.branches) || project.head;
|
||||
$: getBlob = loadBlob(path);
|
||||
$: loadingPath = state.status == Status.Loading ? state.path : null;
|
||||
</script>
|
||||
|
||||
@@ -4,16 +4,15 @@
|
||||
import { formatCommitTime } from "@app/commit";
|
||||
import { formatCommit } from "@app/utils";
|
||||
|
||||
export let source: proj.Source;
|
||||
export let project: proj.Project;
|
||||
export let commit: string;
|
||||
|
||||
const { seed, urn } = source;
|
||||
const onBrowse = (event: { detail: string }) => {
|
||||
proj.navigateTo({
|
||||
project.navigateTo({
|
||||
content: proj.ProjectContent.Tree,
|
||||
revision: commit,
|
||||
path: event.detail
|
||||
}, source);
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -61,7 +60,7 @@
|
||||
}
|
||||
</style>
|
||||
|
||||
{#await proj.getCommit(urn, commit, seed.api) then commit}
|
||||
{#await project.getCommit(commit) then commit}
|
||||
<div class="commit">
|
||||
<header>
|
||||
<div class="summary">
|
||||
|
||||
@@ -2,20 +2,19 @@
|
||||
import type { Writable } from 'svelte/store';
|
||||
import { navigate } from 'svelte-routing';
|
||||
import * as utils from '@app/utils';
|
||||
import * as proj from '@app/project';
|
||||
import { Browser, ProjectContent, Source } from '@app/project';
|
||||
import { Browser, ProjectContent, Project } from '@app/project';
|
||||
import AnchorBadge from '@app/base/profiles/AnchorBadge.svelte';
|
||||
import type { Tree } from "@app/project";
|
||||
import BranchSelector from './BranchSelector.svelte';
|
||||
import PeerSelector from './PeerSelector.svelte';
|
||||
|
||||
export let source: Source;
|
||||
export let project: Project;
|
||||
export let tree: Tree;
|
||||
export let commit: string;
|
||||
export let browserStore: Writable<Browser>;
|
||||
export let peerSelector: boolean; // If peerSelector should be showed.
|
||||
|
||||
let { urn, project, peers, seed, anchors } = source;
|
||||
let { urn, peers, branches, seed, anchors } = project;
|
||||
|
||||
$: browser = $browserStore;
|
||||
$: revision = browser.revision || commit;
|
||||
@@ -31,19 +30,19 @@
|
||||
|
||||
// Switches between the browser and commit view.
|
||||
const toggleContent = (input: ProjectContent) => {
|
||||
proj.navigateTo({
|
||||
project.navigateTo({
|
||||
content: content === input ? ProjectContent.Tree : input
|
||||
}, source);
|
||||
});
|
||||
};
|
||||
|
||||
const updatePeer = (peer: string) => {
|
||||
dropdownState.peer = false;
|
||||
proj.navigateTo({ peer, revision: null }, source);
|
||||
project.navigateTo({ peer, revision: null });
|
||||
};
|
||||
|
||||
const updateRevision = (revision: string) => {
|
||||
dropdownState.branch = false;
|
||||
proj.navigateTo({ revision }, source);
|
||||
project.navigateTo({ revision });
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -157,7 +156,7 @@
|
||||
bind:peersDropdown={dropdownState.peer}
|
||||
on:peerChanged={(event) => updatePeer(event.detail)} />
|
||||
{/if}
|
||||
<BranchSelector branches={source.branches} {project} {revision} {toggleDropdown}
|
||||
<BranchSelector {branches} {project} {revision} {toggleDropdown}
|
||||
bind:branchesDropdown={dropdownState.branch}
|
||||
on:branchChanged={(event) => updateRevision(event.detail)} />
|
||||
<div class="anchor">
|
||||
|
||||
@@ -1,20 +1,18 @@
|
||||
<script lang="ts">
|
||||
import CommitTeaser from "./Commit/CommitTeaser.svelte";
|
||||
import { getCommits, Source, ProjectContent } from "@app/project";
|
||||
import * as proj from "@app/project";
|
||||
import type { Project } from "@app/project";
|
||||
import { ProjectContent } from "@app/project";
|
||||
import Loading from "@app/Loading.svelte";
|
||||
import { groupCommitHistory, GroupedCommitsHistory } from "@app/commit";
|
||||
|
||||
export let source: Source;
|
||||
export let project: Project;
|
||||
export let commit: string;
|
||||
|
||||
let { urn, seed } = source;
|
||||
|
||||
const navigateHistory = (revision: string, content?: ProjectContent) => {
|
||||
proj.navigateTo({ content, revision, path: null }, source);
|
||||
project.navigateTo({ content, revision, path: null });
|
||||
};
|
||||
const fetchCommits = async (parentCommit: string): Promise<GroupedCommitsHistory> => {
|
||||
const commitsQuery = await getCommits(urn, parentCommit, seed.api);
|
||||
const commitsQuery = await project.getCommits(parentCommit);
|
||||
return groupCommitHistory(commitsQuery);
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -14,22 +14,20 @@
|
||||
|
||||
export let peer: string | null = null;
|
||||
export let config: Config;
|
||||
export let source: proj.Source;
|
||||
export let project: proj.Project;
|
||||
export let content: proj.ProjectContent;
|
||||
export let revision: string;
|
||||
|
||||
const project = source.project;
|
||||
|
||||
let parentName = source.profile ? formatProfile(source.profile.nameOrAddress, config) : null;
|
||||
let parentName = project.profile ? formatProfile(project.profile.nameOrAddress, config) : null;
|
||||
let pageTitle = parentName ? `${parentName}/${project.name}` : project.name;
|
||||
|
||||
function rootPath(source: proj.Source): string {
|
||||
return proj.pathTo({
|
||||
function rootPath(): string {
|
||||
return project.pathTo({
|
||||
content: proj.ProjectContent.Tree,
|
||||
peer: null,
|
||||
path: "/",
|
||||
revision: null,
|
||||
}, source);
|
||||
});
|
||||
}
|
||||
|
||||
const baseName = parentName
|
||||
@@ -107,30 +105,30 @@
|
||||
|
||||
<header>
|
||||
<div class="title bold">
|
||||
{#if source.profile}
|
||||
<a class="org-avatar" title={source.profile.nameOrAddress} href="/{source.profile.nameOrAddress}">
|
||||
<Avatar source={source.profile.avatar || source.profile.address} address={source.profile.address}/>
|
||||
{#if project.profile}
|
||||
<a class="org-avatar" title={project.profile.nameOrAddress} href="/{project.profile.nameOrAddress}">
|
||||
<Avatar source={project.profile.avatar || project.profile.address} address={project.profile.address}/>
|
||||
</a>
|
||||
<span class="divider">/</span>
|
||||
{/if}
|
||||
<Link to={rootPath(source)}>{source.project.name}</Link>
|
||||
<Link to={rootPath()}>{project.name}</Link>
|
||||
{#if peer}
|
||||
<span class="divider" title={peer}>/ {formatSeedId(peer)}</span>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="urn">{source.urn}</div>
|
||||
<div class="description">{source.project.description}</div>
|
||||
<div class="urn">{project.urn}</div>
|
||||
<div class="description">{project.description}</div>
|
||||
</header>
|
||||
|
||||
{#await proj.getRoot(source.project, revision, source.branches, source.seed.api) then { tree, commit }}
|
||||
<Header {tree} {commit} {browserStore} {source} peerSelector={! source.profile} />
|
||||
{#await project.getRoot(revision) then { tree, commit }}
|
||||
<Header {tree} {commit} {browserStore} {project} peerSelector={! project.profile} />
|
||||
|
||||
{#if content == proj.ProjectContent.Tree}
|
||||
<Browser {source} {tree} {browserStore} />
|
||||
<Browser {project} {tree} {browserStore} />
|
||||
{:else if content == proj.ProjectContent.History}
|
||||
<History {source} {commit} />
|
||||
<History {project} {commit} />
|
||||
{:else if content == proj.ProjectContent.Commit}
|
||||
<Commit {source} {commit} />
|
||||
<Commit {project} {commit} />
|
||||
{/if}
|
||||
{:catch err}
|
||||
<div class="container center-content">
|
||||
|
||||
@@ -10,15 +10,15 @@
|
||||
export let revision: string | null = null;
|
||||
export let peer: string | null;
|
||||
export let content: proj.ProjectContent = proj.ProjectContent.Tree;
|
||||
export let source: proj.Source;
|
||||
export let project: proj.Project;
|
||||
export let config: Config;
|
||||
|
||||
const browse: proj.BrowseTo = { content, peer, path: "/" };
|
||||
const head = source.branches[source.project.defaultBranch];
|
||||
const head = project.branches[project.defaultBranch];
|
||||
|
||||
// route is passed when the URL has more params after e.g. /tree or /history
|
||||
$: if (route) {
|
||||
const { path, revision } = proj.parseRoute(route, source.branches);
|
||||
const { path, revision } = proj.parseRoute(route, project.branches);
|
||||
|
||||
if (path) browse.path = path;
|
||||
if (revision) browse.revision = revision;
|
||||
@@ -36,6 +36,6 @@
|
||||
peer={browser.peer}
|
||||
revision={browser.revision || head}
|
||||
content={browser.content}
|
||||
{source}
|
||||
{project}
|
||||
{config}
|
||||
/>
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
<script lang="ts">
|
||||
import type { Config } from '@app/config';
|
||||
import { Route, Router } from "svelte-routing";
|
||||
import * as proj from '@app/project';
|
||||
import { Project, ProjectContent } from '@app/project';
|
||||
import Loading from '@app/Loading.svelte';
|
||||
import { Profile, ProfileType } from '@app/profile';
|
||||
import { isRadicleId } from '@app/utils';
|
||||
import { Seed } from '@app/base/seeds/Seed';
|
||||
import NotFound from '@app/NotFound.svelte';
|
||||
|
||||
import ProjectRoute from "./ProjectRoute.svelte";
|
||||
@@ -15,38 +12,6 @@
|
||||
export let profileName: string | null = null; // Address or name of parent profile.
|
||||
export let peer: string | null = null;
|
||||
export let config: Config;
|
||||
|
||||
const getProject = async (peer: string | null): Promise<proj.Source> => {
|
||||
const profile = profileName ? await Profile.get(profileName, ProfileType.Project, config) : null;
|
||||
const seed = profile ? profile.seed : seedHost ? await Seed.lookup(seedHost, config) : null;
|
||||
|
||||
if (!profile && !seed) {
|
||||
throw new Error("Couldn't load project");
|
||||
}
|
||||
if (! seed?.valid) {
|
||||
throw new Error("Couldn't load project: invalid seed");
|
||||
}
|
||||
|
||||
const project = await proj.getInfo(id, seed.api);
|
||||
const urn = isRadicleId(id) ? id : project.urn;
|
||||
const anchors = profile ? await profile.confirmedProjectAnchors(urn, config) : [];
|
||||
|
||||
// Older versions of http-api don't include the URN.
|
||||
if (! project.urn) project.urn = urn;
|
||||
|
||||
const peers: proj.PeerId[] = project.delegates
|
||||
? await proj.getRemotes(urn, seed.api)
|
||||
: [];
|
||||
|
||||
let remote: proj.Remote = {
|
||||
heads: { [project.defaultBranch]: project.head }
|
||||
};
|
||||
|
||||
if (peer) {
|
||||
remote = await proj.getRemote(urn, peer, seed.api);
|
||||
}
|
||||
return { urn, seed, project, peers, branches: remote.heads, profile, anchors };
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
@@ -72,35 +37,35 @@
|
||||
</style>
|
||||
|
||||
<main>
|
||||
{#await getProject(peer)}
|
||||
{#await Project.get(id, peer, profileName, seedHost, config)}
|
||||
<header>
|
||||
<Loading center />
|
||||
</header>
|
||||
{:then source}
|
||||
{:then project}
|
||||
<Router>
|
||||
<!-- The default action is to render Browser with the default branch head -->
|
||||
<Route path="/">
|
||||
<ProjectRoute content={proj.ProjectContent.Tree} {peer} {source} {config} />
|
||||
<ProjectRoute content={ProjectContent.Tree} {peer} {project} {config} />
|
||||
</Route>
|
||||
<Route path="/tree">
|
||||
<ProjectRoute content={proj.ProjectContent.Tree} {peer} {source} {config} />
|
||||
<ProjectRoute content={ProjectContent.Tree} {peer} {project} {config} />
|
||||
</Route>
|
||||
<Route path="/tree/*" let:params>
|
||||
<ProjectRoute route={params["*"]} content={proj.ProjectContent.Tree} {peer} {source} {config} />
|
||||
<ProjectRoute route={params["*"]} content={ProjectContent.Tree} {peer} {project} {config} />
|
||||
</Route>
|
||||
|
||||
<Route path="/history">
|
||||
<ProjectRoute content={proj.ProjectContent.History} {peer} {source} {config} />
|
||||
<ProjectRoute content={ProjectContent.History} {peer} {project} {config} />
|
||||
</Route>
|
||||
<Route path="/history/*" let:params>
|
||||
<ProjectRoute route={params["*"]} content={proj.ProjectContent.History} {peer} {source} {config} />
|
||||
<ProjectRoute route={params["*"]} content={ProjectContent.History} {peer} {project} {config} />
|
||||
</Route>
|
||||
|
||||
<Route path="/commits/:commit" let:params>
|
||||
<ProjectRoute revision={params.commit} content={proj.ProjectContent.Commit} {peer} {source} {config} />
|
||||
<ProjectRoute revision={params.commit} content={ProjectContent.Commit} {peer} {project} {config} />
|
||||
</Route>
|
||||
<Route path="/commits/*" let:params>
|
||||
<ProjectRoute route={params["*"]} content={proj.ProjectContent.Commit} {peer} {source} {config} />
|
||||
<ProjectRoute route={params["*"]} content={ProjectContent.Commit} {peer} {project} {config} />
|
||||
</Route>
|
||||
</Router>
|
||||
{:catch}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as api from '@app/api';
|
||||
import type { Config } from '@app/config';
|
||||
import * as proj from '@app/project';
|
||||
import * as proj from "@app/project";
|
||||
import { isDomain } from '@app/utils';
|
||||
import { assert } from '@app/error';
|
||||
|
||||
@@ -65,15 +65,15 @@ export class Seed {
|
||||
}
|
||||
|
||||
async getProject(urn: string): Promise<proj.ProjectInfo> {
|
||||
return proj.getInfo(urn, this.api);
|
||||
return proj.Project.getInfo(urn, this.api);
|
||||
}
|
||||
|
||||
async getProjects(id?: string): Promise<proj.ProjectInfo[]> {
|
||||
const result = id
|
||||
? await proj.getDelegateProjects(id, this.api)
|
||||
: await proj.getProjects(this.api);
|
||||
? await proj.Project.getDelegateProjects(id, this.api)
|
||||
: await proj.Project.getProjects(this.api);
|
||||
|
||||
return result.map((project: any) => ({ ...project, id: project.urn }));
|
||||
return result.map((project: proj.ProjectInfo) => ({ ...project, id: project.urn }));
|
||||
}
|
||||
|
||||
static async getPeer({ host, port }: api.Host): Promise<{ id: string }> {
|
||||
|
||||
+157
-115
@@ -2,9 +2,10 @@ import { navigate } from 'svelte-routing';
|
||||
import { get, writable } from 'svelte/store';
|
||||
import * as api from '@app/api';
|
||||
import type { Commit, CommitHeader, CommitsHistory } from '@app/commit';
|
||||
import { isOid } from '@app/utils';
|
||||
import type { Profile } from '@app/profile';
|
||||
import type { Seed } from '@app/base/seeds/Seed';
|
||||
import { isOid, isRadicleId } from '@app/utils';
|
||||
import { Profile, ProfileType } from '@app/profile';
|
||||
import { Seed } from '@app/base/seeds/Seed';
|
||||
import type { Config } from '@app/config';
|
||||
|
||||
export type Urn = string;
|
||||
export type PeerId = string;
|
||||
@@ -28,17 +29,6 @@ export interface PendingAnchor {
|
||||
};
|
||||
}
|
||||
|
||||
// Params to render correctly source code related views
|
||||
export interface Source {
|
||||
urn: string;
|
||||
project: ProjectInfo;
|
||||
peers: PeerId[];
|
||||
branches: Branches;
|
||||
anchors: string[];
|
||||
seed: Seed;
|
||||
profile?: Profile | null;
|
||||
}
|
||||
|
||||
// Enumerates the space below the Header component in the projects View component
|
||||
export enum ProjectContent {
|
||||
Tree,
|
||||
@@ -129,107 +119,6 @@ export function browse(browse: BrowseTo): void {
|
||||
browserStore.set({ ...browser, ...browse });
|
||||
}
|
||||
|
||||
export function pathTo(browse: BrowseTo, source: Source): string {
|
||||
const browser = get(browserStore);
|
||||
const options: PathOptions = {
|
||||
urn: source.urn,
|
||||
...browser,
|
||||
...browse
|
||||
};
|
||||
|
||||
if (source.profile) {
|
||||
options.profile = source.profile?.nameOrAddress;
|
||||
} else {
|
||||
options.seed = source.seed.host;
|
||||
}
|
||||
|
||||
return path(options);
|
||||
}
|
||||
|
||||
export function navigateTo(browse: BrowseTo, source: Source): void {
|
||||
navigate(pathTo(browse, source));
|
||||
}
|
||||
|
||||
export async function getInfo(nameOrUrn: string, host: api.Host): Promise<ProjectInfo> {
|
||||
const info = await api.get(`projects/${nameOrUrn}`, {}, host);
|
||||
|
||||
return {
|
||||
...info,
|
||||
...info.meta // Nb. This is only needed while we are upgrading to the new http-api.
|
||||
};
|
||||
}
|
||||
|
||||
export async function getCommits(urn: string, commit: string, host: api.Host): Promise<CommitsHistory> {
|
||||
return api.get(`projects/${urn}/commits?from=${commit}`, {}, host);
|
||||
}
|
||||
|
||||
export async function getCommit(urn: string, commit: string, host: api.Host): Promise<Commit> {
|
||||
return api.get(`projects/${urn}/commits/${commit}`, {}, host);
|
||||
}
|
||||
|
||||
export async function getProjects(host: api.Host): Promise<ProjectInfo[]> {
|
||||
return api.get("projects", {}, host);
|
||||
}
|
||||
|
||||
export async function getDelegateProjects(delegate: string, host: api.Host): Promise<ProjectInfo[]> {
|
||||
return api.get(`delegates/${delegate}/projects`, {}, host);
|
||||
}
|
||||
|
||||
export async function getRemote(urn: string, peer: string, host: api.Host): Promise<Remote> {
|
||||
return api.get(`projects/${urn}/remotes/${peer}`, {}, host);
|
||||
}
|
||||
|
||||
export async function getRemotes(urn: string, host: api.Host): Promise<PeerId[]> {
|
||||
return api.get(`projects/${urn}/remotes`, {}, host);
|
||||
}
|
||||
|
||||
export async function getRoot(
|
||||
project: ProjectInfo,
|
||||
revision: string | null,
|
||||
heads: Branches,
|
||||
host: api.Host
|
||||
): Promise<{ tree: Tree; commit: string }> {
|
||||
const urn = project.urn;
|
||||
|
||||
const head = heads[project.defaultBranch];
|
||||
const commit = revision ? getOid(revision, heads) : head;
|
||||
|
||||
if (! commit) {
|
||||
throw new Error(`Revision ${revision} not found`);
|
||||
}
|
||||
const tree = await getTree(urn, commit, "/", host);
|
||||
|
||||
return { tree, commit };
|
||||
}
|
||||
|
||||
export async function getTree(
|
||||
urn: string,
|
||||
commit: string,
|
||||
path: string,
|
||||
host: api.Host
|
||||
): Promise<Tree> {
|
||||
if (path === "/") path = "";
|
||||
return api.get(`projects/${urn}/tree/${commit}/${path}`, {}, host);
|
||||
}
|
||||
|
||||
export async function getBlob(
|
||||
urn: string,
|
||||
commit: string,
|
||||
path: string,
|
||||
options: { highlight: boolean },
|
||||
host: api.Host
|
||||
): Promise<Blob> {
|
||||
return api.get(`projects/${urn}/blob/${commit}/${path}`, options, host);
|
||||
}
|
||||
|
||||
export async function getReadme(
|
||||
urn: string,
|
||||
commit: string,
|
||||
host: api.Host
|
||||
): Promise<Blob> {
|
||||
return api.get(`projects/${urn}/readme/${commit}`, {}, host);
|
||||
}
|
||||
|
||||
export function path(opts: PathOptions): string {
|
||||
const { urn, profile, seed, peer, content, revision, path } = opts;
|
||||
const result = [];
|
||||
@@ -304,3 +193,156 @@ export function parseRoute(input: string, branches: Branches): { path?: string;
|
||||
}
|
||||
return parsed;
|
||||
}
|
||||
|
||||
export class Project implements ProjectInfo {
|
||||
urn: string;
|
||||
head: string;
|
||||
name: string;
|
||||
description: string;
|
||||
defaultBranch: string;
|
||||
maintainers: Urn[];
|
||||
delegates: PeerId[];
|
||||
seed: Seed;
|
||||
peers: string[];
|
||||
branches: Branches;
|
||||
profile: Profile | null;
|
||||
anchors: string[];
|
||||
|
||||
constructor(urn: string, info: ProjectInfo, seed: Seed, peers: string[], branches: Branches, profile: Profile | null, anchors: string[]) {
|
||||
this.urn = urn;
|
||||
this.head = info.head;
|
||||
this.name = info.name;
|
||||
this.description = info.description;
|
||||
this.defaultBranch = info.defaultBranch;
|
||||
this.maintainers = info.maintainers;
|
||||
this.delegates = info.delegates;
|
||||
this.seed = seed;
|
||||
this.peers = peers;
|
||||
this.branches = branches;
|
||||
this.profile = profile;
|
||||
this.anchors = anchors;
|
||||
}
|
||||
|
||||
async getRoot(
|
||||
revision: string | null,
|
||||
): Promise<{ tree: Tree; commit: string }> {
|
||||
const head = this.branches[this.defaultBranch];
|
||||
const commit = revision ? getOid(revision, this.branches) : head;
|
||||
|
||||
if (! commit) {
|
||||
throw new Error(`Revision ${revision} not found`);
|
||||
}
|
||||
const tree = await this.getTree(commit, "/");
|
||||
|
||||
return { tree, commit };
|
||||
}
|
||||
|
||||
static async getInfo(nameOrUrn: string, host: api.Host): Promise<ProjectInfo> {
|
||||
const info = await api.get(`projects/${nameOrUrn}`, {}, host);
|
||||
|
||||
return {
|
||||
...info,
|
||||
...info.meta // Nb. This is only needed while we are upgrading to the new http-api.
|
||||
};
|
||||
}
|
||||
|
||||
static async getProjects(host: api.Host): Promise<ProjectInfo[]> {
|
||||
return api.get("projects", {}, host);
|
||||
}
|
||||
|
||||
static async getDelegateProjects(delegate: string, host: api.Host): Promise<ProjectInfo[]> {
|
||||
return api.get(`delegates/${delegate}/projects`, {}, host);
|
||||
}
|
||||
|
||||
static async getRemote(urn: string, peer: string, host: api.Host): Promise<Remote> {
|
||||
return api.get(`projects/${urn}/remotes/${peer}`, {}, host);
|
||||
}
|
||||
|
||||
static async getRemotes(urn: string, host: api.Host): Promise<PeerId[]> {
|
||||
return api.get(`projects/${urn}/remotes`, {}, host);
|
||||
}
|
||||
|
||||
async getCommits(commit: string): Promise<CommitsHistory> {
|
||||
return api.get(`projects/${this.urn}/commits?from=${commit}`, {}, this.seed.api);
|
||||
}
|
||||
|
||||
async getCommit(commit: string): Promise<Commit> {
|
||||
return api.get(`projects/${this.urn}/commits/${commit}`, {}, this.seed.api);
|
||||
}
|
||||
|
||||
async getTree(
|
||||
commit: string,
|
||||
path: string,
|
||||
): Promise<Tree> {
|
||||
if (path === "/") path = "";
|
||||
return api.get(`projects/${this.urn}/tree/${commit}/${path}`, {}, this.seed.api);
|
||||
}
|
||||
|
||||
async getBlob(
|
||||
commit: string,
|
||||
path: string,
|
||||
options: { highlight: boolean },
|
||||
): Promise<Blob> {
|
||||
return api.get(`projects/${this.urn}/blob/${commit}/${path}`, options, this.seed.api);
|
||||
}
|
||||
|
||||
async getReadme(
|
||||
commit: string,
|
||||
): Promise<Blob> {
|
||||
return api.get(`projects/${this.urn}/readme/${commit}`, {}, this.seed.api);
|
||||
}
|
||||
|
||||
navigateTo(browse: BrowseTo): void {
|
||||
navigate(this.pathTo(browse));
|
||||
}
|
||||
|
||||
pathTo(browse: BrowseTo): string {
|
||||
const browser = get(browserStore);
|
||||
const options: PathOptions = {
|
||||
urn: this.urn,
|
||||
...browser,
|
||||
...browse
|
||||
};
|
||||
|
||||
if (this.profile) {
|
||||
options.profile = this.profile?.nameOrAddress;
|
||||
} else {
|
||||
options.seed = this.seed.host;
|
||||
}
|
||||
|
||||
return path(options);
|
||||
}
|
||||
|
||||
static async get(id: string, peer: string | null, profileName: string | null, seedHost: string | null, config: Config): Promise<Project> {
|
||||
const profile = profileName ? await Profile.get(profileName, ProfileType.Project, config) : null;
|
||||
const seed = profile ? profile.seed : seedHost ? await Seed.lookup(seedHost, config) : null;
|
||||
|
||||
if (!profile && !seed) {
|
||||
throw new Error("Couldn't load project");
|
||||
}
|
||||
if (! seed?.valid) {
|
||||
throw new Error("Couldn't load project: invalid seed");
|
||||
}
|
||||
|
||||
const info = await Project.getInfo(id, seed.api);
|
||||
const urn = isRadicleId(id) ? id : info.urn;
|
||||
const anchors = profile ? await profile.confirmedProjectAnchors(urn, config) : [];
|
||||
|
||||
// Older versions of http-api don't include the URN.
|
||||
if (! info.urn) info.urn = urn;
|
||||
|
||||
const peers: PeerId[] = info.delegates
|
||||
? await Project.getRemotes(urn, seed.api)
|
||||
: [];
|
||||
|
||||
let remote: Remote = {
|
||||
heads: { [info.defaultBranch]: info.head }
|
||||
};
|
||||
|
||||
if (peer) {
|
||||
remote = await Project.getRemote(urn, peer, seed.api);
|
||||
}
|
||||
|
||||
return new Project(urn, info, seed, peers, remote.heads, profile, anchors);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user