Radish alpha
r
Radicle web interface
Radicle
Git (anonymous pull)
Log in to clone via SSH
Show project with anchor when no commit hash passed
Sebastian Martinez committed 4 years ago
commit 34673adf4d5d175a7800ebd0f0e7f92534a0597a
parent 85f8c130cd16375306cc418d338e23976a520e9b
4 files changed +69 -79
added src/anchors.ts
@@ -0,0 +1,28 @@
+
import { ethers } from "ethers";
+
import type { Config } from "./config";
+
import { decodeRadicleId, formatProjectHash, querySubgraph } from "./utils";
+

+
const GetAllAnchors = `
+
  query GetAllAnchors($project: Bytes!, $org: ID!) {
+
    anchors(orderBy: timestamp, orderDirection: desc, where: { objectId: $project, org: $org }) {
+
      multihash
+
      timestamp
+
    }
+
  }
+
`;
+

+
interface AnchorObject {
+
  timestamp: number;
+
  multihash: string;
+
}
+

+
export async function getAllAnchors(config: Config, urn: string, anchors?: string | null): Promise<string[]> {
+
  if (! anchors) {
+
    return [];
+
  }
+
  const unpadded = decodeRadicleId(urn);
+
  const id = ethers.utils.hexZeroPad(unpadded, 32);
+
  const allAnchors = await querySubgraph(config.orgs.subgraph, GetAllAnchors, { project: id, org: anchors });
+
  return allAnchors.anchors
+
    .map((anchor: AnchorObject) => formatProjectHash(ethers.utils.arrayify(anchor.multihash)));
+
}
modified src/base/projects/Header.svelte
@@ -2,8 +2,6 @@
  import { navigate } from 'svelte-routing';
  import type { Config } from '@app/config';
  import * as utils from '@app/utils';
-
  import Loading from '@app/Loading.svelte';
-
  import { ethers } from "ethers";
  import { ProjectContent, getOid } from '@app/project';
  import type { Info, Tree } from "@app/project";
  import BranchSelector from './BranchSelector.svelte';
@@ -13,7 +11,7 @@
  const dispatch = createEventDispatcher();

  export let config: Config;
-
  export let anchors: string | null = null;
+
  export let anchors: string[];
  export let urn: string;
  export let path: string;
  export let project: Info;
@@ -49,32 +47,6 @@
    dispatch("routeParamsChange", { content, revision: newRevision, peer, path });
  };

-
  const GetAllAnchors = `
-
    query GetAllAnchors($project: Bytes!, $org: ID!) {
-
      anchors(orderBy: timestamp, orderDirection: desc, where: { objectId: $project, org: $org }) {
-
        multihash
-
        timestamp
-
      }
-
    }
-
  `;
-

-
  interface AnchorObject {
-
    timestamp: number;
-
    multihash: string;
-
  }
-

-
  async function getAllAnchors(anchors: string | null, urn: string): Promise<string[] | null> {
-
    if (! anchors) {
-
      return null;
-
    }
-
    const unpadded = utils.decodeRadicleId(urn);
-
    const id = ethers.utils.hexZeroPad(unpadded, 32);
-
    const allAnchors = await utils.querySubgraph(config.orgs.subgraph, GetAllAnchors, { project: id, org: anchors });
-
    return allAnchors.anchors
-
      .map((anchor: AnchorObject) => utils.formatProjectHash(ethers.utils.arrayify(anchor.multihash)));
-
  }
-

-
  $: getAnchor = anchors ? getAllAnchors(anchors, urn) : null;
  $: commit = getOid(project.head, revision, branches);
</script>

@@ -192,10 +164,6 @@
    background: var(--color-foreground-90);
  }

