Radish alpha
r
Radicle web interface
Radicle
Git (anonymous pull)
Log in to clone via SSH
Implement more simplifications
Alexis Sellier committed 4 years ago
commit c58db9d278982ddf7405c2a8a3f2c65f22431ad0
parent 7e9e40738249470c80c4bd32642a78395ffbe463
10 files changed +109 -144
modified src/base/orgs/Org.ts
@@ -212,29 +212,33 @@ export class Org {
  async getPendingProjects(config: Config): Promise<PendingAnchor[]> {
    if (! config.safe.client) return [];

-
    const orgAddr = ethers.utils.getAddress(this.address);
-
    const response = await config.safe.client.getPendingTransactions(
-
      ethers.utils.getAddress(this.owner)
-
    );
-
    const projects: PendingAnchor[] = [];
-

-
    for (const tx of response.results || []) {
-
      if (tx.data && tx.to === orgAddr) {
-
        const anchor = parseAnchorTx(tx.data, config);
-
        const confirmations = tx.confirmations?.map(t => t.owner) || [];
-

-
        if (anchor) {
-
          projects.push({
-
            id: anchor.id,
-
            anchor: { stateHash: anchor.stateHash },
-
            confirmations,
-
            safeTxHash: tx.safeTxHash,
-
            confirmed: false,
-
          });
+
    try {
+
      const orgAddr = ethers.utils.getAddress(this.address);
+
      const response = await config.safe.client.getPendingTransactions(
+
        ethers.utils.getAddress(this.owner)
+
      );
+
      const projects: PendingAnchor[] = [];
+

+
      for (const tx of response.results || []) {
+
        if (tx.data && tx.to === orgAddr) {
+
          const anchor = parseAnchorTx(tx.data, config);
+
          const confirmations = tx.confirmations?.map(t => t.owner) || [];
+

+
          if (anchor) {
+
            projects.push({
+
              id: anchor.id,
+
              anchor: { stateHash: anchor.stateHash },
+
              confirmations,
+
              safeTxHash: tx.safeTxHash,
+
              confirmed: false,
+
            });
+
          }
        }
      }
+
      return projects;
+
    } catch {
+
      return [];
    }
-
    return projects;
  }

  static async getAnchor(orgAddr: string, urn: string, config: Config): Promise<string | null> {
modified src/base/projects/BranchSelector.svelte
@@ -1,7 +1,7 @@
<script lang="ts">
  import { createEventDispatcher } from "svelte";
  import { ProjectInfo, Branches, getOid } from "@app/project";
-
  import { formatCommit, isOid } from "@app/utils";
+
  import { formatCommit } from "@app/utils";
  import Dropdown from "@app/Dropdown.svelte";

  export let branches: Branches;
modified src/base/projects/Browser.svelte
@@ -25,7 +25,7 @@

  $: browser = $browserStore;
  $: path = browser.path || "/";
-
  $: revision = browser.revision || browser.branches[project.head];
+
  $: revision = browser.revision || source.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 };
@@ -71,7 +71,7 @@
    mobileFileTree = !mobileFileTree;
  };

-
  $: commit = proj.getOid(revision, browser.branches) || project.head;
+
  $: commit = proj.getOid(revision, source.branches) || project.head;
  $: getBlob = loadBlob(path);
  $: loadingPath = state.status == Status.Loading ? state.path : null;
</script>
modified src/base/projects/Header.svelte
@@ -14,7 +14,6 @@
  export let commit: string;
  export let browserStore: Writable<Browser>;
  export let peerSelector: boolean; // If peerSelector should be showed.
-
  export let branches: proj.Branches;

  let { urn, project, peers, seed, anchors } = source;

@@ -22,12 +21,6 @@
  $: revision = browser.revision || commit;
  $: content = browser.content;

-
  $: if (Object.keys(browser.branches).length > 0) {
-
    branches = browser.branches;
-
  } else {
-
    proj.browse({ branches });
-
  }
-

  let dropdownState: { [key: string]: boolean } = { clone: false, seed: false, branch: false, peer: false };
  function toggleDropdown(input: string) {
    Object.keys(dropdownState).map((key: string) => {
@@ -164,7 +157,7 @@
      bind:peersDropdown={dropdownState.peer}
      on:peerChanged={(event) => updatePeer(event.detail)} />
  {/if}
-
  <BranchSelector {branches} {project} {revision} {toggleDropdown}
+
  <BranchSelector branches={source.branches} {project} {revision} {toggleDropdown}
    bind:branchesDropdown={dropdownState.branch}
    on:branchChanged={(event) => updateRevision(event.detail)} />
  <div class="anchor">
modified src/base/projects/Project.svelte
@@ -7,12 +7,16 @@
  import { browserStore } from '@app/project';

  import Header from '@app/base/projects/Header.svelte';
-
  import ProjectContentRoutes from '@app/base/projects/ProjectContentRoutes.svelte';
+

+
  import Browser from "./Browser.svelte";
+
  import Commit from "./Commit.svelte";
+
  import History from "./History.svelte";

  export let peer: string | null = null;
  export let config: Config;
  export let source: proj.Source;
-
  export let peerSelector = false;
+
  export let content: proj.ProjectContent;
+
  export let revision: string;

  const project = source.project;

@@ -43,11 +47,6 @@
    { prop: "og:description", content: project.description },
    { prop: "og:url", content: window.location.href }
  ]);
-

-
  // Necessary for the initial load, but causes double rendering.
-
  // Once the content routing is above this component, this can go
-
  // away.
-
  $: revision = $browserStore.revision;
</script>

<style>
@@ -119,9 +118,16 @@
  <div class="description">{source.project.description}</div>
</header>

-
{#await proj.getRoot(source.project, revision, peer, source.seed.api) then { tree, branches, commit }}
-
  <Header {tree} {branches} {commit} {browserStore} {source} {peerSelector} />
-
  <ProjectContentRoutes {tree} {peer} {branches} {browserStore} {source} />
+
{#await proj.getRoot(source.project, revision, source.branches, source.seed.api) then { tree, commit }}
+
  <Header {tree} {commit} {browserStore} {source} peerSelector={! source.profile} />
+

+
  {#if content == proj.ProjectContent.Tree}
+
    <Browser {source} {tree} {browserStore} />
+
  {:else if content == proj.ProjectContent.History}
+
    <History {source} {commit} />
+
  {:else if content == proj.ProjectContent.Commit}
+
    <Commit {source} {commit} />
+
  {/if}
{:catch err}
  <div class="container center-content">
    <div class="error error-message text-xsmall">
modified src/base/projects/ProjectContentRoutes.svelte
@@ -1,65 +1,38 @@
<script lang="ts">
-
  import type { Writable } from "svelte/store";
  import { Route, Router } from "svelte-routing";
  import type * as proj from "@app/project";
+
  import type { Config } from "@app/config";
  import { ProjectContent } from "@app/project";
-
  import Browser from "./Browser.svelte";
-
  import Commit from "./Commit.svelte";
-
  import History from "./History.svelte";
  import RouteContext from "./RouteContext.svelte";

+
  export let config: Config;
  export let source: proj.Source;
-
  export let tree: proj.Tree;
-
  export let browserStore: Writable<proj.Browser>;
  export let peer: string | null;
-
  export let branches: proj.Branches;
-

-
  const project = source.project;
</script>

<Router>
  <!-- The default action is to render Browser with the default branch head -->
  <Route path="/">
-
    <RouteContext {browserStore} {peer} {branches} {project}>
-
      <Browser {source} {tree} {browserStore} />
-
    </RouteContext>
+
    <RouteContext content={ProjectContent.Tree} {peer} {source} {config} />
  </Route>
  <Route path="/tree">
-
    <RouteContext {browserStore} {peer} {branches} {project}>
-
      <Browser {source} {tree} {browserStore} />
-
    </RouteContext>
+
    <RouteContext content={ProjectContent.Tree} {peer} {source} {config} />
  </Route>
  <Route path="/tree/*" let:params>
-
    <RouteContext route={params["*"]} {browserStore} {peer} {branches} {project}>
-
      <Browser {source} {tree} {browserStore} />
-
    </RouteContext>
+
    <RouteContext route={params["*"]} content={ProjectContent.Tree} {peer} {source} {config} />
  </Route>
+

  <Route path="/history">
-
    <RouteContext {browserStore} content={ProjectContent.History} {peer} {branches} {project} let:commit>
-
      {#if commit}
-
        <History {source} {commit} />
-
      {/if}
-
    </RouteContext>
+
    <RouteContext content={ProjectContent.History} {peer} {source} {config} />
  </Route>
  <Route path="/history/*" let:params>
-
    <RouteContext route={params["*"]} {browserStore} content={ProjectContent.History} {peer} {branches} {project} let:commit>
-
      {#if commit}
-
        <History {source} {commit} />
-
      {/if}
-
    </RouteContext>
+
    <RouteContext route={params["*"]} content={ProjectContent.History} {peer} {source} {config} />
  </Route>
+

  <Route path="/commits/:commit" let:params>
-
    <RouteContext revision={params.commit} {browserStore} {project} content={ProjectContent.Commit} {peer} {branches} let:revision>
-
      {#if revision}
-
        <Commit {source} commit={revision} />
-
      {/if}
-
    </RouteContext>
+
    <RouteContext revision={params.commit} content={ProjectContent.Commit} {peer} {source} {config} />
  </Route>
  <Route path="/commits/*" let:params>
-
    <RouteContext route={params["*"]} {browserStore} {project} content={ProjectContent.Commit} {peer} {branches} let:revision>
-
      {#if revision}
-
        <Commit {source} commit={revision} />
-
      {/if}
-
    </RouteContext>
+
    <RouteContext route={params["*"]} content={ProjectContent.Commit} {peer} {source} {config} />
  </Route>
</Router>
modified src/base/projects/RouteContext.svelte
@@ -1,42 +1,40 @@
<script lang="ts">
  import type { Writable } from 'svelte/store';
+
  import type { Config } from "@app/config";
  import * as proj from '@app/project';

-
  export let browserStore: Writable<proj.Browser>;
+
  import Project from './Project.svelte';
+

+
  export let browserStore: Writable<proj.Browser> = proj.browserStore;
  export let route: string | null = null;
  export let revision: string | null = null;
  export let peer: string | null;
  export let content: proj.ProjectContent = proj.ProjectContent.Tree;
-
  export let branches: proj.Branches;
-
  export let project: proj.ProjectInfo;
+
  export let source: proj.Source;
+
  export let config: Config;

-
  const browse: any = { content, peer, branches, path: "/" };
+
  const browse: any = { content, peer, path: "/" };
+
  const head = source.branches[source.project.defaultBranch];

  $: if (route) {
-
    const result = proj.splitPrefixFromPath(route, $browserStore.branches);
-

-
    console.log("RouteParser", route, result);
-

-
    if (result) {
-
      const [revision, path] = result;
+
    const { path, revision } = proj.parseRoute(route, source.branches);

-
      browse.revision = revision;
-
      browse.path = path;
-
    }
+
    if (path) browse.path = path;
+
    if (revision) browse.revision = revision;
  } else if (revision) {
    browse.revision = revision;
  } else {
-
    browse.revision = branches[project.defaultBranch];
+
    browse.revision = head;
  }

  $: proj.browse(browse);
  $: browser = $browserStore;
-
  $: commit = browser.revision && proj.getOid(browser.revision, browser.branches);
</script>

-
<slot
-
  revision={browser.revision}
+
<Project
  peer={browser.peer}
-
  path={browser.path || "/"}
-
  {commit}
-
></slot>
+
  revision={browser.revision || head}
+
  content={browser.content}
+
  {source}
+
  {config}
+
/>
modified src/base/projects/Routes.svelte
@@ -5,7 +5,6 @@
  import Redirect from "@app/Redirect.svelte";

  export let config: Config;
-

</script>

<!-- With an Seed context -->
modified src/base/projects/View.svelte
@@ -7,7 +7,7 @@
  import { Seed } from '@app/base/seeds/Seed';
  import NotFound from '@app/NotFound.svelte';

-
  import Project from './Project.svelte';
+
  import ProjectContentRoutes from './ProjectContentRoutes.svelte';

  export let id: string; // Project name or URN.
  export let seedHost: string | null = null;
@@ -15,14 +15,6 @@
  export let peer: string | null = null;
  export let config: Config;

-
  // Show peer selector only if we're browsing via a seed.
-
  const peerSelector = Boolean(seedHost);
-

-
  // Nb. Once we move the content routing above this component, this should
-
  // no longer be necessary, but right now, we have the project header that
-
  // is rendered before the routes are parsed, so we have to set this here.
-
  proj.browse({ peer });
-

  const getProject = async (): 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;
@@ -34,18 +26,25 @@
      throw new Error("Couldn't load project: invalid seed");
    }

-
    const info = await proj.getInfo(id, seed.api);
-
    const urn = isRadicleId(id) ? id : info.urn;
+
    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 (! info.urn) info.urn = urn;
+
    if (! project.urn) project.urn = urn;

-
    const peers: proj.PeerId[] = info.delegates
+
    const peers: proj.PeerId[] = project.delegates
      ? await proj.getRemotes(urn, seed.api)
      : [];

-
    return { urn, seed, project: info, peers, profile, anchors };
+
    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>

@@ -77,7 +76,7 @@
      <Loading center />
    </header>
  {:then source}
-
    <Project {source} {peer} {config} {peerSelector} />
+
    <ProjectContentRoutes {source} {peer} {config} />
  {:catch}
    <NotFound title={id} subtitle="This project was not found." />
  {/await}
modified src/project.ts
@@ -33,6 +33,7 @@ export interface Source {
  urn: string;
  project: ProjectInfo;
  peers: PeerId[];
+
  branches: Branches;
  anchors: string[];
  seed: Seed;
  profile?: Profile | null;
@@ -97,7 +98,6 @@ export interface Remote {

export interface Browser {
  content: ProjectContent;
-
  branches: Branches;
  revision: string | null;
  peer: string | null;
  path: string | null;
@@ -112,21 +112,16 @@ export const browserStore = writable({
} as Browser);

export interface BrowseTo {
-
    content?: ProjectContent;
-
    revision?: string | null;
-
    path?: string | null;
-
    peer?: string | null;
-
    branches?: Branches;
+
  content?: ProjectContent;
+
  revision?: string | null;
+
  path?: string | null;
+
  peer?: string | null;
}

-
export interface PathOptions {
+
export interface PathOptions extends BrowseTo {
  urn: string;
-
  content?: ProjectContent;
  profile?: string | null;
  seed?: string | null;
-
  peer?: string | null;
-
  revision?: string | null;
-
  path?: string | null;
}

export function browse(browse: BrowseTo): void {
@@ -191,28 +186,20 @@ export async function getRemotes(urn: string, host: api.Host): Promise<PeerId[]>
export async function getRoot(
  project: ProjectInfo,
  revision: string | null,
-
  peer: string | null,
+
  heads: Branches,
  host: api.Host
-
): Promise<{ tree: Tree; branches: Branches; commit: string }> {
+
): Promise<{ tree: Tree; commit: string }> {
  const urn = project.urn;

-
  let remote: Remote = {
-
    heads: { [project.defaultBranch]: project.head }
-
  };
-

-
  if (peer) {
-
    remote = await getRemote(urn, peer, host);
-
  }
-

-
  const head = remote.heads[project.defaultBranch];
-
  const commit = revision ? getOid(revision, remote.heads) : head;
+
  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, branches: remote.heads, commit };
+
  return { tree, commit };
}

export async function getTree(
@@ -298,16 +285,22 @@ export function getOid(revision: string, branches?: Branches): string | null {
  return null;
}

-
// Splits the path consisting of a revision (eg. branch or commit) and file path into a tuple [revision, file-path]
-
export function splitPrefixFromPath(input: string, branches: Branches): [string, string] | null {
+
// Parses the path consisting of a revision (eg. branch or commit) and file path into a tuple [revision, file-path]
+
export function parseRoute(input: string, branches: Branches): { path?: string; revision?: string } {
  const branch = Object.entries(branches).find(([branchName,]) => input.startsWith(branchName));
  const commitPath = [input.slice(0, 40), input.slice(41)];
+
  const parsed: { path?: string; revision?: string } = {};

  if (branch) {
    const [rev, path] = [input.slice(0, branch[0].length), input.slice(branch[0].length + 1)];
-
    return [rev, path ? path : "/"];
+

+
    parsed.revision = rev;
+
    parsed.path = path ? path : "/";
  } else if (isOid(commitPath[0])) {
-
    return [commitPath[0], commitPath[1] ? commitPath[1] : "/"];
+
    parsed.revision = commitPath[0];
+
    parsed.path = commitPath[1] ? commitPath[1] : "/";
+
  } else {
+
    parsed.path = input;
  }
-
  return null;
+
  return parsed;
}