-
  .error {
-
    color: var(--color-negative);
-
    cursor: not-allowed;
-
  }
  @media (max-width: 960px) {
    header {
      padding-left: 2rem;
@@ -221,46 +189,36 @@
  <BranchSelector {branches} {project} {revision} {toggleDropdown}
    bind:branchesDropdown={dropdownState.branch}
    on:revisionChanged={(event) => updateRevision(event.detail)} />
-
  {#if anchors}
-
    <div class="anchor">
-
      {#await getAnchor}
-
        <Loading small margins />
-
      {:then anchor}
-
        {#if anchor}
-
          <!-- commit is head and latest anchor  -->
-
          {#if commit == anchor[0] && commit === project.head}
-
            <span class="anchor-widget anchor-latest">
-
              <span class="anchor-label" title="{anchors}">latest 🔐</span>
-
            </span>
-
          <!-- commit is not head but latest anchor  -->
-
          {:else if commit == anchor[0] && commit !== project.head}
-
            <span class="anchor-widget" on:click={() => updateRevision(project.head)}>
-
              <span class="anchor-label" title="{anchors}">latest 🔐</span>
-
            </span>
-
          <!-- commit is not head a stale anchor  -->
-
          {:else if anchor?.includes(commit)}
-
            <span class="anchor-widget" on:click={() => updateRevision(anchor[0])}>
-
              <span class="anchor-label" title="{anchors}">stale 🔒</span>
-
            </span>
-
          <!-- commit is not anchored, could be head or any other commit  -->
-
          {:else}
-
            <span class="anchor-widget not-anchored" on:click={() => updateRevision(anchor[0])}>
-
              <span class="anchor-label">not anchored 🔓</span>
-
            </span>
-
          {/if}
-
        {:else}
-
          <!-- commit is not head and neither an anchor, and there are no anchors available  -->
-
          <span class="anchor-widget not-anchored not-allowed">
-
            <span class="anchor-label">not anchored 🔓</span>
-
          </span>
-
        {/if}
-
      {:catch}
-
        <span class="anchor-widget error" title="Not able to fetch anchor from subgraph">
-
          <span class="anchor-label">❌</span>
+
  <div class="anchor">
+
    {#if anchors}
+
      <!-- commit is head and latest anchor  -->
+
      {#if commit == anchors[0] && commit === project.head}
+
        <span class="anchor-widget anchor-latest">
+
          <span class="anchor-label" title="{anchors[0]}">latest 🔐</span>
        </span>
-
      {/await}
-
    </div>
-
  {/if}
+
      <!-- commit is not head but latest anchor  -->
+
      {:else if commit == anchors[0] && commit !== project.head}
+
        <span class="anchor-widget" on:click={() => updateRevision(project.head)}>
+
          <span class="anchor-label" title="{anchors[0]}">latest 🔐</span>
+
        </span>
+
      <!-- commit is not head a stale anchor  -->
+
      {:else if anchors.includes(commit)}
+
        <span class="anchor-widget" on:click={() => updateRevision(anchors[0])}>
+
          <span class="anchor-label" title="{commit}">stale 🔒</span>
+
        </span>
+
      <!-- commit is not anchored, could be head or any other commit  -->
+
      {:else}
+
        <span class="anchor-widget not-anchored" on:click={() => updateRevision(anchors[0])}>
+
          <span class="anchor-label">not anchored 🔓</span>
+
        </span>
+
      {/if}
+
    {:else}
+
      <!-- commit is not head and neither an anchor, and there are no anchors available  -->
+
      <span class="anchor-widget not-anchored not-allowed">
+
        <span class="anchor-label">not anchored 🔓</span>
+
      </span>
+
    {/if}
+
  </div>
  {#if config.seed.git.host}
    <span>
      <div class="clone" on:click={() => toggleDropdown("clone")}>
modified src/base/projects/ProjectContentRoutes.svelte
@@ -15,22 +15,23 @@
  export let peer: Peer;
  export let branches: [string, string][];
  export let content: ProjectContent;
+
  export let anchors: string[];
  export let revision: string;
  export let path: string;
+

+
  let locator = anchors[0] || project.head;
</script>

<Router>
  <!-- The default action is to render Browser with the default branch head -->
  <Route path="/">
-
    <Browser {urn} {org} {user} {seed} {config} {tree} {project} {branches} {peer}
-
      locator={project.head}
+
    <Browser {urn} {org} {user} {seed} {config} {tree} {project} {branches} {peer} {locator}
      bind:content={content}
      bind:path={path}
      bind:revision={revision} />
  </Route>
  <Route path="/tree">
-
    <Browser {urn} {org} {user} {seed} {config} {tree} {project} {branches} {peer}
-
      locator={project.head}
+
    <Browser {urn} {org} {user} {seed} {config} {tree} {project} {branches} {peer} {locator}
      bind:content={content}
      bind:path={path}
      bind:revision={revision} />
@@ -43,7 +44,7 @@
      bind:revision={revision} />
  </Route>
  <Route path="/history">
-
    <History {urn} locator={project.head} {config} {project} {branches}
+
    <History {urn} {config} {project} {branches} {locator}
      bind:content={content}
      bind:revision={revision} />
  </Route>
modified src/base/projects/View.svelte
@@ -10,6 +10,7 @@
  import { formatOrg, formatSeedId } from '@app/utils';
  import { getOid } from '@app/project';
  import { Seed } from '@app/base/seeds/Seed';
+
  import { getAllAnchors } from '@app/anchors';

  import Header from '@app/base/projects/Header.svelte';
  import ProjectContentRoutes from '@app/base/projects/ProjectContentRoutes.svelte';
@@ -43,6 +44,7 @@
    const cfg = seed ? config.withSeed(seed) : config;
    const info = await proj.getInfo(urn, cfg);
    projectInfo = info;
+
    const anchors = await getAllAnchors(config, urn, profile?.anchorsAccount ?? org);
    let branches = Array([info.meta.defaultBranch, info.head]) as [string, string][];
    let peers: proj.Peer[] = [];

@@ -55,7 +57,7 @@
      }
      peers = await proj.getPeers(urn, cfg);
    }
-
    return { project: info, branches, peers, config: cfg, profile };
+
    return { project: info, branches, peers, anchors, config: cfg, profile };
  });

  const parentUrl = (profile: Profile) => {
@@ -178,7 +180,7 @@
    </header>
    {#await proj.getTree(urn, getOid(result.project.head, revision, result.branches), "/", config) then tree}
      <Header {urn} {tree} {revision} {content} {path} {peer}
-
        anchors={result.profile?.anchorsAccount ?? org}
+
        anchors={result.anchors}
        peerSelector={!!seed}
        config={result.config}
        project={result.project}
@@ -187,6 +189,7 @@
        on:routeParamsChange={updateRouteParams} />
      <ProjectContentRoutes {urn} {org} {user} {seed} {tree} {peer}
        project={result.project}
+
        anchors={result.anchors}
        branches={result.branches}
        config={result.config}
        bind:content={content}